From edd2fd5e6334f73ab6abcb3329589b6a4c705d91 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 18:37:33 +0100 Subject: [PATCH 0001/2040] Renamed aarch64 to arm64 --- .github/workflows/build-cmake.yml | 2 +- TargetArch.cmake | 2 +- code/qcommon/q_platform.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index ef9e80e3..0c99c3a1 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -22,7 +22,7 @@ jobs: architecture: [ {name: 'amd64', triple: 'x86_64-linux-gnu'}, {name: 'i686', triple: 'i686-linux-gnu'}, - {name: 'aarch64', triple: 'aarch64-linux-gnu'}, + {name: 'arm64', triple: 'aarch64-linux-gnu'}, {name: 'armhf', triple: 'arm-linux-gnueabihf'} ] diff --git a/TargetArch.cmake b/TargetArch.cmake index fd4ba8d9..933c1646 100644 --- a/TargetArch.cmake +++ b/TargetArch.cmake @@ -22,7 +22,7 @@ set(archdetect_c_code " #elif defined __arm__ || defined (_M_ARM) # error cmake_ARCH arm #elif defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64) -# error cmake_ARCH aarch64 +# error cmake_ARCH arm64 #elif defined __cris__ # error cmake_ARCH cris #elif defined __hppa__ diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 50f18140..fdf0c25f 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -208,7 +208,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #elif defined __arm__ # define ARCH_STRING "arm" #elif defined(__aarch64__) || defined(__ARM64__) -# define ARCH_STRING "aarch64" +# define ARCH_STRING "arm64" #elif defined __cris__ # define ARCH_STRING "cris" #elif defined __hppa__ From ff5b0b760796e5d820e9af004c5f55095adedb2a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 19:43:47 +0100 Subject: [PATCH 0002/2040] Added snd_mem_new.c --- code/client/CMakeLists.txt | 2 + code/client/snd_mem_new.c | 171 +++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 code/client/snd_mem_new.c diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index babaf736..6bdd9d49 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -31,6 +31,8 @@ if (USE_SOUND_NEW) endif() list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.c$") + file(GLOB_RECURSE SOURCES_CLIENT_SND "./snd_*_new.c*") + list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) endif() if (USE_OPENAL) diff --git a/code/client/snd_mem_new.c b/code/client/snd_mem_new.c new file mode 100644 index 00000000..af0ccc19 --- /dev/null +++ b/code/client/snd_mem_new.c @@ -0,0 +1,171 @@ +/* +=========================================================================== +Copyright (C) 2024 the OpenMoHAA team + +This file is part of OpenMoHAA source code. + +OpenMoHAA source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +OpenMoHAA source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with OpenMoHAA source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#if USE_SOUND_NEW + +# include "snd_local.h" + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + +qboolean S_LoadMP3(const char *fileName, sfx_t *sfx); + +short int GetLittleShort() +{ + union { + short value; + byte bytes[2]; + } val; + +# ifdef Q3_LITTLE_ENDIAN + val.bytes[1] = data_p[0]; + val.bytes[0] = data_p[1]; +# else + val.bytes[0] = data_p[0]; + val.bytes[1] = data_p[1]; +# endif + + data_p += sizeof(short); + return val.value; +} + +int GetLittleLong() +{ + union { + int value; + byte bytes[4]; + } val; + +# ifdef Q3_LITTLE_ENDIAN + val.bytes[3] = data_p[0]; + val.bytes[2] = data_p[1]; + val.bytes[1] = data_p[2]; + val.bytes[0] = data_p[3]; +# else + val.bytes[0] = data_p[0]; + val.bytes[1] = data_p[1]; + val.bytes[2] = data_p[2]; + val.bytes[3] = data_p[3]; +# endif + + data_p += sizeof(int); + return val.value; +} + +void SetLittleShort(int i) +{ + union { + short value; + byte bytes[2]; + } val; + + val.value = i; + +# ifdef Q3_LITTLE_ENDIAN + data_p[0] = val.bytes[1]; + data_p[1] = val.bytes[0]; +# else + data_p[0] = val.bytes[0]; + data_p[1] = val.bytes[1]; +# endif + + data_p += sizeof(short); +} + +void SetLittleLong(int i) +{ + union { + int value; + byte bytes[2]; + } val; + + val.value = i; + +# ifdef Q3_LITTLE_ENDIAN + data_p[0] = val.bytes[3]; + data_p[1] = val.bytes[2]; + data_p[2] = val.bytes[1]; + data_p[3] = val.bytes[0]; +# else + data_p[0] = val.bytes[0]; + data_p[1] = val.bytes[1]; + data_p[2] = val.bytes[2]; + data_p[3] = val.bytes[3]; +# endif + + data_p += sizeof(int); +} + +void FindNextChunk(const char *name) +{ + // FIXME: unimplemented +} + +void FindChunk(const char *name) +{ + // FIXME: unimplemented +} + +void DumpChunks() +{ + // FIXME: unimplemented +} + +wavinfo_t GetWavinfo(const char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int samples; + + memset(&info, 0, sizeof(wavinfo_t)); + + // FIXME: unimplemented + return info; +} + +int DownSampleWav(wavinfo_t *info, byte *wav, int wavlength, int newkhz, byte **newdata) +{ + // FIXME: unimplemented + return 0; +} + +int DownSampleWav_MILES(wavinfo_t *info, byte *wav, int wavlength, int newkhz, byte **newdata) +{ + // FIXME: unimplemented + return 0; +} + +qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean force_load) +{ + // FIXME: unimplemented + return qfalse; +} + +qboolean S_LoadMP3(const char *fileName, sfx_t *sfx) +{ + // FIXME: unimplemented + return qfalse; +} + +#endif From e936a0b995b3fe6cb627b62112e490aa2a915a3e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 19:44:04 +0100 Subject: [PATCH 0003/2040] Added more declarations --- code/client/cl_ui.h | 1 + code/client/snd_local_new.h | 19 +++++++++++++++++++ code/client/snd_openal_new.cpp | 2 +- code/client/snd_openal_new.h | 3 ++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/code/client/cl_ui.h b/code/client/cl_ui.h index 257161a7..329880f0 100644 --- a/code/client/cl_ui.h +++ b/code/client/cl_ui.h @@ -49,6 +49,7 @@ void CL_ShutdownUI(void); extern inventory_t client_inv; extern bind_t client_bind; extern cvar_t *cl_greenfps; +extern qboolean server_loading; const char *CvarGetForUI(const char *name, const char *defval); void UI_ClearState(void); diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 8707f56c..f7cf6118 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -130,10 +130,18 @@ typedef struct { channelbasesavegame_t Channels[96]; } soundsystemsavegame_t; +enum sfx_flags_t { + SFX_FLAG_DEFAULT_SOUND = 1 +}; + // The current sound driver. // Currently OPENAL #define SOUND_DRIVER OPENAL +// +// snd_dma_new.cpp +// + sfx_t *S_FindName(const char *name, int sequenceNumber); void S_DefaultSound(sfx_t *sfx); @@ -141,6 +149,11 @@ void S_LoadData(soundsystemsavegame_t *pSave); void S_SaveData(soundsystemsavegame_t *pSave); void S_ClearSoundBuffer(); +// +// snd_mem.c +// +qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean force_load); + #define S_StopAllSounds2 S_StopAllSounds // @@ -150,6 +163,7 @@ void S_ClearSoundBuffer(); #define S_Call_SndDriverX(driver, func) S_Call_SndDriver(driver, func) #define S_Driver_Init S_Call_SndDriverX(SOUND_DRIVER, Init) +#define S_Driver_Shutdown S_Call_SndDriverX(SOUND_DRIVER, Shutdown) #define S_Driver_StartSound S_Call_SndDriverX(SOUND_DRIVER, StartSound) #define S_Driver_AddLoopingSound S_Call_SndDriverX(SOUND_DRIVER, AddLoopingSound) #define S_Driver_ClearLoopingSounds S_Call_SndDriverX(SOUND_DRIVER, ClearLoopingSounds) @@ -159,6 +173,11 @@ void S_ClearSoundBuffer(); #define S_Driver_SetReverb S_Call_SndDriverX(SOUND_DRIVER, SetReverb) #define S_Driver_Update S_Call_SndDriverX(SOUND_DRIVER, Update) +void S_PrintInfo(); +void S_DumpInfo(); + +extern cvar_t *s_show_sounds; + #ifdef __cplusplus } #endif diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index e2146254..caeee87f 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -316,7 +316,7 @@ void S_OPENAL_StopLoopingSounds() // FIXME: unimplemented } -void S_OPENAL_StopSound(int iEntNum) +void S_OPENAL_StopSound(int iEntNum, int iEntChannel) { // FIXME: unimplemented } diff --git a/code/client/snd_openal_new.h b/code/client/snd_openal_new.h index a7b54ace..83648019 100644 --- a/code/client/snd_openal_new.h +++ b/code/client/snd_openal_new.h @@ -137,6 +137,7 @@ extern "C" { #endif qboolean S_OPENAL_Init(); +void S_OPENAL_Shutdown(); void S_OPENAL_StartSound( const vec3_t vOrigin, int iEntNum, @@ -159,7 +160,7 @@ void S_OPENAL_AddLoopingSound( int iFlags ); void S_OPENAL_ClearLoopingSounds(); -void S_OPENAL_StopSound(int iEntNum); +void S_OPENAL_StopSound(int iEntNum, int iEntChannel); void S_OPENAL_StopAllSounds(qboolean bStopMusic); void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxis[3]); void S_OPENAL_SetReverb(int iType, float fLevel); From 88ccaee5cc176502e3712ccbdb6413c11d1e4d38 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 20:07:26 +0100 Subject: [PATCH 0004/2040] Implemented C++ sound DMA --- code/client/snd_dma_new.cpp | 625 ++++++++++++++++++++++++++++++++++-- 1 file changed, 593 insertions(+), 32 deletions(-) diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index f08bb524..00289bc0 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -22,8 +22,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if USE_SOUND_NEW -#include "snd_local.h" -#include "snd_openal_new.h" +# include "snd_local.h" +# include "snd_openal_new.h" +# include "client.h" +# include "cl_ui.h" typedef struct { vec3_t origin; @@ -70,81 +72,401 @@ cvar_t *s_dialogscale; int numLoopSounds; loopSound_t loopSounds[MAX_LOOP_SOUNDS]; +/* +============== +S_SoundInfo_f +============== +*/ void S_SoundInfo_f() { - // FIXME: unimplemented + S_PrintInfo(); } +/* +============== +S_SoundDump_f +============== +*/ void S_SoundDump_f() { - // FIXME: unimplemented + S_DumpInfo(); } +/* +============== +S_Init +============== +*/ void S_Init(qboolean full_startup) { - // FIXME: unimplemented + int iStart, iEnd; + cvar_t *cv; + + Com_Printf("------- Sound Initialization (%s) -------\n", full_startup ? "full" : "partial"); + + iStart = Sys_Milliseconds(); + + s_volume = Cvar_Get("s_volume", "0.9", CVAR_ARCHIVE); + s_musicVolume = Cvar_Get("s_musicvolume", "0.9", CVAR_ARCHIVE); + s_ambientVolume = Cvar_Get("s_ambientvolume", "1.00", CVAR_ARCHIVE); + s_separation = Cvar_Get("s_separation", "0.5", CVAR_ARCHIVE); + s_khz = Cvar_Get("s_khz", "11", CVAR_ARCHIVE | CVAR_SOUND_LATCH); + s_loadas8bit = Cvar_Get("s_loadas8bit", "0", CVAR_ARCHIVE | CVAR_LATCH); + s_mixPreStep = Cvar_Get("s_mixPreStep", "0.05", CVAR_ARCHIVE); + s_show = Cvar_Get("s_show", "0", CVAR_CHEAT); + s_testsound = Cvar_Get("s_testsound", "0", CVAR_CHEAT); + s_dialogscale = Cvar_Get("s_dialogscale", "1", CVAR_ARCHIVE); + s_bLastInitSound = false; + + cv = Cvar_Get("s_initsound", "1", 0); + + if (cv->integer) { + Cmd_AddCommand("play", S_Play); + Cmd_AddCommand("soundlist", S_SoundList); + Cmd_AddCommand("soundinfo", S_SoundInfo_f); + Cmd_AddCommand("sounddump", S_SoundDump_f); + + if (S_Driver_Init()) { + s_bLastInitSound = true; + s_bSoundStarted = true; + + if (full_startup) { + s_numSfx = 0; + S_StopAllSounds(true); + } + + S_FindName("***DEFAULT***", -1); + S_SoundInfo_f(); + } + } else { + Com_Printf("Sound Not Initializing.\n"); + s_bSoundStarted = 0; + } + + iEnd = Sys_Milliseconds(); + Com_Printf("------- Sound Initialization Complete ------- %i ms\n", iEnd - iStart); } +/* +============== +S_Shutdown +============== +*/ void S_Shutdown(qboolean full_shutdown) { - // FIXME: unimplemented + int i; + sfx_t *sfx; + + if (!s_bSoundStarted) { + return; + } + + Com_Printf("------- Sound Shutdown (%s) -------\n", full_shutdown ? "full" : "partial"); + + S_Driver_Shutdown(); + s_bSoundStarted = false; + + Cmd_RemoveCommand("play"); + Cmd_RemoveCommand("music"); + Cmd_RemoveCommand("stopsound"); + Cmd_RemoveCommand("soundlist"); + Cmd_RemoveCommand("soundinfo"); + + if (full_shutdown) { + for (i = 0; i < s_numSfx; i++) { + sfx = &s_knownSfx[i]; + + if (sfx->name[0]) { + if (sfx->data) { + Z_Free(sfx->data); + } + + *sfx = {}; + } + } + + s_numSfx = 0; + } + + Com_Printf("------- Sound Shutdown Complete -------\n"); } +/* +============== +S_NameExists +============== +*/ qboolean S_NameExists(const char *name) { - // FIXME: unimplemented + int i; + + if (strlen(name) >= MAX_RES_NAME) { + Com_DPrintf("Sound name too long: %s", name); + return qfalse; + } + + for (i = 0; i < s_numSfx; i++) { + if (!strcmp(s_knownSfx[i].name, name)) { + return qtrue; + } + } + return qfalse; } +/* +============== +S_FindName +============== +*/ sfx_t *S_FindName(const char *name, int sequenceNumber) { - // FIXME: unimplemented - return NULL; + int i; + sfx_t *sfx; + + if (!name) { + Com_DPrintf("S_FindName: NULL\n"); + return NULL; + } + + if (!name[0]) { + Com_DPrintf("S_FindName: empty name\n"); + return NULL; + } + + if (strlen(name) >= MAX_RES_NAME) { + Com_DPrintf("Sound name too long: %s", name); + return NULL; + } + + for (i = 0; i < s_numSfx; i++) { + sfx = &s_knownSfx[i]; + + if (!strcmp(sfx->name, name)) { + if (sfx->registration_sequence != -1) { + sfx->registration_sequence = sequenceNumber; + } + + return sfx; + } + } + + sfx = &s_knownSfx[0]; + + for (i = 0; i < s_numSfx; i++) { + sfx = &s_knownSfx[i]; + if (!sfx->name[0]) { + break; + } + } + + if (i == s_numSfx) { + if (i == MAX_SFX) { + Com_Error(ERR_FATAL, "S_FindName: out of sfx_t"); + } + + s_numSfx++; + } + + *sfx = {}; + // Fixed in OPM + // strcpy was used before + //strcpy(sfx->name, name); + Q_strncpyz(sfx->name, name, sizeof(sfx->name)); + sfx->registration_sequence = sequenceNumber; + + return sfx; } +/* +============== +S_BeginRegistration +============== +*/ void S_BeginRegistration() { - // FIXME: unimplemented + Com_Printf("------- Sound Begin Registration -------\n"); + + S_StopAllSounds(true); + + ++s_registrationSequence; + s_inRegistration = true; + s_knownSfx[0].registration_sequence = s_registrationSequence; + + Com_Printf("------- Sound Begin Registration Complete -------\n"); } +/* +============== +S_DefaultSound +============== +*/ void S_DefaultSound(sfx_t *sfx) { - // FIXME: unimplemented + sfx->data = NULL; + sfx->iFlags |= SFX_FLAG_DEFAULT_SOUND; } +/* +============== +S_IsSoundRegistered +============== +*/ qboolean S_IsSoundRegistered(const char *name) { - // FIXME: unimplemented - return qfalse; + char szCacheName[MAX_QPATH]; + int i; + + if (!s_bSoundStarted) { + return qfalse; + } + + for (i = 0; name[i] && i < MAX_QPATH; i++) { + szCacheName[i] = tolower(name[i]); + } + szCacheName[i] = 0; + + if (i >= MAX_QPATH) { + Com_Printf("Sound name exceeds MAX_QPATH\n"); + return qfalse; + } + + return S_NameExists(szCacheName); } +/* +============== +S_RegisterSound +============== +*/ sfxHandle_t S_RegisterSound(const char *name, int streamed, qboolean force_load) { - // FIXME: unimplemented - return 0; + char szCacheName[MAX_QPATH]; + sfx_t *sfx; + int i; + + if (!s_bSoundStarted) { + Com_Printf("ERROR: Trying to register sound %s when soundsystem hasn't started.\n", name); + return 0; + } + + if (!name) { + return 0; + } + + for (i = 0; name[i] && i < MAX_QPATH; i++) { + szCacheName[i] = tolower(name[i]); + } + szCacheName[i] = 0; + + if (i >= MAX_QPATH) { + Com_Printf("Sound name exceeds MAX_QPATH\n"); + return 0; + } + + sfx = S_FindName(szCacheName, s_registrationSequence); + if (!sfx) { + return 0; + } + + if (!sfx->data) { + if (!S_LoadSound(sfx->name, sfx, streamed, force_load)) { + Com_DPrintf("Couldn't load sound: %s\n", sfx->name); + if (!S_LoadSound("sound/default.wav", sfx, streamed, 0)) { + Com_DPrintf("Couldn't load sound: sound/default.wav\n"); + sfx->iFlags |= SFX_FLAG_DEFAULT_SOUND; + return 0; + } + } + + sfx->iFlags &= ~SFX_FLAG_DEFAULT_SOUND; + sfx->sfx_info_index = 0; + + for (i = 0; i < number_of_sfx_infos; i++) { + if (!Q_stricmp(sfx->name, sfx_infos[i].name)) { + sfx->sfx_info_index = i; + break; + } + } + } + + return sfx - s_knownSfx; } +/* +============== +S_GetSoundTime +============== +*/ float S_GetSoundTime(sfxHandle_t handle) { - // FIXME: unimplemented - return 0; + return s_knownSfx[handle].time_length; } +/* +============== +S_EndRegistration +============== +*/ void S_EndRegistration() { - // FIXME: unimplemented + int i; + sfx_t *sfx; + + Com_Printf("------- Sound End Registration -------\n"); + s_inRegistration = qfalse; + + for (i = 0; i < s_numSfx; i++) { + sfx = &s_knownSfx[i]; + + if (!sfx->name[0]) { + continue; + } + + if (sfx->registration_sequence && sfx->registration_sequence != s_registrationSequence) { + if (sfx->data) { + Z_Free(sfx->data); + } + + *sfx = {}; + } + } + + Com_Printf("------- Sound End Registration Complete -------\n"); } +/* +============== +S_UpdateEntity +============== +*/ void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t vel, qboolean use_listener) { - // FIXME: unimplemented + if (entityNum > MAX_GENTITIES) { + Com_Error(ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum); + } + + VectorCopy(origin, s_entity[entityNum].position); + VectorCopy(vel, s_entity[entityNum].velocity); + s_entity[entityNum].use_listener = use_listener; + s_entity[entityNum].time = cl.serverTime; } +/* +============== +S_SetGlobalAmbientVolumeLevel +============== +*/ void S_SetGlobalAmbientVolumeLevel(float volume) { - // FIXME: unimplemented + s_fAmbientVolume = volume; } +/* +============== +S_StartSound +============== +*/ void S_StartSound( const vec3_t origin, int entnum, @@ -157,29 +479,171 @@ void S_StartSound( int streamed ) { - // FIXME: unimplemented + if (s_show_sounds->integer > 0 && sfxHandle > 0 && sfxHandle < s_numSfx) { + Com_DPrintf("S_StartSound: %s\n", s_knownSfx[sfxHandle].name); + } + + if (!s_bSoundStarted) { + if (s_show_sounds->integer > 0) { + Com_DPrintf("^~^~^ sound system not yet started\n"); + } + return; + } + + if (server_loading) { + if (s_show_sounds->integer > 0) { + Com_DPrintf("^~^~^ cannot start sounds while loading a server\n"); + } + return; + } + + if (sfxHandle < 0 || sfxHandle >= s_numSfx) { + Com_Error(ERR_DROP, "S_StartSound: handle %i out of range", sfxHandle); + } + + if (!sfxHandle) { + if (s_show_sounds->integer > 0) { + Com_DPrintf("^~^~^ null handle\n"); + } + return; + } + + if (entnum && (entchannel == CHAN_DIALOG || entchannel == CHAN_DIALOG_SECONDARY) && s_dialogscale->value > 0) { + volume *= s_dialogscale->value; + } + + S_Driver_StartSound(origin, entnum, entchannel, sfxHandle, volume, min_dist, pitch, maxDist, streamed); } +/* +============== +S_StartLocalSound +============== +*/ void S_StartLocalSound(const char *sound_name, qboolean force_load) { - // FIXME: unimplemented + sfxHandle_t sfxHandle; + const char *name; + AliasListNode_t *pSoundAlias; + + if (!s_bSoundStarted) { + return; + } + + if (!sound_name) { + return; + } + + name = Alias_FindRandom(sound_name, &pSoundAlias); + if (!name) { + name = sound_name; + } + + sfxHandle = S_RegisterSound(name, pSoundAlias ? pSoundAlias->streamed : qfalse, force_load); + + if (!pSoundAlias) { + S_StartSound(NULL, s_iListenerNumber, CHAN_MENU, sfxHandle, -1.0, -1.0, 1.0, -1.0, qfalse); + return; + } + + S_StartSound( + 0, + s_iListenerNumber, + CHAN_MENU, + sfxHandle, + pSoundAlias->volume + random() * pSoundAlias->volumeMod, + -1.0, + pSoundAlias->pitch + random() * pSoundAlias->pitchMod, + pSoundAlias->maxDist, + pSoundAlias->streamed + ); } +/* +============== +S_StartLocalSoundChannel + +Added in 2.0 +Starts a local sound, with the specified channel +============== +*/ void S_StartLocalSoundChannel(const char *sound_name, qboolean force_load, soundChannel_t channel) { - // FIXME: unimplemented + sfxHandle_t sfxHandle; + const char *name; + AliasListNode_t *pSoundAlias; + + if (!s_bSoundStarted) { + return; + } + + if (!sound_name) { + return; + } + + name = Alias_FindRandom(sound_name, &pSoundAlias); + if (!name) { + name = sound_name; + } + + sfxHandle = S_RegisterSound(name, pSoundAlias ? pSoundAlias->streamed : qfalse, force_load); + + if (!pSoundAlias) { + S_StartSound(NULL, s_iListenerNumber, channel, sfxHandle, -1.0, -1.0, 1.0, -1.0, qfalse); + return; + } + + S_StartSound( + 0, + s_iListenerNumber, + channel, + sfxHandle, + pSoundAlias->volume + random() * pSoundAlias->volumeMod, + -1.0, + pSoundAlias->pitch + random() * pSoundAlias->pitchMod, + pSoundAlias->maxDist, + pSoundAlias->streamed + ); } +/* +============== +S_StopAllSounds +============== +*/ void S_StopAllSounds(qboolean stop_music) { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + Com_Printf("------- S_StopAllSounds (%s) -------\n", stop_music ? "stop music" : "don't stop music"); + + // Tell the driver to stop all sounds + S_Driver_StopAllSounds(stop_music); + + Com_Printf("------- S_StopAllSounds Complete-------\n"); } +/* +============== +S_ClearLoopingSounds +============== +*/ void S_ClearLoopingSounds() { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + S_Driver_ClearLoopingSounds(); } +/* +============== +S_AddLoopingSound +============== +*/ void S_AddLoopingSound( const vec3_t origin, const vec3_t velocity, @@ -191,39 +655,136 @@ void S_AddLoopingSound( int flags ) { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + if (sfxHandle < 0 || sfxHandle >= s_numSfx) { + Com_Error(ERR_DROP, "S_AddLoopingSound: handle %i out of range", sfxHandle); + } + + if (!sfxHandle) { + return; + } + + S_Driver_AddLoopingSound(origin, velocity, sfxHandle, volume, min_dist, max_dist, pitch, flags); } +/* +============== +S_Respatialize +============== +*/ void S_Respatialize(int entityNum, const vec3_t head, vec3_t axis[3]) { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + S_Driver_Respatialize(entityNum, head, axis); } +/* +============== +S_Update +============== +*/ void S_Update() { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + if (server_loading) { + return; + } + + S_Driver_Update(); } +/* +============== +S_StopSound +============== +*/ void S_StopSound(int entnum, int channel) { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + if (channel == CHAN_AUTO) { + return; + } + + S_Driver_StopSound(entnum, channel); } +/* +============== +S_SetReverb +============== +*/ void S_SetReverb(int reverb_type, float reverb_level) { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + S_Driver_SetReverb(reverb_type, reverb_level); } +/* +============== +S_Play +============== +*/ void S_Play() { - // FIXME: unimplemented + int i; + char name[MAX_QPATH]; + + for (i = 1; i < Cmd_Argc(); i++) { + if (strrchr(Cmd_Argv(i), '.')) { + Q_strncpyz(name, Cmd_Argv(i), sizeof(name)); + } else { + Com_sprintf(name, sizeof(name), "%s.wav", Cmd_Argv(1)); + } + } + + S_StartLocalSound(name, qfalse); } +/* +============== +S_SoundList +============== +*/ void S_SoundList() { - // FIXME: unimplemented + int i; + sfx_t *sfx; + int size; + int total = 0; + + for (i = 0; i < s_numSfx; i++) { + sfx = &s_knownSfx[i]; + + if (sfx->registration_sequence) { + size = sfx->length * sfx->width; + total += size; + Com_Printf("(%2db) %6i : %s\n", sfx->width * 8, size, sfx->name); + } + } + + Com_Printf("Total resident: %i\n", total); } +/* +============== +S_ClearSoundBuffer +============== +*/ void S_ClearSoundBuffer() { // TODO: Remove once AL is fully implemented From 09ad42ba478a0800070ef7712dcb4c5aa2580fa7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 22:56:26 +0100 Subject: [PATCH 0005/2040] Fixed players not being able to use while firing, below 2.0 --- code/fgame/player.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index f94913bf..5b524fa0 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -3433,12 +3433,14 @@ void Player::DoUse(Event *ev) return; } - if ((buttons & BUTTON_ATTACKLEFT) || (buttons & BUTTON_ATTACKRIGHT)) { - // - // Added in 2.0 - // Only allow use if the player isn't holding attack buttons - // - return; + if (g_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + if ((buttons & BUTTON_ATTACKLEFT) || (buttons & BUTTON_ATTACKRIGHT)) { + // + // Added in 2.0 + // Only allow use if the player isn't holding attack buttons + // + return; + } } num = getUseableEntities(touch, MAX_GENTITIES, true); From 2e10a96d11be296ebc1885d529706b49cae6b265 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:05:21 +0100 Subject: [PATCH 0006/2040] Crosshair must always be shown in 1.11 and below regardless of the property --- code/fgame/weapon.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index f6921757..a4336227 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -4149,6 +4149,11 @@ void Weapon::FallingAngleAdjust(Event *ev) //====================== qboolean Weapon::GetUseCrosshair() const { + if (g_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + // Always show the crosshair in 1.11 and below + return qtrue; + } + if (m_fMaxFireMovement >= 1.f) { return crosshair; } From 5c4c14a17d38de15dd7296546e9e915cd1291e41 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:15:09 +0100 Subject: [PATCH 0007/2040] Added SFX flags --- code/client/snd_local_new.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index f7cf6118..7c128643 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -29,6 +29,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA extern "C" { #endif +extern cvar_t *s_khz; + typedef struct { int format; float rate; @@ -131,7 +133,10 @@ typedef struct { } soundsystemsavegame_t; enum sfx_flags_t { - SFX_FLAG_DEFAULT_SOUND = 1 + SFX_FLAG_DEFAULT_SOUND = 1, + SFX_FLAG_MP3 = 2, + SFX_FLAG_NO_DATA = 4, + SFX_FLAG_NO_OFFSET = 8, }; // The current sound driver. From 028489d673171d73dcfc24a88dce68364da6163e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:15:12 +0100 Subject: [PATCH 0008/2040] Implemented snd_mem_new.c --- code/client/snd_mem_new.c | 395 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 383 insertions(+), 12 deletions(-) diff --git a/code/client/snd_mem_new.c b/code/client/snd_mem_new.c index af0ccc19..b9eee6c6 100644 --- a/code/client/snd_mem_new.c +++ b/code/client/snd_mem_new.c @@ -32,6 +32,11 @@ int iff_chunk_len; qboolean S_LoadMP3(const char *fileName, sfx_t *sfx); +/* +============== +GetLittleShort +============== +*/ short int GetLittleShort() { union { @@ -51,6 +56,11 @@ short int GetLittleShort() return val.value; } +/* +============== +GetLittleLong +============== +*/ int GetLittleLong() { union { @@ -74,6 +84,11 @@ int GetLittleLong() return val.value; } +/* +============== +SetLittleShort +============== +*/ void SetLittleShort(int i) { union { @@ -94,6 +109,11 @@ void SetLittleShort(int i) data_p += sizeof(short); } +/* +============== +SetLittleLong +============== +*/ void SetLittleLong(int i) { union { @@ -118,21 +138,83 @@ void SetLittleLong(int i) data_p += sizeof(int); } +/* +============== +FindNextChunk +============== +*/ void FindNextChunk(const char *name) { - // FIXME: unimplemented + int value; + + while (1) { + data_p = last_chunk; + + if (last_chunk >= (byte *)iff_end) { + break; + } + + data_p = last_chunk + 4; + value = GetLittleLong(); + + iff_chunk_len = value; + if (value < 0) { + break; + } + + data_p -= 8; + value++; + value &= ~1; + + last_chunk = data_p + value * 8; + if (!strncmp((const char *)data_p, name, 4u)) { + return; + } + } + + data_p = NULL; } +/* +============== +FindChunk +============== +*/ void FindChunk(const char *name) { - // FIXME: unimplemented + last_chunk = iff_data; + FindNextChunk(name); } +/* +============== +DumpChunks +============== +*/ void DumpChunks() { - // FIXME: unimplemented + char str[5]; + + str[4] = 0; + + data_p = iff_data; + do { + memcpy(str, data_p, 4); + data_p += 4; + + iff_chunk_len = GetLittleLong(); + + Com_Printf("0x%x : %s (%d)\n", data_p - 4, str, iff_chunk_len); + + data_p += (iff_chunk_len + 1) & ~1; + } while (data_p < (byte *)iff_end); } +/* +============== +GetWavinfo +============== +*/ wavinfo_t GetWavinfo(const char *name, byte *wav, int wavlength) { wavinfo_t info; @@ -140,32 +222,321 @@ wavinfo_t GetWavinfo(const char *name, byte *wav, int wavlength) memset(&info, 0, sizeof(wavinfo_t)); - // FIXME: unimplemented + if (!wav) { + return info; + } + + iff_data = wav; + iff_end = &wav[wavlength]; + FindChunk("RIFF"); + + if (!data_p || strncmp((const char *)data_p + 8, "WAVE", 4u)) { + Com_Printf("Missing RIFF/WAVE chunks\n"); + return info; + } + + iff_data = data_p + 12; + FindChunk("fmt "); + if (!data_p) { + Com_Printf("Missing fmt chunk\n"); + return info; + } + + data_p += 8; + + info.format = GetLittleShort(); + if (info.format == 17) { + info.channels = GetLittleShort(); + info.rate = (float)GetLittleLong(); + data_p += 6; + info.width = (float)GetLittleShort() / 8.f; + data_p += 2; + + FindChunk("data"); + if (!data_p) { + Com_Printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + if (info.width >= 1.0) { + samples = (int)((float)GetLittleLong() / info.width); + } else { + samples = (int)((float)GetLittleLong() * info.width); + } + + if (!info.samples) { + info.samples = samples; + } else if (samples < info.samples) { + Com_Error(ERR_DROP, "Sound %s has a bad loop length", name); + } + + info.dataofs = 0; + } else if (info.format == 1) { + info.channels = GetLittleShort(); + info.rate = (float)GetLittleLong(); + data_p += 6; + info.width = (float)(GetLittleShort() / 8); + + FindChunk("data"); + if (!data_p) { + Com_Printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = (float)GetLittleLong() / info.width; + + if (!info.samples) { + info.samples = samples; + } else if (samples < info.samples) { + Com_Error(ERR_DROP, "Sound %s has a bad loop length", name); + } + + info.dataofs = data_p - wav; + } else { + Com_Printf("Microsoft PCM format only\n"); + return info; + } + + info.datasize = iff_chunk_len; + return info; } -int DownSampleWav(wavinfo_t *info, byte *wav, int wavlength, int newkhz, byte **newdata) +/* +============== +DownSampleWav +============== +*/ +qboolean DownSampleWav(wavinfo_t *info, byte *wav, int wavlength, int newkhz, byte **newdata) { - // FIXME: unimplemented - return 0; + int newdatasize; + byte* datap; + int i; + int ii; + int error; + int width; + int oldsamples; + int oldrate; + + newdatasize = 0; + datap = &wav[info->dataofs]; + + if (info->channels > 1) + { + Com_DPrintf("Could not downsample WAV file. Stereo WAVs not supported!\n"); + return 0; + } + + if (info->format != 1 || !info->dataofs) + { + Com_DPrintf("Could not downsample WAV file. Not PCM format!\n"); + return 0; + } + + if (info->rate <= newkhz) { + return 0; + } + + error = 0; + width = info->width; + for (i = 0; i < info->samples; i++) { + error += newkhz; + while (error > info->rate) { + error -= info->rate; + newdatasize += width; + } + } + + oldsamples = info->samples; + oldrate = info->rate; + info->samples = newdatasize / width; + info->rate = (float)newkhz; + newdatasize += info->dataofs; + + *newdata = Z_TagMalloc(newdatasize, TAG_SOUND); + memcpy(*newdata, wav, info->dataofs); + + iff_data = *newdata; + iff_end = *newdata + newdatasize; + FindChunk("RIFF"); + + if (!data_p || strncmp((const char*)data_p + 8, "WAVE", 4u)) + { + Com_DPrintf("Missing RIFF/WAVE chunks\n"); + return 0; + } + + iff_data = data_p + 12; + FindChunk("fmt "); + if (!data_p) + { + Com_DPrintf("Missing fmt chunk\n"); + return 0; + } + + data_p += 12; + SetLittleShort((int)info->rate); + data_p += 8; + + FindChunk("data"); + if (!data_p) + { + Com_DPrintf("Missing data chunk\n"); + return 0; + } + + data_p += 4; + SetLittleLong((int)(info->samples * info->width)); + + error = 0; + for (i = 0; i < oldsamples; i++) { + error += newkhz; + while (error > oldrate) { + error -= oldrate; + for (ii = 0; ii < width; i++) { + data_p[ii] = datap[ii]; + } + + data_p += width; + } + + datap += width; + } + + return newdatasize; } +/* +============== +DownSampleWav_MILES +============== +*/ int DownSampleWav_MILES(wavinfo_t *info, byte *wav, int wavlength, int newkhz, byte **newdata) { - // FIXME: unimplemented + STUB_DESC("sound stuff"); return 0; } +/* +============== +S_LoadSound +============== +*/ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean force_load) { - // FIXME: unimplemented - return qfalse; + int size; + fileHandle_t file_handle; + char tempName[MAX_RES_NAME + 1]; + int realKhz; + + sfx->buffer = NULL; + + if (fileName[0] == '*') { + return qfalse; + } + + if (strstr(fileName, ".mp3")) { + return S_LoadMP3(fileName, sfx); + } + + size = FS_FOpenFileRead(fileName, &file_handle, qfalse, qtrue); + if (size <= 0) + { + if (file_handle) { + FS_FCloseFile(file_handle); + } + return qfalse; + } + + sfx->data = Z_TagMalloc(size, TAG_SOUND); + + FS_Read(sfx->data, size, file_handle); + FS_FCloseFile(file_handle); + sfx->info = GetWavinfo(fileName, sfx->data, size); + + if (sfx->info.channels != 1) + { + Com_Printf("%s is a stereo wav file\n", fileName); + Z_Free(sfx->data); + sfx->data = NULL; + return qfalse; + } + + if (!sfx->info.dataofs) { + sfx->iFlags |= SFX_FLAG_NO_OFFSET; + } + + realKhz = 11025; + + if (s_khz->integer != 11) + { + realKhz = 22050; + if (s_khz->integer == 44) { + realKhz = 44100; + } + } + + if (!(sfx->iFlags & SFX_FLAG_NO_DATA) && realKhz < sfx->info.rate) { + byte* newdata; + int newdatasize; + + newdata = NULL; + if (sfx->iFlags & SFX_FLAG_NO_OFFSET) { + newdatasize = DownSampleWav_MILES(&sfx->info, sfx->data, size, realKhz, &newdata); + } else { + newdatasize = DownSampleWav(&sfx->info, sfx->data, size, realKhz, &newdata); + } + + if (newdatasize) { + Z_Free(sfx->data); + sfx->data = newdata; + } + } + + sfx->length = sfx->info.samples; + sfx->width = sfx->info.width; + sfx->time_length = sfx->info.samples / sfx->info.rate * 1000.f; + + if (sfx->iFlags & SFX_FLAG_NO_DATA) { + Z_Free(sfx->data); + sfx->data = NULL; + } + + sprintf(tempName, "k%s", fileName); + UI_LoadResource(tempName); + return qtrue; } +/* +============== +S_LoadMP3 +============== +*/ qboolean S_LoadMP3(const char *fileName, sfx_t *sfx) { - // FIXME: unimplemented - return qfalse; + int length; + fileHandle_t file_handle; + + length = FS_FOpenFileRead(fileName, &file_handle, 0, 1); + if (length <= 0) { + if (file_handle) { + FS_FCloseFile(file_handle); + } + return qfalse; + } + + memset(&sfx->info, 0, sizeof(sfx->info)); + sfx->data = Z_TagMalloc(length, TAG_SOUND); + sfx->length = length; + sfx->width = 1; + FS_Read(sfx->data, length, file_handle); + FS_FCloseFile(file_handle); + + sfx->iFlags |= SFX_FLAG_MP3; + + return qtrue; } #endif From 8b85e4e0756fc751f9c3570ff55b0499011633e6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:25:41 +0100 Subject: [PATCH 0009/2040] Export number_of_sfx_infos and sfx_infos --- code/client/snd_dma_new.cpp | 4 ---- code/client/snd_local_new.h | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index 00289bc0..35c78787 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -34,10 +34,6 @@ typedef struct { int mergeFrame; } loopSound_t; -# define MAX_SFX 1400 -# define MAX_SFX_INFOS 1000 -# define MAX_LOOP_SOUNDS 64 - qboolean s_bLastInitSound = qfalse; qboolean s_bSoundStarted = qfalse; qboolean s_bSoundPaused = qfalse; diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 7c128643..a3412466 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -139,6 +139,13 @@ enum sfx_flags_t { SFX_FLAG_NO_OFFSET = 8, }; +#define MAX_SFX 1400 +#define MAX_SFX_INFOS 1000 +#define MAX_LOOP_SOUNDS 64 + +extern int number_of_sfx_infos; +extern sfx_info_t sfx_infos[]; + // The current sound driver. // Currently OPENAL #define SOUND_DRIVER OPENAL From 71dba1b7dc530a92f2614616bb6ca086eaf61118 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:25:48 +0100 Subject: [PATCH 0010/2040] Added snd_info.cpp --- code/client/snd_info.cpp | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 code/client/snd_info.cpp diff --git a/code/client/snd_info.cpp b/code/client/snd_info.cpp new file mode 100644 index 00000000..6cbdc02b --- /dev/null +++ b/code/client/snd_info.cpp @@ -0,0 +1,99 @@ +/* +=========================================================================== +Copyright (C) 2024 the OpenMoHAA team + +This file is part of OpenMoHAA source code. + +OpenMoHAA source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +OpenMoHAA source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with OpenMoHAA source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#if USE_SOUND_NEW + +# include "snd_local.h" +# include "../qcommon/tiki.h" + +void load_sfx_info() +{ + TikiScript tiki; + const char *token; + int current_sound_file; + char file_name[MAX_QPATH]; + + sfx_infos[0].name[0] = 0; + sfx_infos[0].max_factor = -1.0; + sfx_infos[0].loop_start = -1; + sfx_infos[0].loop_end = -1; + sfx_infos[0].max_number_playing = 5; + number_of_sfx_infos = 1; + + for (current_sound_file = 0; current_sound_file < 10; current_sound_file++) { + Com_sprintf(file_name, sizeof(file_name), "global/sound%d.txt", current_sound_file); + + if (!tiki.LoadFile(file_name, qtrue)) { + continue; + } + + Com_Printf("Loading %s\n", file_name); + + while (tiki.TokenAvailable(qtrue)) { + token = tiki.GetToken(qtrue); + + if (!Q_stricmp(token, "sound")) { + if (tiki.TokenAvailable(qtrue)) { + token = tiki.GetToken(qtrue); + + if (number_of_sfx_infos == 1000) { + Com_DPrintf("Too many sound infos specified\n"); + break; + } + + Q_strncpyz(sfx_infos[number_of_sfx_infos].name, token, sizeof(sfx_infos[number_of_sfx_infos].name)); + sfx_infos[number_of_sfx_infos].max_factor = -1.f; + sfx_infos[number_of_sfx_infos].loop_start = -1; + sfx_infos[number_of_sfx_infos].loop_end = -1; + sfx_infos[number_of_sfx_infos].max_number_playing = 5; + number_of_sfx_infos++; + } + } else if (!Q_stricmp(token, "loopstart")) { + if (!tiki.TokenAvailable(qtrue)) { + token = tiki.GetToken(qtrue); + sfx_infos[number_of_sfx_infos - 1].loop_start = atoi(token); + } + } else if (!Q_stricmp(token, "loopend")) { + if (!tiki.TokenAvailable(qtrue)) { + token = tiki.GetToken(qtrue); + sfx_infos[number_of_sfx_infos - 1].loop_end = atoi(token); + } + } else if (!Q_stricmp(token, "maxnumber")) { + if (!tiki.TokenAvailable(qtrue)) { + token = tiki.GetToken(qtrue); + sfx_infos[number_of_sfx_infos - 1].max_number_playing = atoi(token); + } + } else if (!Q_stricmp(token, "maxfactor")) { + if (!tiki.TokenAvailable(qtrue)) { + token = tiki.GetToken(qtrue); + sfx_infos[number_of_sfx_infos - 1].max_factor = atoi(token); + } + } + } + } + + tiki.Close(); + + sfx_infos[0].name[0] = 0; +} + +#endif From aac9dd40def57cf7f762cd9d7e1fc99aade0a758 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:27:51 +0100 Subject: [PATCH 0011/2040] Add USE_OPENAL=1 definition when USE_SOUND_NEW is defined --- code/client/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index 6bdd9d49..af694882 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -9,6 +9,7 @@ file(GLOB_RECURSE SOURCES_UILIB "../uilib/*.c*") # Made as an interface and not static, as static only links used methods add_library(omohclient INTERFACE) target_compile_definitions(omohclient INTERFACE APP_MODULE) +target_compile_definitions(omohclient INTERFACE USE_OPENAL_DLOPEN=1) target_compile_features(omohclient INTERFACE cxx_nullptr) target_compile_features(omohclient INTERFACE c_variadic_macros) target_link_libraries(omohclient INTERFACE omohsdl) @@ -21,7 +22,7 @@ if (USE_SOUND_NEW) # Try to use OpenAL find_package(OpenAL) if (OPENAL_FOUND) - target_compile_definitions(omohclient INTERFACE USE_SOUND_NEW=1) + target_compile_definitions(omohclient INTERFACE USE_OPENAL=1 USE_SOUND_NEW=1) if (MSVC) target_include_directories(omohclient INTERFACE ${OPENAL_INCLUDE_DIR}/AL) else() From 46aa58d0cd5c4da10c9e24c7d602ea41f0ec79d9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:28:01 +0100 Subject: [PATCH 0012/2040] Made qal.h C++ aware --- code/client/qal.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/client/qal.h b/code/client/qal.h index a478eb53..c72285b3 100644 --- a/code/client/qal.h +++ b/code/client/qal.h @@ -55,6 +55,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif +#ifdef __cplusplus +extern "C" { +#endif + #ifdef USE_OPENAL_DLOPEN extern LPALENABLE qalEnable; extern LPALDISABLE qalDisable; @@ -248,4 +252,8 @@ extern LPALCCAPTURESAMPLES qalcCaptureSamples; qboolean QAL_Init(const char *libname); void QAL_Shutdown( void ); +#ifdef __cplusplus +} +#endif + #endif // __QAL_H__ From 26c50f15dcd2e46749433a92f12101d8c85e3b59 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:28:28 +0100 Subject: [PATCH 0013/2040] Added s_volume and sfx exports + added load_sfx_info() declaration --- code/client/snd_local_new.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index a3412466..9dfdd0aa 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA extern "C" { #endif +extern cvar_t *s_volume; extern cvar_t *s_khz; typedef struct { @@ -145,11 +146,18 @@ enum sfx_flags_t { extern int number_of_sfx_infos; extern sfx_info_t sfx_infos[]; +extern sfx_t s_knownSfx[]; +extern int s_numSfx; // The current sound driver. // Currently OPENAL #define SOUND_DRIVER OPENAL +// +// snd_info.cpp +// +void load_sfx_info(); + // // snd_dma_new.cpp // From 13f23ace767332f4cf5623efd2c4451037963e19 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:30:29 +0100 Subject: [PATCH 0014/2040] Added macros for more clarity --- code/client/snd_openal_new.h | 110 ++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/code/client/snd_openal_new.h b/code/client/snd_openal_new.h index 83648019..14f14230 100644 --- a/code/client/snd_openal_new.h +++ b/code/client/snd_openal_new.h @@ -29,6 +29,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA typedef int S32; typedef unsigned int U32; +#define MAX_OPENAL_CHANNELS_3D 32 +#define MAX_OPENAL_CHANNELS_2D 32 +#define MAX_OPENAL_CHANNELS_2D_STREAM 32 +#define MAX_OPENAL_SONGS 2 +#define MAX_OPENAL_CHANNELS \ + (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM + MAX_OPENAL_SONGS + 3) +#define MAX_OPENAL_LOOP_SOUNDS 64 + +#define OPENAL_CHANNEL_MP3_ID \ + (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM + MAX_OPENAL_SONGS) +#define OPENAL_CHANNEL_TRIGGER_MUSIC_ID (OPENAL_CHANNEL_MP3_ID + 1) +#define OPENAL_CHANNEL_MOVIE_ID (OPENAL_CHANNEL_TRIGGER_MUSIC_ID + 1) + typedef enum { FADE_NONE, FADE_IN, @@ -36,46 +49,56 @@ typedef enum { } fade_t; typedef struct { - vec3_t vOrigin; - vec3_t vRelativeOrigin; - vec3_t vVelocity; + vec3_t vOrigin; + vec3_t vRelativeOrigin; + vec3_t vVelocity; + sfx_t *pSfx; qboolean bPlaying; - int iChannel; - float fVolume; - float fPitch; + + int iChannel; + float fVolume; + float fPitch; + int iStartTime; qboolean bInUse; qboolean bCombine; - float fBaseVolume; - float fMinDist; - float fMaxDist; - int iFlags; + + float fBaseVolume; + float fMinDist; + float fMaxDist; + int iFlags; } openal_loop_sound_t; struct openal_channel { - sfx_t *pSfx; - int iEntNum; - int iEntChannel; - vec3_t vOrigin; - float fVolume; - int iBaseRate; - float fNewPitchMult; - float fMinDist; - float fMaxDist; - int iStartTime; - int iTime; - int iEndTime; - int iFlags; - int iPausedOffset; - int song_number; - fade_t fading; - int fade_time; - int fade_start_time; + sfx_t *pSfx; + int iEntNum; + int iEntChannel; + vec3_t vOrigin; + + float fVolume; + int iBaseRate; + float fNewPitchMult; + float fMinDist; + float fMaxDist; + + int iStartTime; + int iTime; + int iEndTime; + int iFlags; + int iPausedOffset; + + int song_number; + + fade_t fading; + int fade_time; + int fade_start_time; + ALuint source; ALuint buffer; ALubyte *bufferdata; +public: void play(); void stop(); void pause(); @@ -117,19 +140,24 @@ struct openal_channel { }; struct openal_internal_t { - openal_channel chan_3D[32]; - openal_channel chan_2D[32]; - openal_channel chan_2D_stream[32]; - openal_channel chan_song[2]; - openal_channel chan_mp3; - openal_channel chan_trig_music; - openal_channel chan_movie; - openal_channel *channel[101]; - openal_loop_sound_t loop_sounds[64]; - openal_channel movieChannel; - sfx_t movieSFX; - char tm_filename[64]; - int tm_loopcount; + openal_channel chan_3D[MAX_OPENAL_CHANNELS_3D]; + openal_channel chan_2D[MAX_OPENAL_CHANNELS_2D]; + openal_channel chan_2D_stream[MAX_OPENAL_CHANNELS_2D_STREAM]; + openal_channel chan_song[MAX_OPENAL_SONGS]; + openal_channel chan_mp3; + openal_channel chan_trig_music; + openal_channel chan_movie; + + // Pointers to channels + openal_channel *channel[MAX_OPENAL_CHANNELS]; + + openal_loop_sound_t loop_sounds[MAX_OPENAL_LOOP_SOUNDS]; + + openal_channel movieChannel; + sfx_t movieSFX; + + char tm_filename[MAX_RES_NAME]; + int tm_loopcount; }; #ifdef __cplusplus From 3be1673eb9eace4be9ee1e5569e1e98670a40ebd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:32:44 +0100 Subject: [PATCH 0015/2040] Added boolean sound DMA variables --- code/client/snd_local_new.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 9dfdd0aa..01e27197 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -144,6 +144,10 @@ enum sfx_flags_t { #define MAX_SFX_INFOS 1000 #define MAX_LOOP_SOUNDS 64 +extern qboolean s_bLastInitSound; +extern qboolean s_bSoundStarted; +extern qboolean s_bSoundPaused; +extern qboolean s_bTryUnpause; extern int number_of_sfx_infos; extern sfx_info_t sfx_infos[]; extern sfx_t s_knownSfx[]; From d3de937ee0d38d7809bed2556e72cf481a154d4c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:45:53 +0100 Subject: [PATCH 0016/2040] Added FS_CorrectCase --- code/qcommon/qcommon.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 6fc4385a..dd1cabcc 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -700,6 +700,8 @@ void FS_FreeFileList( char **list ); qboolean FS_FileExists( const char *file ); +void FS_CorrectCase(char* path); + char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); qboolean FS_CreatePath(char *OSPath); From 8d327cd0a0797ebaca4230368d79a202f30fafe9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:02:30 +0100 Subject: [PATCH 0017/2040] Added more SFX flags and exports --- code/client/snd_local_new.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 01e27197..e379933e 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -31,6 +31,7 @@ extern "C" { extern cvar_t *s_volume; extern cvar_t *s_khz; +extern cvar_t *s_loadas8bit; typedef struct { int format; @@ -134,10 +135,13 @@ typedef struct { } soundsystemsavegame_t; enum sfx_flags_t { - SFX_FLAG_DEFAULT_SOUND = 1, - SFX_FLAG_MP3 = 2, - SFX_FLAG_NO_DATA = 4, - SFX_FLAG_NO_OFFSET = 8, + SFX_FLAG_DEFAULT_SOUND = 1, + SFX_FLAG_MP3 = 2, + SFX_FLAG_NO_DATA = 4, + SFX_FLAG_NO_OFFSET = 8, + SFX_FLAG_LOCAL_LISTENER = 16, + SFX_FLAG_NO_ENTITY = 32, + SFX_FLAG_PAUSED = 64, }; #define MAX_SFX 1400 @@ -148,6 +152,7 @@ extern qboolean s_bLastInitSound; extern qboolean s_bSoundStarted; extern qboolean s_bSoundPaused; extern qboolean s_bTryUnpause; +extern int s_iListenerNumber; extern int number_of_sfx_infos; extern sfx_info_t sfx_infos[]; extern sfx_t s_knownSfx[]; From 318dc1889145f4de2b33f345afd28db20001f606 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:03:03 +0100 Subject: [PATCH 0018/2040] Added MAX_OPENAL_POSITION_CHANNELS --- code/client/snd_openal_new.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/client/snd_openal_new.h b/code/client/snd_openal_new.h index 14f14230..1fbec8ba 100644 --- a/code/client/snd_openal_new.h +++ b/code/client/snd_openal_new.h @@ -32,9 +32,12 @@ typedef unsigned int U32; #define MAX_OPENAL_CHANNELS_3D 32 #define MAX_OPENAL_CHANNELS_2D 32 #define MAX_OPENAL_CHANNELS_2D_STREAM 32 +#define MAX_OPENAL_POSITION_CHANNELS (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM) #define MAX_OPENAL_SONGS 2 -#define MAX_OPENAL_CHANNELS \ - (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM + MAX_OPENAL_SONGS + 3) +#define MAX_OPENAL_MISC_CHANNELS 3 +#define MAX_OPENAL_CHANNELS \ + (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM + MAX_OPENAL_SONGS \ + + MAX_OPENAL_MISC_CHANNELS) #define MAX_OPENAL_LOOP_SOUNDS 64 #define OPENAL_CHANNEL_MP3_ID \ From 9ea7b772314f1e71895ea286e238949eabe4c0e0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 12 Jan 2024 00:04:20 +0100 Subject: [PATCH 0019/2040] Added channel flags and loopsound flags --- code/client/snd_local_new.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index e379933e..26e7eb24 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -134,14 +134,23 @@ typedef struct { channelbasesavegame_t Channels[96]; } soundsystemsavegame_t; +enum channel_flags_t { + CHANNEL_FLAG_PLAYABLE = 1, + CHANNEL_FLAG_LOCAL_LISTENER = 16, + CHANNEL_FLAG_NO_ENTITY = 32, + CHANNEL_FLAG_PAUSED = 64, + CHANNEL_FLAG_LOOPING = 128, +}; + enum sfx_flags_t { - SFX_FLAG_DEFAULT_SOUND = 1, - SFX_FLAG_MP3 = 2, - SFX_FLAG_NO_DATA = 4, - SFX_FLAG_NO_OFFSET = 8, - SFX_FLAG_LOCAL_LISTENER = 16, - SFX_FLAG_NO_ENTITY = 32, - SFX_FLAG_PAUSED = 64, + SFX_FLAG_DEFAULT_SOUND = 1, + SFX_FLAG_MP3 = 2, + SFX_FLAG_NO_DATA = 4, + SFX_FLAG_NO_OFFSET = 8, +}; + +enum loopsound_flags_t { + LOOPSOUND_FLAG_NO_PAN = 1 }; #define MAX_SFX 1400 From 032eb11cfb2d405c654701455e1a612e0e4ace43 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 12 Jan 2024 00:04:36 +0100 Subject: [PATCH 0020/2040] Implemented various methods --- code/client/snd_openal_new.cpp | 1286 ++++++++++++++++++++++++++++++-- 1 file changed, 1230 insertions(+), 56 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index caeee87f..25aa813f 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -24,6 +24,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include "snd_local.h" # include "snd_openal_new.h" +# include "client.h" +# include "../server/server.h" + +# include typedef struct { char *funcname; @@ -63,7 +67,7 @@ static bool al_initialized = false; static bool al_use_reverb = false; static float al_current_volume = 0; static unsigned int al_frequency = 22050; -static void *al_context_id = NULL; +static ALCcontext *al_context_id = NULL; static ALCdevice *al_device = NULL; static ALboolean (*_alutLoadMP3_LOKI)(unsigned int buffer, const byte *data, int length); @@ -90,172 +94,848 @@ static float s_fFadeStartTime; static float s_fFadeStopTime; static char current_soundtrack[128]; -static void __alDieIfError(char *file) +static void S_OPENAL_PlayMP3(); +static void S_OPENAL_StopMP3(); +static void S_OPENAL_Pitch(); +static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); + +# define alDieIfError() __alDieIfError(__FILE__, __LINE__) + +static void __alDieIfError(const char *file, int line) { - // FIXME: unimplemented + ALint alErr = qalGetError(); + if (alErr) { + Com_DPrintf("OpenAL error, %s, line %i: [%s].\n", file, line, qalGetString(alErr)); + } } static void S_OPENAL_NukeSource(ALuint *srcptr) { - // FIXME: unimplemented + ALuint source; + + source = *srcptr; + if (!*srcptr) { + return; + } + + if (!qalIsSource(*srcptr)) { + return; + } + + alDieIfError(); + qalSourceStop(source); + + alDieIfError(); + qalSourcei(source, AL_BUFFER, 0); + + alDieIfError(); + qalDeleteSources(1, srcptr); + + alDieIfError(); + *srcptr = 0; } static void S_OPENAL_NukeBuffer(ALuint *bufptr) { + if (!*bufptr) { + return; + } + + if (!qalIsBuffer(*bufptr)) { + return; + } + + alDieIfError(); + qalDeleteBuffers(1, bufptr); + + alDieIfError(); + *bufptr = 0; // FIXME: unimplemented } static void S_OPENAL_NukeChannel(openal_channel *channel) { - // FIXME: unimplemented + if (!channel) { + return; + } + + S_OPENAL_NukeSource(&channel->source); + S_OPENAL_NukeBuffer(&channel->buffer); + + if (channel->bufferdata) { + delete[] channel->bufferdata; + } } static void S_OPENAL_NukeContext() { - // FIXME: unimplemented + int i; + + Com_Printf("OpenAL: Destroying channels...\n"); + + for (i = 0; i < MAX_OPENAL_CHANNELS; ++i) { + S_OPENAL_NukeChannel(openal.channel[i]); + } + + Com_Printf("OpenAL: Channels destroyed successfully.\n"); + + for (i = 0; i < s_numSfx; i++) { + S_OPENAL_NukeBuffer(&s_knownSfx[i].buffer); + } + + S_OPENAL_NukeBuffer(&openal.movieSFX.buffer); + + if (al_context_id) { + Com_Printf("OpenAL: Destroying context...\n"); + + qalcSuspendContext(al_context_id); + qalcMakeContextCurrent(NULL); + qalcDestroyContext(al_context_id); + al_context_id = NULL; + + Com_Printf("OpenAL: Context destroyed successfully.\n"); + } + + if (al_device) { + Com_Printf("OpenAL: Closing device...\n"); + + qalcCloseDevice(al_device); + al_device = NULL; + + Com_Printf("OpenAL: Device closed successfully.\n"); + } } static bool S_OPENAL_InitContext() { - // FIXME: unimplemented - return false; + const char *dev; + int attrlist[6]; + + dev = 0; + if (s_openaldevice) { + dev = s_openaldevice->string; + } + + if (dev && !*dev) { + dev = NULL; + } + + Com_Printf("OpenAL: Opening device %s...\n", dev ? dev : "{default}"); + + al_device = qalcOpenDevice(dev); + if (!al_device) { + Com_Printf("OpenAL: Could not open device\n"); + S_OPENAL_NukeContext(); + return false; + } + + Com_Printf("OpenAL: Device opened successfully.\n"); + al_frequency = 22050; + if (s_khz->integer == 11) { + al_frequency = 11025; + } else if (s_khz->integer == 44) { + al_frequency = 44100; + } + + attrlist[0] = 256; + attrlist[1] = al_frequency; + attrlist[2] = 258; + attrlist[3] = 0; + attrlist[4] = 0; + attrlist[5] = 0; + + Com_Printf("OpenAL: Creating AL context...\n"); + al_context_id = qalcCreateContext(al_device, attrlist); + if (!al_context_id) { + Com_Printf("OpenAL: Could not create context\n"); + S_OPENAL_NukeContext(); + return false; + } + + Com_Printf("OpenAL: Context created successfully.\n"); + + qalcMakeContextCurrent(al_context_id); + alDieIfError(); + + Com_Printf("AL_VENDOR: %s\n", qalGetString(AL_VENDOR)); + alDieIfError(); + + Com_Printf("AL_VERSION: %s\n", qalGetString(AL_VERSION)); + alDieIfError(); + + Com_Printf("AL_RENDERER: %s\n", qalGetString(AL_RENDERER)); + alDieIfError(); + + Com_Printf("AL_EXTENSIONS: %s\n", qalGetString(AL_EXTENSIONS)); + alDieIfError(); + + qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); + alDieIfError(); + + qalcProcessContext(al_context_id); + alDieIfError(); + + return true; } static bool S_OPENAL_InitExtensions() { - // FIXME: unimplemented - return false; + extensions_table_t extensions_table[4] = { + "alutLoadMP3_LOKI", + (void **)_alutLoadMP3_LOKI, + true, + "alReverbScale_LOKI", + (void **)_alReverbScale_LOKI, + true, + "alReverbDelay_LOKI", + (void **)_alReverbDelay_LOKI, + true + }; + extensions_table_t *i; + + for (i = extensions_table; i->funcname; ++i) { + *i->funcptr = NULL; + } + + for (i = extensions_table; i->funcname; ++i) { + Com_Printf("AL extension: Looking up %ssymbol \"%s\"...", i->required ? "required " : "", i->funcname); + + *i->funcptr = qalGetProcAddress(i->funcname); + if (!*i->funcptr) { + Com_Printf("...not found! [%s]\n", qalGetError()); + if (i->required) { + S_OPENAL_NukeContext(); + return false; + } + continue; + } + + Com_Printf("...found.\n"); + } + + qalGetError(); + return true; } static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) { - // FIXME: unimplemented - return false; + openal.channel[idx] = chan; + chan->vOrigin[2] = 0.0; + chan->vOrigin[1] = 0.0; + chan->vOrigin[0] = 0.0; + chan->fVolume = 1.0; + chan->fNewPitchMult = 0.0; + chan->fMinDist = 0.0; + chan->fMaxDist = 0.0; + chan->pSfx = 0; + chan->iEntNum = 0; + chan->iEntChannel = 0; + chan->iBaseRate = 0; + chan->iStartTime = 0; + chan->iTime = 0; + chan->iEndTime = 0; + chan->iFlags = 0; + chan->iPausedOffset = 0; + chan->source = 0; + chan->buffer = 0; + chan->bufferdata = 0; + chan->fading = FADE_NONE; + chan->fade_time = 0; + chan->fade_start_time = 0; + chan->song_number = 0; + + qalGenSources(1, &chan->source); + alDieIfError(); + qalSourcei(chan->source, 514, 1); + alDieIfError(); + + return true; } qboolean S_OPENAL_Init() { - // FIXME: unimplemented - return qfalse; + int i; + + if (al_initialized) { + Com_DPrintf("S_OPENAL_Init(): Called when sound is already initialized!\n"); + return qtrue; + } + + for (i = 0; i < MAX_OPENAL_CHANNELS; i++) { + openal.channel[i] = NULL; + } + + for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) { + openal.loop_sounds[i] = {}; + } + + s_milesdriver = Cvar_Get("s_milesdriver", "auto", CVAR_SOUND_LATCH | CVAR_ARCHIVE); + s_openaldevice = Cvar_Get("s_openaldevice", "", CVAR_SOUND_LATCH | CVAR_ARCHIVE); + s_reverb = Cvar_Get("s_reverb", "0", CVAR_SOUND_LATCH | CVAR_ARCHIVE); + s_show_cpu = Cvar_Get("s_show_cpu", "0", 0); + s_show_num_active_sounds = Cvar_Get("s_show_num_active_sounds", "0", 0); + s_show_sounds = Cvar_Get("s_show_sounds", "0", 0); + s_speaker_type = Cvar_Get("s_speaker_type", "0", CVAR_ARCHIVE); + s_obstruction_cal_time = Cvar_Get("s_obstruction_cal_time", "500", CVAR_ARCHIVE); + + if (!Cvar_Get("s_initsound", "1", 0)->integer) { + Com_Printf("OpenAL: s_initsound set to zero...disabling audio.\n"); + return true; + } + + if (!S_OPENAL_InitContext()) { + Com_Printf("OpenAL: initialization failed. No audio will play.\n"); + return false; + } + + if (!S_OPENAL_InitExtensions()) { + Com_Printf("OpenAL: A required extension is missing. No audio will play.\n"); + return false; + } + + al_use_reverb = false; + if (s_reverb->integer) { + STUB_DESC("reenable reverb support later."); + + if (al_use_reverb) { + S_OPENAL_SetReverb(s_iReverbType, s_fReverbLevel); + } else { + Com_Printf("OpenAL: No reverb support. Reverb is disabled.\n"); + } + } + + al_current_volume = s_volume->value * s_volume->value; + qalListenerf(AL_GAIN, al_current_volume); + alDieIfError(); + + for (i = 0; i < MAX_OPENAL_CHANNELS_3D; i++) { + if (!S_OPENAL_InitChannel(i, &openal.chan_3D[i])) { + return false; + } + } + + for (i = 0; i < MAX_OPENAL_CHANNELS_2D; i++) { + if (!S_OPENAL_InitChannel(i, &openal.chan_2D[i])) { + return false; + } + } + + for (i = 0; i < MAX_OPENAL_CHANNELS_2D_STREAM; i++) { + if (!S_OPENAL_InitChannel(i, &openal.chan_2D_stream[i])) { + return false; + } + } + + for (i = 0; i < MAX_OPENAL_SONGS; i++) { + if (!S_OPENAL_InitChannel(i, &openal.chan_song[i])) { + return false; + } + } + + if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_MP3_ID, &openal.chan_mp3)) { + return false; + } + + if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_mp3)) { + return false; + } + + if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_MOVIE_ID, &openal.chan_mp3)) { + return false; + } + + Cmd_AddCommand("playmp3", S_OPENAL_PlayMP3); + Cmd_AddCommand("stopmp3", S_OPENAL_StopMP3); + Cmd_AddCommand("loadsoundtrack", S_loadsoundtrack); + Cmd_AddCommand("playsong", S_PlaySong); + Cmd_AddCommand("pitch", S_OPENAL_Pitch); + Cmd_AddCommand("tmstart", S_TriggeredMusic_Start); + Cmd_AddCommand("tmstartloop", S_TriggeredMusic_StartLoop); + Cmd_AddCommand("tmstop", S_TriggeredMusic_Stop); + + S_OPENAL_ClearLoopingSounds(); + load_sfx_info(); + s_bProvidersEmunerated = true; + al_initialized = true; + + return true; } void S_OPENAL_Shutdown() { - // FIXME: unimplemented + if (!al_initialized) { + Com_DPrintf("S_OPENAL_Shutdown(): Called when sound is NOT initialized!\n"); + return; + } + + S_OPENAL_StopAllSounds(true); + + Cmd_RemoveCommand("playmp3"); + Cmd_RemoveCommand("stopmp3"); + Cmd_RemoveCommand("loadsoundtrack"); + Cmd_RemoveCommand("playsong"); + Cmd_RemoveCommand("pitch"); + Cmd_RemoveCommand("tmstart"); + Cmd_RemoveCommand("tmstartloop"); + Cmd_RemoveCommand("tmstop"); + + S_OPENAL_NukeContext(); + + s_bProvidersEmunerated = false; + al_initialized = false; } void S_FadeSound(float fTime) { - // FIXME: unimplemented + Com_Printf("Called FadeSound with: %f\n", fTime); + + if (fTime > 0) { + s_bFading = true; + s_fFadeStartTime = cls.realtime; + s_fFadeVolume = 1; + s_fFadeStopTime = cls.realtime + fTime; + } else { + s_fFadeVolume = 1; + s_bFading = false; + } } float S_GetBaseVolume() { - // FIXME: unimplemented - return 0; + return s_volume->value * s_fFadeVolume; } qboolean S_NeedFullRestart() { - // FIXME: unimplemented - return qfalse; + return Cvar_Get("s_initsound", "1", 0)->integer != s_bLastInitSound; } void S_PrintInfo() { - // FIXME: unimplemented + const char *dev; + + Com_Printf("----- Sound Info -----\n"); + + if (s_bSoundStarted) { + dev = NULL; + if (s_openaldevice) { + dev = s_openaldevice->string; + } + if (!dev || !*dev) { + dev = "{default}"; + } + Com_Printf("device - %s\n", dev); + if (al_use_reverb) { + Com_Printf("reverb - ON\n"); + } else { + Com_Printf("reverb - OFF\n"); + } + Com_Printf("samplebits - 16\n"); + Com_Printf("speed - %d\n", al_frequency); + if (s_loadas8bit->integer) { + Com_Printf("Can NOT force all sounds to 8 bit in OpenAL, I think.\n"); + } + } else { + Com_Printf("sound system not started\n"); + } + + Com_Printf("----------------------\n"); } static void S_DumpStatus(const char *pszChanName, int iChanNum, openal_channel *channel) { - // FIXME: unimplemented + sfx_t *sfx; + ALint status; + + sfx = channel->pSfx; + + qalGetSourceiv(channel->source, AL_SOURCE_STATE, &status); + alDieIfError(); + + if (status == AL_PLAYING || status == AL_PAUSED) { + const char *pszMode = status == AL_PLAYING ? "playing" : "paused"; + + if (sfx) { + if (sfx != (sfx_t *)-16 && sfx->name[0]) { + Com_Printf("%s channel %i - %s sfx %s\n", pszChanName, iChanNum, pszMode, sfx->name); + } else { + Com_Printf("%s channel %i - %s with nameless sfx\n", pszChanName, iChanNum, pszMode); + } + } else { + Com_Printf("%s channel %i - %s with NULL sfx\n", pszChanName, iChanNum, pszMode); + } + } } void S_DumpInfo() { - // FIXME: unimplemented + int i; + + for (i = 0; i < MAX_OPENAL_CHANNELS_3D; i++) { + S_DumpStatus("3D", i, openal.channel[i]); + } + + for (i = 0; i < MAX_OPENAL_CHANNELS_2D; i++) { + S_DumpStatus("2D", i, openal.channel[MAX_OPENAL_CHANNELS_3D + i]); + } + + for (i = 0; i < MAX_OPENAL_CHANNELS_2D_STREAM; i++) { + S_DumpStatus("2D stream", i, openal.channel[MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + i]); + } + + for (i = 0; i < MAX_OPENAL_MISC_CHANNELS; i++) { + S_DumpStatus( + "Misc", + i, + openal.channel[MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM + i] + ); + } } static void S_OPENAL_Pitch() { - // FIXME: unimplemented + Com_Printf("S_OPENAL_Pitch() needs to be implemented!\n"); } static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) { - // FIXME: unimplemented - return false; + char path[MAX_QPATH]; + FILE *in; + size_t len; + size_t rc; + bool failed; + + chan->stop(); + + qalSourcei(chan->source, AL_BUFFER, 0); + alDieIfError(); + + S_OPENAL_NukeBuffer(&chan->buffer); + alDieIfError(); + + Q_strncpyz(path, _path, sizeof(path)); + path[MAX_QPATH - 1] = 0; + + FS_CorrectCase(path); + + in = fopen(path, "rb"); + if (!in) { + Com_DPrintf("Failed to open MP3 \"%s\" for playback\n", path); + return false; + } + + fseek(in, 0, SEEK_END); + len = ftell(in); + fseek(in, 0, SEEK_SET); + + chan->bufferdata = new ALubyte[len]; + rc = fread(chan->bufferdata, 1, len, in); + fclose(in); + + if (rc != len) { + delete[] chan->bufferdata; + chan->bufferdata = NULL; + Com_DPrintf("Failed to read MP3 \"%s\" from disk\n", path); + + return false; + } + + qalGenBuffers(1, &chan->buffer); + alDieIfError(); + + failed = !_alutLoadMP3_LOKI(chan->buffer, chan->bufferdata, rc); + alDieIfError(); + + delete[] chan->bufferdata; + chan->bufferdata = NULL; + + if (failed) { + Com_DPrintf("Failed to decode MP3 file \"%s\"\n", path); + return false; + } + + qalSourcei(chan->source, AL_BUFFER, chan->buffer); + alDieIfError(); + + chan->set_no_3d(); + + return true; } static void S_OPENAL_PlayMP3() { - // FIXME: unimplemented + const char *path; + + if (Cmd_Argc() != 2) { + Com_Printf("playmp3 \n"); + return; + } + + path = Cmd_Argv(1); + if (!S_OPENAL_LoadMP3(path, &openal.chan_mp3)) { + Com_Printf("Failed to play mp3 - %s\n", path); + return; + } + + openal.chan_mp3.play(); + Com_Printf("Playing mp3 - %s\n", path); } static void S_OPENAL_StopMP3() { - // FIXME: unimplemented + S_OPENAL_NukeChannel(&openal.chan_mp3); } void MUSIC_Pause() { - // FIXME: unimplemented + int i; + + for (i = 0; i < MAX_OPENAL_SONGS; i++) { + openal.chan_song[i].pause(); + } } void MUSIC_Unpause() { - // FIXME: unimplemented + int i; + + for (i = 0; i < MAX_OPENAL_SONGS; i++) { + if (openal.chan_song[i].is_paused()) { + openal.chan_song[i].play(); + } + } } void S_PauseSound() { - // FIXME: unimplemented + int i; + + if (!s_bSoundStarted) { + return; + } + + s_bSoundPaused = true; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + openal_channel *pChannel = openal.channel[i]; + if (!pChannel) { + continue; + } + + if (pChannel->iEntChannel == CHAN_MENU) { + continue; + } + + if (!pChannel->is_playing()) { + continue; + } + + pChannel->pause(); + } + + if (openal.chan_mp3.is_playing()) { + openal.chan_mp3.pause(); + } + + MUSIC_Pause(); + S_TriggeredMusic_Pause(); } void S_UnpauseSound() { - // FIXME: unimplemented + int i; + + if (!s_bSoundStarted) { + return; + } + + s_bSoundPaused = true; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + openal_channel *pChannel = openal.channel[i]; + if (!pChannel) { + continue; + } + + if (!pChannel->is_paused()) { + continue; + } + + pChannel->play(); + } + + if (openal.chan_mp3.is_paused()) { + openal.chan_mp3.play(); + } + + MUSIC_Unpause(); + S_TriggeredMusic_Unpause(); + + s_bSoundPaused = false; } static qboolean S_OPENAL_ShouldPlay(sfx_t *pSfx) { - // FIXME: unimplemented - return qfalse; + if (sfx_infos[pSfx->sfx_info_index].max_number_playing <= 0) { + return qtrue; + } + + int iRemainingTimesToPlay; + int i; + + iRemainingTimesToPlay = sfx_infos[pSfx->sfx_info_index].max_number_playing; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + openal_channel *pChannel = openal.channel[i]; + if (!pChannel) { + continue; + } + + if (pChannel->pSfx == pSfx && pChannel->is_playing()) { + iRemainingTimesToPlay--; + if (!iRemainingTimesToPlay) { + return qfalse; + } + } + } + + return qtrue; } static qboolean S_OPENAL_ShouldStart(const vec3_t vOrigin, float fMinDist, float fMaxDist) { - // FIXME: unimplemented - return qfalse; + vec3_t vDir; + vec3_t vListenerOrigin; + vec3_t alvec; + + if (!al_initialized) { + return false; + } + + qalGetListenerfv(AL_POSITION, alvec); + + VectorScale(alvec, 52.49f, vListenerOrigin); + VectorSubtract(vOrigin, vListenerOrigin, vDir); + + return Square(fMaxDist) > VectorLengthSquared(vDir); } static int S_OPENAL_PickChannelBase(int iEntNum, int iEntChannel, int iFirstChannel, int iLastChannel) { - // FIXME: unimplemented - return 0; + int i; + int iBestChannel; + openal_channel *pChannel; + + iBestChannel = -1; + if (iEntNum != ENTITYNUM_NONE && iEntChannel) { + bool bStoppedChannel = false; + + for (i = iFirstChannel; i <= iLastChannel; i++) { + pChannel = openal.channel[i]; + if (!pChannel) { + continue; + } + + if (pChannel->is_free()) { + iBestChannel = i; + continue; + } + + if (pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) { + pChannel->end_sample(); + bStoppedChannel = 1; + iBestChannel = i; + break; + } + } + + if (!bStoppedChannel) { + for (i = 0; i < iFirstChannel; ++i) { + pChannel = openal.channel[i]; + if (!pChannel || pChannel->is_free()) { + continue; + } + + if (pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) { + bStoppedChannel = 1; + break; + } + } + + if (!bStoppedChannel) { + i = iLastChannel; + while (++i <= 95) { + pChannel = openal.channel[i]; + if (!pChannel || pChannel->is_free()) { + continue; + } + + if (pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) { + break; + } + } + } + } + } + + if (iBestChannel < 0) { + int iBestTime = 0x7FFFFFFF; + + for (i = iFirstChannel; i <= iLastChannel; i++) { + pChannel = openal.channel[i]; + if (!pChannel) { + continue; + } + + if (pChannel->is_free()) { + return i; + } + + if (pChannel->iEntNum == s_iListenerNumber && iEntNum != pChannel->iEntNum) { + continue; + } + + if (pChannel->iEntChannel < iEntChannel + || (pChannel->iEntChannel == iEntChannel && pChannel->iStartTime < iBestTime)) { + iBestChannel = i; + iEntChannel = pChannel->iEntChannel; + iBestTime = pChannel->iStartTime; + } + } + } + + return iBestChannel; } static int S_OPENAL_PickChannel3D(int iEntNum, int iEntChannel) { - // FIXME: unimplemented - return 0; + return S_OPENAL_PickChannelBase(iEntNum, iEntChannel, 0, MAX_OPENAL_CHANNELS_3D - 1); } static int S_OPENAL_PickChannel2D(int iEntNum, int iEntChannel) { - // FIXME: unimplemented - return 0; + return S_OPENAL_PickChannelBase( + iEntNum, iEntChannel, MAX_OPENAL_CHANNELS_3D, MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D - 1 + ); } static int S_OPENAL_PickChannel2DStreamed(int iEntNum, int iEntChannel) { - // FIXME: unimplemented - return 0; + return S_OPENAL_PickChannelBase( + iEntNum, + iEntChannel, + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D, + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM - 1 + ); } void callbackServer(int entnum, int channel_number, const char *name) { - // FIXME: unimplemented + if (!com_sv_running->integer) { + return; + } + + SV_SoundCallback(entnum, channel_number, name); } static void S_OPENAL_Start2DSound( @@ -269,7 +949,129 @@ static void S_OPENAL_Start2DSound( float fMaxDistance ) { - // FIXME: unimplemented + int iRealEntNum; + int iFreeChannel; + openal_channel *pChannel; + float fRealVolume; + bool bSupportWaitTillSoundDone; + + iRealEntNum = iEntNum & ~S_FLAG_DO_CALLBACK; + + if (pSfx->iFlags & SFX_FLAG_NO_DATA) { + iFreeChannel = S_OPENAL_PickChannel2DStreamed(iRealEntNum, iEntChannel); + } else { + iFreeChannel = S_OPENAL_PickChannel2D(iRealEntNum, iEntChannel); + } + + if (iFreeChannel < 0) { + Com_DPrintf( + "Couldn't play %s sound '%s' for entity %i on channel %s\n", + (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "2Dstreamed" : "2D", + pSfx->name, + iEntNum & ~S_FLAG_DO_CALLBACK, + S_ChannelNumToName(iEntChannel) + ); + return; + } + + if (iEntNum & S_FLAG_DO_CALLBACK) { + callbackServer(iEntNum, iFreeChannel, pSfx->name); + } + + pChannel = openal.channel[iFreeChannel]; + pChannel->force_free(); + + if (fVolume < 0) { + fVolume = 1; + } + + fRealVolume = S_GetBaseVolume() * fVolume; + pChannel->fVolume = fVolume; + + if (pChannel->iEntChannel == CHAN_LOCAL) { + pChannel->iFlags |= CHANNEL_FLAG_LOCAL_LISTENER; + } else { + pChannel->iFlags &= ~CHANNEL_FLAG_LOCAL_LISTENER; + } + pChannel->iFlags &= ~CHANNEL_FLAG_PAUSED; + + if (fMinDistance < 0.0) { + fMinDistance = 200.0; + } + pChannel->fMinDist = fMinDistance; + + if (fMaxDistance < 0.0) { + fMaxDistance = pChannel->fMinDist * 64; + } + pChannel->fMaxDist = fMaxDistance; + + pChannel->fNewPitchMult = fPitch; + pChannel->pSfx = pSfx; + pChannel->iEntNum = iRealEntNum; + pChannel->iEntChannel = iEntChannel; + if (iEntNum == ENTITYNUM_NONE) { + VectorClear(pChannel->vOrigin); + pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; + pChannel->iEntNum = 0; + + if (vOrigin) { + pChannel->vOrigin[0] = -vOrigin[0]; + pChannel->vOrigin[1] = vOrigin[2]; + pChannel->vOrigin[2] = -vOrigin[1]; + } + } else { + pChannel->iFlags &= ~CHANNEL_FLAG_NO_ENTITY; + pChannel->iEntNum = iRealEntNum; + if (vOrigin) { + pChannel->vOrigin[0] = -vOrigin[0]; + pChannel->vOrigin[1] = vOrigin[2]; + pChannel->vOrigin[2] = -vOrigin[1]; + + bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; + pChannel->iTime = cl.serverTime - 1; + if (bSupportWaitTillSoundDone) { + pChannel->iTime = 0; + } + } else { + VectorClear(pChannel->vOrigin); + pChannel->iTime = 0; + } + } + + pChannel->iStartTime = cl.serverTime; + pChannel->iEndTime = (int)(cl.serverTime + pSfx->time_length + 250.f); + + if (iFreeChannel > MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D) { + // streamed + if (!pChannel->set_sfx(pSfx)) { + Com_DPrintf("Set stream error - %s\n", pSfx->name); + return; + } + + pChannel->iBaseRate = pChannel->sample_playback_rate(); + pChannel->set_no_3d(); + fRealVolume = fRealVolume * 84.f; + pChannel->set_gain(fRealVolume); + pChannel->play(); + } else { + pChannel->stop(); + pChannel->set_no_3d(); + pChannel->set_sfx(pSfx); + pChannel->set_gain(fRealVolume); + pChannel->play(); + } + + if (s_show_sounds->integer > 0) { + Com_DPrintf( + "2D - %d (#%i) - %s (vol %f, mindist %f, maxdist %f)\n", + cl.serverTime, + iFreeChannel, + pSfx->name, + fVolume, + fMinDistance, + fMaxDistance + ); + } } void S_OPENAL_StartSound( @@ -284,7 +1086,147 @@ void S_OPENAL_StartSound( qboolean bStreamed ) { - // FIXME: unimplemented + int iChannel; + openal_channel* pChannel; + sfx_info_t* pSfxInfo; + sfx_t* pSfx; + ALint state; + bool bOnlyUpdate; + bool bSupportWaitTillSoundDone; + + bOnlyUpdate = false; + pSfx = &s_knownSfx[sfxHandle]; + if (bStreamed) { + pSfx->iFlags |= SFX_FLAG_NO_DATA; + } + + if (!S_OPENAL_ShouldPlay(pSfx)) + { + Com_DPrintf("^~^~^ Not playing sound '%s'\n", pSfx->name); + return; + } + + if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) + { + S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist); + return; + } + + bSupportWaitTillSoundDone = (iEntNum & S_FLAG_DO_CALLBACK) != 0; + iEntNum &= ~S_FLAG_DO_CALLBACK; + + pSfxInfo = &sfx_infos[pSfx->sfx_info_index]; + if (pSfx->iFlags & SFX_FLAG_NO_DATA) { + Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name); + return; + } + + iChannel = S_OPENAL_PickChannel3D(iEntNum, iEntChannel); + if (iChannel < 0) + { + Com_DPrintf("Couldn't play %s sound '%s' for entity %i on channel %s\n", (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "3Dstreamed" : "3D", pSfx->name, iEntNum, S_ChannelNumToName(iEntChannel)); + return; + } + + if (bSupportWaitTillSoundDone) { + callbackServer(iEntNum, iChannel, pSfx->name); + } + + pChannel = &openal.chan_3D[iChannel]; + pChannel->fNewPitchMult = fPitch; + pChannel->iEntChannel = iEntChannel; + pChannel->iFlags &= ~(CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER); + state = pChannel->get_state(); + + if (pChannel->iEntNum == iEntNum && (state == AL_PLAYING || state == AL_PAUSED) && pChannel->pSfx == pSfx) { + bOnlyUpdate = true; + } else { + pChannel->stop(); + pChannel->iFlags &= ~(CHANNEL_FLAG_LOOPING | CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER); + if (!pChannel->set_sfx(pSfx)) { + Com_DPrintf("Set sample error - %s\n", pSfx->name); + return; + } + } + + if (fMinDist < 0.0) + { + fMinDist = 200.0; + fMaxDist = 12800.0; + } + pChannel->fMinDist = fMinDist; + pChannel->fMaxDist = fMaxDist; + + if (fVolume < 0.0) { + fVolume = 1.0; + } + + pChannel->fVolume = S_GetBaseVolume() * fVolume; + pChannel->set_gain(pChannel->fVolume); + + if (s_show_sounds->integer > 0) { + Com_DPrintf( + "%d (#%i) - %s (vol %f, mindist %f, maxdist %f)\n", + cl.serverTime, + iChannel, + pSfx->name, + pChannel->fVolume, + fMinDist, + fMaxDist); + } + + pChannel->set_velocity(0, 0, 0); + if (iEntNum == ENTITYNUM_NONE) { + if (vOrigin) { + pChannel->vOrigin[0] = -vOrigin[0]; + pChannel->vOrigin[1] = vOrigin[2]; + pChannel->vOrigin[2] = -vOrigin[1]; + } else { + //VectorClear(vOrigin); + // Fixed in OPM + // Tiny mistake found in original where the vOrigin parameter is set to 0 + VectorClear(pChannel->vOrigin); + } + + pChannel->set_position(pChannel->vOrigin[0] / 52.49f, pChannel->vOrigin[1] / 52.49f, pChannel->vOrigin[2] / 52.49f); + pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; + pChannel->iEntNum = 0; + } else { + pChannel->iEntNum = iEntNum; + if (vOrigin) { + pChannel->vOrigin[0] = -*vOrigin; + pChannel->vOrigin[1] = vOrigin[2]; + pChannel->vOrigin[2] = -vOrigin[1]; + bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; + pChannel->iTime = cl.serverTime - 1; + if (bSupportWaitTillSoundDone) { + pChannel->iTime = 0; + } + } else { + VectorClear(pChannel->vOrigin); + pChannel->iTime = 0; + } + } + + if (pSfxInfo->loop_start != -1) { + pChannel->set_sample_loop_block(pSfxInfo->loop_start, pSfxInfo->loop_end); + pChannel->set_sample_loop_count(0); + + pChannel->iFlags |= CHANNEL_FLAG_LOOPING; + if (s_show_sounds->integer) { + Com_DPrintf("loopblock - %d to %d\n", pSfxInfo->loop_start, pSfxInfo->loop_end); + } + } else { + pChannel->set_sample_loop_count(1); + } + + if (!bOnlyUpdate && S_OPENAL_ShouldStart(pChannel->vOrigin, pChannel->fMinDist, pChannel->fMaxDist)) + { + pChannel->play(); + pChannel->iEndTime = cl.serverTime + (int)pChannel->pSfx->time_length + 250; + pChannel->iBaseRate = pChannel->sample_playback_rate(); + pChannel->iStartTime = cl.serverTime; + } } void S_OPENAL_AddLoopingSound( @@ -298,31 +1240,166 @@ void S_OPENAL_AddLoopingSound( int iFlags ) { - // FIXME: unimplemented + int i; + int iFreeLoopSound; + sfx_t* pSfx; + openal_loop_sound_t* pLoopSound; + + iFreeLoopSound = -1; + pSfx = &s_knownSfx[sfxHandle]; + if (!pSfx) { + return; + } + + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + pLoopSound = &openal.loop_sounds[i]; + if (pLoopSound->pSfx == pSfx && !pLoopSound->bInUse) { + iFreeLoopSound = i; + break; + } + + } + + if (iFreeLoopSound < 0) { + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + pLoopSound = &openal.loop_sounds[i]; + if (!pLoopSound->pSfx && !pLoopSound->bInUse) { + iFreeLoopSound = i; + pLoopSound->bPlaying = false; + break; + } + } + } + + if (iFreeLoopSound < 0) { + if (cls.realtime >= s_iNextLoopingWarning) { + Com_DPrintf("Too many looping sounds\n"); + s_iNextLoopingWarning = cls.realtime + 1000; + } + return; + } + + pLoopSound = &openal.loop_sounds[iFreeLoopSound]; + pLoopSound->vOrigin[0] = -vOrigin[0]; + pLoopSound->vOrigin[1] = vOrigin[2]; + pLoopSound->vOrigin[2] = -vOrigin[1]; + pLoopSound->vVelocity[0] = -vVelocity[0] / 52.49f / 500.f; + pLoopSound->vVelocity[1] = vVelocity[2] / 52.49f / 500.f; + pLoopSound->vVelocity[2] = -vVelocity[1] / 52.49f / 500.f; + pLoopSound->pSfx = pSfx; + pLoopSound->bInUse = true; + pLoopSound->iStartTime = cls.realtime; + pLoopSound->fBaseVolume = fVolume; + pLoopSound->fMinDist = fMinDist; + pLoopSound->fMaxDist = fMaxDist; + pLoopSound->fPitch = fPitch; + pLoopSound->iFlags = iFlags; + pLoopSound->bCombine = VectorCompare(vVelocity, vec_zero) == 0; + + if (pLoopSound->bCombine) { + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + if (openal.loop_sounds[i].pSfx == pSfx && openal.loop_sounds[i].bInUse) { + pLoopSound->iStartTime = openal.loop_sounds[i].iStartTime; + if (openal.loop_sounds[i].bPlaying) { + pLoopSound->bPlaying = true; + pLoopSound->iChannel = openal.loop_sounds[i].iChannel; + } + } + } + } } void S_OPENAL_StopLoopingSound(openal_loop_sound_t *pLoopSound) { - // FIXME: unimplemented + bool bMayStop; + int i; + openal_channel* pChannel; + + if (!pLoopSound->bPlaying) { + return; + } + bMayStop = true; + + if (pLoopSound->bCombine) { + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + if (openal.loop_sounds[i].pSfx == pLoopSound->pSfx && openal.loop_sounds[i].bInUse) { + bMayStop = false; + break; + } + } + } + + if (bMayStop) { + if (s_show_sounds->integer > 0) { + Com_DPrintf("%d (#%i) - stopped loop - %s\n", cl.serverTime, pLoopSound->iChannel, openal.channel[pLoopSound->iChannel]->pSfx->name); + } + openal.channel[pLoopSound->iChannel]->force_free(); + } + pLoopSound->pSfx = NULL; + pLoopSound->bPlaying = false; + + if (pLoopSound->bCombine) { + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + if (openal.loop_sounds[i].pSfx == pLoopSound->pSfx) + { + openal.loop_sounds[i].bPlaying = false; + openal.loop_sounds[i].pSfx = NULL; + } + } + } } void S_OPENAL_ClearLoopingSounds() { - // FIXME: unimplemented + int i; + + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + openal.loop_sounds[i].bInUse = false; + } } void S_OPENAL_StopLoopingSounds() { - // FIXME: unimplemented + int i; + + for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { + openal.loop_sounds[i].bInUse = false; + S_OPENAL_StopLoopingSound(&openal.loop_sounds[i]); + } } void S_OPENAL_StopSound(int iEntNum, int iEntChannel) { - // FIXME: unimplemented + int i; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + openal_channel* pChannel = openal.channel[i]; + if (!pChannel->is_free() && pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) { + pChannel->end_sample(); + break; + } + } } void S_OPENAL_StopAllSounds(qboolean bStopMusic) { + int i; + + if (!s_bSoundStarted) { + return; + } + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + openal_channel* pChannel = openal.channel[i]; + if (pChannel) { + pChannel->force_free(); + } + } + + if (bStopMusic) { + MUSIC_FreeAllSongs(); + S_TriggeredMusic_Stop(); + } // FIXME: unimplemented } @@ -330,8 +1407,60 @@ static int S_OPENAL_Start2DLoopSound( openal_loop_sound_t *pLoopSound, float fVolume, float fVolumeToPlay, float fMinDistance, const vec3_t vLoopOrigin ) { - // FIXME: unimplemented - return 0; + int iChannel; + int iSoundOFfset; + openal_channel* pChannel; + + if (pLoopSound->pSfx->iFlags & SFX_FLAG_NO_DATA) { + iChannel = S_OPENAL_PickChannel2DStreamed(0, 0); + } + else { + iChannel = S_OPENAL_PickChannel2D(0, 0); + } + + if (iChannel < 0) { + Com_DPrintf("Could not find a free 2D sound channel\n"); + return iChannel; + } + + pChannel = openal.channel[iChannel]; + pChannel->force_free(); + pChannel->fVolume = fVolume; + + if (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN) { + pChannel->iFlags |= CHANNEL_FLAG_LOCAL_LISTENER; + } else { + pChannel->iFlags &= ~CHANNEL_FLAG_LOCAL_LISTENER; + } + pChannel->fMinDist = fMinDistance; + + if (!pChannel->set_sfx(pLoopSound->pSfx)) { + Com_DPrintf("Set sample error\n"); + pChannel->iFlags &= ~CHANNEL_FLAG_PLAYABLE; + return -1; + } + + pChannel->iEntNum = 0; + pChannel->iEntChannel = 0; + pChannel->pSfx = pLoopSound->pSfx; + pChannel->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; + pChannel->iBaseRate = pChannel->sample_playback_rate(); + VectorCopy(vLoopOrigin, pChannel->vOrigin); + pChannel->set_sample_offset((int)(pLoopSound->pSfx->info.width + * pLoopSound->pSfx->info.rate + * (float)(cls.realtime - pLoopSound->iStartTime) + / 1000.0) + % pLoopSound->pSfx->length); + + pChannel->set_sample_loop_count(0); + pChannel->fVolume = fVolumeToPlay; + pChannel->set_gain(fVolumeToPlay); + pChannel->start_sample(); + if (s_show_sounds->integer > 0) { + Com_DPrintf("%d (#%i) - %s (vol %f)\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name, fVolume); + } + + return iChannel; } static int S_OPENAL_Start3DLoopSound( @@ -343,8 +1472,53 @@ static int S_OPENAL_Start3DLoopSound( const vec3_t vListenerOrigin ) { - // FIXME: unimplemented - return 0; + int iChannel; + vec3_t vDir; + int iSoundOffset; + openal_channel* pChan3D; + + if (pLoopSound->pSfx->iFlags & SFX_FLAG_NO_DATA) { + return -1; + } + + iChannel = S_OPENAL_PickChannel3D(0, 0); + if (iChannel < 0) + { + Com_DPrintf("Could not find a free channel\n"); + return iChannel; + } + + pChan3D = &openal.chan_3D[iChannel]; + pChan3D->force_free(); + pChan3D->iEntNum = 0; + pChan3D->iEntChannel = 0; + pChan3D->set_3d(); + + if (!pChan3D->set_sfx(pLoopSound->pSfx)) { + Com_DPrintf("Set sample error - %s\n", pLoopSound->pSfx->name); + return -1; + } + + pChan3D->set_position(vLoopOrigin[0] / 52.49f, pLoopSound->vVelocity[1] / 52.49f, vLoopOrigin[2] / 52.49f); + pChan3D->set_velocity(pLoopSound->vVelocity[0] / 52.49f, vLoopOrigin[1] / 52.49f, pLoopSound->vVelocity[2] / 52.49f); + pChan3D->pSfx = pLoopSound->pSfx; + pChan3D->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; + pChan3D->iBaseRate = pChan3D->sample_playback_rate(); + + iSoundOffset = (int)((int)pLoopSound->pSfx->info.width + * pLoopSound->pSfx->info.rate + * (float)(cls.realtime - pLoopSound->iStartTime) + / 1000.0) + % pLoopSound->pSfx->length; + pChan3D->set_sample_offset(iSoundOffset); + pChan3D->set_sample_loop_count(0); + pChan3D->fVolume = fVolumeToPlay; + pChan3D->set_gain(fVolumeToPlay); + pChan3D->play(); + + S_OPENAL_reverb(iChannel, s_iReverbType, s_fReverbLevel); + + return iChannel; } static bool S_OPENAL_UpdateLoopSound( From 9b35e13923075ba198fe705a42df9888452df055 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 15 Jan 2024 23:04:01 +0100 Subject: [PATCH 0021/2040] Added qalGetSourceiv / qalGetBufferfv --- code/client/qal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/client/qal.c b/code/client/qal.c index 5cc40de2..4e33a292 100644 --- a/code/client/qal.c +++ b/code/client/qal.c @@ -66,6 +66,7 @@ LPALGETSOURCEF qalGetSourcef; LPALGETSOURCE3F qalGetSource3f; LPALGETSOURCEFV qalGetSourcefv; LPALGETSOURCEI qalGetSourcei; +LPALGETSOURCEIV qalGetSourceiv; LPALSOURCEPLAYV qalSourcePlayv; LPALSOURCESTOPV qalSourceStopv; LPALSOURCEREWINDV qalSourceRewindv; @@ -81,6 +82,7 @@ LPALDELETEBUFFERS qalDeleteBuffers; LPALISBUFFER qalIsBuffer; LPALBUFFERDATA qalBufferData; LPALGETBUFFERF qalGetBufferf; +LPALGETBUFFERFV qalGetBufferfv; LPALGETBUFFERI qalGetBufferi; LPALDOPPLERFACTOR qalDopplerFactor; LPALSPEEDOFSOUND qalSpeedOfSound; @@ -184,6 +186,7 @@ qboolean QAL_Init(const char *libname) qalGetSource3f = GPA("alGetSource3f"); qalGetSourcefv = GPA("alGetSourcefv"); qalGetSourcei = GPA("alGetSourcei"); + qalGetSourceiv = GPA("alGetSourceiv"); qalSourcePlayv = GPA("alSourcePlayv"); qalSourceStopv = GPA("alSourceStopv"); qalSourceRewindv = GPA("alSourceRewindv"); @@ -199,6 +202,7 @@ qboolean QAL_Init(const char *libname) qalIsBuffer = GPA("alIsBuffer"); qalBufferData = GPA("alBufferData"); qalGetBufferf = GPA("alGetBufferf"); + qalGetBufferfv = GPA("alGetBufferfv"); qalGetBufferi = GPA("alGetBufferi"); qalDopplerFactor = GPA("alDopplerFactor"); qalSpeedOfSound = GPA("alSpeedOfSound"); @@ -283,6 +287,7 @@ void QAL_Shutdown( void ) qalGetSource3f = NULL; qalGetSourcefv = NULL; qalGetSourcei = NULL; + qalGetSourceiv = NULL; qalSourcePlayv = NULL; qalSourceStopv = NULL; qalSourceRewindv = NULL; @@ -298,6 +303,7 @@ void QAL_Shutdown( void ) qalIsBuffer = NULL; qalBufferData = NULL; qalGetBufferf = NULL; + qalGetBufferfv = NULL; qalGetBufferi = NULL; qalDopplerFactor = NULL; qalSpeedOfSound = NULL; From d88870bc0405c71055cd139622405450f1397784 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 15 Jan 2024 23:04:13 +0100 Subject: [PATCH 0022/2040] Added more exports --- code/client/snd_local_new.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 26e7eb24..8fcd7e6a 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -32,6 +32,9 @@ extern "C" { extern cvar_t *s_volume; extern cvar_t *s_khz; extern cvar_t *s_loadas8bit; +extern cvar_t *s_separation; +extern cvar_t *s_musicVolume; +extern cvar_t *s_ambientVolume; typedef struct { int format; @@ -162,10 +165,12 @@ extern qboolean s_bSoundStarted; extern qboolean s_bSoundPaused; extern qboolean s_bTryUnpause; extern int s_iListenerNumber; +extern float s_fAmbientVolume; extern int number_of_sfx_infos; extern sfx_info_t sfx_infos[]; extern sfx_t s_knownSfx[]; extern int s_numSfx; +extern s_entity_t s_entity[]; // The current sound driver. // Currently OPENAL From 970d72cf0781f84930ca4f438ff06d43dfffdbc7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 15 Jan 2024 23:04:25 +0100 Subject: [PATCH 0023/2040] Implemented snd_openal_new.cpp --- code/client/snd_openal_new.cpp | 2329 +++++++++++++++++++++++++++++--- 1 file changed, 2139 insertions(+), 190 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 25aa813f..e86fa40a 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -97,10 +97,17 @@ static char current_soundtrack[128]; static void S_OPENAL_PlayMP3(); static void S_OPENAL_StopMP3(); static void S_OPENAL_Pitch(); +static int +S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin); static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); # define alDieIfError() __alDieIfError(__FILE__, __LINE__) +/* +============== +__alDieIfError +============== +*/ static void __alDieIfError(const char *file, int line) { ALint alErr = qalGetError(); @@ -109,6 +116,11 @@ static void __alDieIfError(const char *file, int line) } } +/* +============== +S_OPENAL_NukeSource +============== +*/ static void S_OPENAL_NukeSource(ALuint *srcptr) { ALuint source; @@ -135,6 +147,11 @@ static void S_OPENAL_NukeSource(ALuint *srcptr) *srcptr = 0; } +/* +============== +S_OPENAL_NukeBuffer +============== +*/ static void S_OPENAL_NukeBuffer(ALuint *bufptr) { if (!*bufptr) { @@ -150,9 +167,13 @@ static void S_OPENAL_NukeBuffer(ALuint *bufptr) alDieIfError(); *bufptr = 0; - // FIXME: unimplemented } +/* +============== +S_OPENAL_NukeChannel +============== +*/ static void S_OPENAL_NukeChannel(openal_channel *channel) { if (!channel) { @@ -167,6 +188,11 @@ static void S_OPENAL_NukeChannel(openal_channel *channel) } } +/* +============== +S_OPENAL_NukeContext +============== +*/ static void S_OPENAL_NukeContext() { int i; @@ -206,6 +232,11 @@ static void S_OPENAL_NukeContext() } } +/* +============== +S_OPENAL_InitContext +============== +*/ static bool S_OPENAL_InitContext() { const char *dev; @@ -278,6 +309,11 @@ static bool S_OPENAL_InitContext() return true; } +/* +============== +S_OPENAL_InitExtensions +============== +*/ static bool S_OPENAL_InitExtensions() { extensions_table_t extensions_table[4] = { @@ -317,6 +353,11 @@ static bool S_OPENAL_InitExtensions() return true; } +/* +============== +S_OPENAL_InitChannel +============== +*/ static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) { openal.channel[idx] = chan; @@ -352,6 +393,11 @@ static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) return true; } +/* +============== +S_OPENAL_Init +============== +*/ qboolean S_OPENAL_Init() { int i; @@ -461,6 +507,11 @@ qboolean S_OPENAL_Init() return true; } +/* +============== +S_OPENAL_Shutdown +============== +*/ void S_OPENAL_Shutdown() { if (!al_initialized) { @@ -485,6 +536,11 @@ void S_OPENAL_Shutdown() al_initialized = false; } +/* +============== +S_FadeSound +============== +*/ void S_FadeSound(float fTime) { Com_Printf("Called FadeSound with: %f\n", fTime); @@ -500,16 +556,31 @@ void S_FadeSound(float fTime) } } +/* +============== +S_GetBaseVolume +============== +*/ float S_GetBaseVolume() { return s_volume->value * s_fFadeVolume; } +/* +============== +S_NeedFullRestart +============== +*/ qboolean S_NeedFullRestart() { return Cvar_Get("s_initsound", "1", 0)->integer != s_bLastInitSound; } +/* +============== +S_PrintInfo +============== +*/ void S_PrintInfo() { const char *dev; @@ -542,6 +613,11 @@ void S_PrintInfo() Com_Printf("----------------------\n"); } +/* +============== +S_DumpStatus +============== +*/ static void S_DumpStatus(const char *pszChanName, int iChanNum, openal_channel *channel) { sfx_t *sfx; @@ -567,6 +643,11 @@ static void S_DumpStatus(const char *pszChanName, int iChanNum, openal_channel * } } +/* +============== +S_DumpInfo +============== +*/ void S_DumpInfo() { int i; @@ -592,11 +673,21 @@ void S_DumpInfo() } } +/* +============== +S_OPENAL_Pitch +============== +*/ static void S_OPENAL_Pitch() { Com_Printf("S_OPENAL_Pitch() needs to be implemented!\n"); } +/* +============== +S_OPENAL_LoadMP3 +============== +*/ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) { char path[MAX_QPATH]; @@ -662,6 +753,11 @@ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) return true; } +/* +============== +S_OPENAL_PlayMP3 +============== +*/ static void S_OPENAL_PlayMP3() { const char *path; @@ -681,11 +777,21 @@ static void S_OPENAL_PlayMP3() Com_Printf("Playing mp3 - %s\n", path); } +/* +============== +S_OPENAL_StopMP3 +============== +*/ static void S_OPENAL_StopMP3() { S_OPENAL_NukeChannel(&openal.chan_mp3); } +/* +============== +MUSIC_Pause +============== +*/ void MUSIC_Pause() { int i; @@ -695,6 +801,11 @@ void MUSIC_Pause() } } +/* +============== +MUSIC_Unpause +============== +*/ void MUSIC_Unpause() { int i; @@ -706,6 +817,11 @@ void MUSIC_Unpause() } } +/* +============== +S_PauseSound +============== +*/ void S_PauseSound() { int i; @@ -741,6 +857,11 @@ void S_PauseSound() S_TriggeredMusic_Pause(); } +/* +============== +S_UnpauseSound +============== +*/ void S_UnpauseSound() { int i; @@ -774,6 +895,11 @@ void S_UnpauseSound() s_bSoundPaused = false; } +/* +============== +S_OPENAL_ShouldPlay +============== +*/ static qboolean S_OPENAL_ShouldPlay(sfx_t *pSfx) { if (sfx_infos[pSfx->sfx_info_index].max_number_playing <= 0) { @@ -802,6 +928,11 @@ static qboolean S_OPENAL_ShouldPlay(sfx_t *pSfx) return qtrue; } +/* +============== +S_OPENAL_ShouldStart +============== +*/ static qboolean S_OPENAL_ShouldStart(const vec3_t vOrigin, float fMinDist, float fMaxDist) { vec3_t vDir; @@ -820,6 +951,11 @@ static qboolean S_OPENAL_ShouldStart(const vec3_t vOrigin, float fMinDist, float return Square(fMaxDist) > VectorLengthSquared(vDir); } +/* +============== +S_OPENAL_PickChannelBase +============== +*/ static int S_OPENAL_PickChannelBase(int iEntNum, int iEntChannel, int iFirstChannel, int iLastChannel) { int i; @@ -907,11 +1043,21 @@ static int S_OPENAL_PickChannelBase(int iEntNum, int iEntChannel, int iFirstChan return iBestChannel; } +/* +============== +S_OPENAL_PickChannel3D +============== +*/ static int S_OPENAL_PickChannel3D(int iEntNum, int iEntChannel) { return S_OPENAL_PickChannelBase(iEntNum, iEntChannel, 0, MAX_OPENAL_CHANNELS_3D - 1); } +/* +============== +S_OPENAL_PickChannel2D +============== +*/ static int S_OPENAL_PickChannel2D(int iEntNum, int iEntChannel) { return S_OPENAL_PickChannelBase( @@ -919,6 +1065,11 @@ static int S_OPENAL_PickChannel2D(int iEntNum, int iEntChannel) ); } +/* +============== +S_OPENAL_PickChannel2DStreamed +============== +*/ static int S_OPENAL_PickChannel2DStreamed(int iEntNum, int iEntChannel) { return S_OPENAL_PickChannelBase( @@ -929,6 +1080,11 @@ static int S_OPENAL_PickChannel2DStreamed(int iEntNum, int iEntChannel) ); } +/* +============== +callbackServer +============== +*/ void callbackServer(int entnum, int channel_number, const char *name) { if (!com_sv_running->integer) { @@ -938,6 +1094,11 @@ void callbackServer(int entnum, int channel_number, const char *name) SV_SoundCallback(entnum, channel_number, name); } +/* +============== +S_OPENAL_Start2DSound +============== +*/ static void S_OPENAL_Start2DSound( const vec3_t vOrigin, int iEntNum, @@ -1028,7 +1189,7 @@ static void S_OPENAL_Start2DSound( pChannel->vOrigin[2] = -vOrigin[1]; bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; - pChannel->iTime = cl.serverTime - 1; + pChannel->iTime = cl.serverTime - 1; if (bSupportWaitTillSoundDone) { pChannel->iTime = 0; } @@ -1074,6 +1235,11 @@ static void S_OPENAL_Start2DSound( } } +/* +============== +S_OPENAL_StartSound +============== +*/ void S_OPENAL_StartSound( const vec3_t vOrigin, int iEntNum, @@ -1086,28 +1252,27 @@ void S_OPENAL_StartSound( qboolean bStreamed ) { - int iChannel; - openal_channel* pChannel; - sfx_info_t* pSfxInfo; - sfx_t* pSfx; - ALint state; - bool bOnlyUpdate; - bool bSupportWaitTillSoundDone; + int iChannel; + openal_channel *pChannel; + sfx_info_t *pSfxInfo; + sfx_t *pSfx; + ALint state; + bool bOnlyUpdate; + bool bSupportWaitTillSoundDone; bOnlyUpdate = false; - pSfx = &s_knownSfx[sfxHandle]; + pSfx = &s_knownSfx[sfxHandle]; if (bStreamed) { pSfx->iFlags |= SFX_FLAG_NO_DATA; } - if (!S_OPENAL_ShouldPlay(pSfx)) - { + if (!S_OPENAL_ShouldPlay(pSfx)) { Com_DPrintf("^~^~^ Not playing sound '%s'\n", pSfx->name); return; } - if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) - { + if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU + || iEntChannel == CHAN_LOCAL) { S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist); return; } @@ -1122,9 +1287,14 @@ void S_OPENAL_StartSound( } iChannel = S_OPENAL_PickChannel3D(iEntNum, iEntChannel); - if (iChannel < 0) - { - Com_DPrintf("Couldn't play %s sound '%s' for entity %i on channel %s\n", (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "3Dstreamed" : "3D", pSfx->name, iEntNum, S_ChannelNumToName(iEntChannel)); + if (iChannel < 0) { + Com_DPrintf( + "Couldn't play %s sound '%s' for entity %i on channel %s\n", + (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "3Dstreamed" : "3D", + pSfx->name, + iEntNum, + S_ChannelNumToName(iEntChannel) + ); return; } @@ -1132,9 +1302,9 @@ void S_OPENAL_StartSound( callbackServer(iEntNum, iChannel, pSfx->name); } - pChannel = &openal.chan_3D[iChannel]; + pChannel = &openal.chan_3D[iChannel]; pChannel->fNewPitchMult = fPitch; - pChannel->iEntChannel = iEntChannel; + pChannel->iEntChannel = iEntChannel; pChannel->iFlags &= ~(CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER); state = pChannel->get_state(); @@ -1149,8 +1319,7 @@ void S_OPENAL_StartSound( } } - if (fMinDist < 0.0) - { + if (fMinDist < 0.0) { fMinDist = 200.0; fMaxDist = 12800.0; } @@ -1172,7 +1341,8 @@ void S_OPENAL_StartSound( pSfx->name, pChannel->fVolume, fMinDist, - fMaxDist); + fMaxDist + ); } pChannel->set_velocity(0, 0, 0); @@ -1188,17 +1358,19 @@ void S_OPENAL_StartSound( VectorClear(pChannel->vOrigin); } - pChannel->set_position(pChannel->vOrigin[0] / 52.49f, pChannel->vOrigin[1] / 52.49f, pChannel->vOrigin[2] / 52.49f); + pChannel->set_position( + pChannel->vOrigin[0] / 52.49f, pChannel->vOrigin[1] / 52.49f, pChannel->vOrigin[2] / 52.49f + ); pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = 0; } else { pChannel->iEntNum = iEntNum; if (vOrigin) { - pChannel->vOrigin[0] = -*vOrigin; - pChannel->vOrigin[1] = vOrigin[2]; - pChannel->vOrigin[2] = -vOrigin[1]; + pChannel->vOrigin[0] = -*vOrigin; + pChannel->vOrigin[1] = vOrigin[2]; + pChannel->vOrigin[2] = -vOrigin[1]; bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; - pChannel->iTime = cl.serverTime - 1; + pChannel->iTime = cl.serverTime - 1; if (bSupportWaitTillSoundDone) { pChannel->iTime = 0; } @@ -1220,15 +1392,19 @@ void S_OPENAL_StartSound( pChannel->set_sample_loop_count(1); } - if (!bOnlyUpdate && S_OPENAL_ShouldStart(pChannel->vOrigin, pChannel->fMinDist, pChannel->fMaxDist)) - { + if (!bOnlyUpdate && S_OPENAL_ShouldStart(pChannel->vOrigin, pChannel->fMinDist, pChannel->fMaxDist)) { pChannel->play(); - pChannel->iEndTime = cl.serverTime + (int)pChannel->pSfx->time_length + 250; - pChannel->iBaseRate = pChannel->sample_playback_rate(); + pChannel->iEndTime = cl.serverTime + (int)pChannel->pSfx->time_length + 250; + pChannel->iBaseRate = pChannel->sample_playback_rate(); pChannel->iStartTime = cl.serverTime; } } +/* +============== +S_OPENAL_AddLoopingSound +============== +*/ void S_OPENAL_AddLoopingSound( const vec3_t vOrigin, const vec3_t vVelocity, @@ -1240,13 +1416,13 @@ void S_OPENAL_AddLoopingSound( int iFlags ) { - int i; - int iFreeLoopSound; - sfx_t* pSfx; - openal_loop_sound_t* pLoopSound; + int i; + int iFreeLoopSound; + sfx_t *pSfx; + openal_loop_sound_t *pLoopSound; iFreeLoopSound = -1; - pSfx = &s_knownSfx[sfxHandle]; + pSfx = &s_knownSfx[sfxHandle]; if (!pSfx) { return; } @@ -1257,14 +1433,13 @@ void S_OPENAL_AddLoopingSound( iFreeLoopSound = i; break; } - } if (iFreeLoopSound < 0) { for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { pLoopSound = &openal.loop_sounds[i]; if (!pLoopSound->pSfx && !pLoopSound->bInUse) { - iFreeLoopSound = i; + iFreeLoopSound = i; pLoopSound->bPlaying = false; break; } @@ -1279,22 +1454,22 @@ void S_OPENAL_AddLoopingSound( return; } - pLoopSound = &openal.loop_sounds[iFreeLoopSound]; - pLoopSound->vOrigin[0] = -vOrigin[0]; - pLoopSound->vOrigin[1] = vOrigin[2]; - pLoopSound->vOrigin[2] = -vOrigin[1]; + pLoopSound = &openal.loop_sounds[iFreeLoopSound]; + pLoopSound->vOrigin[0] = -vOrigin[0]; + pLoopSound->vOrigin[1] = vOrigin[2]; + pLoopSound->vOrigin[2] = -vOrigin[1]; pLoopSound->vVelocity[0] = -vVelocity[0] / 52.49f / 500.f; pLoopSound->vVelocity[1] = vVelocity[2] / 52.49f / 500.f; pLoopSound->vVelocity[2] = -vVelocity[1] / 52.49f / 500.f; - pLoopSound->pSfx = pSfx; - pLoopSound->bInUse = true; - pLoopSound->iStartTime = cls.realtime; - pLoopSound->fBaseVolume = fVolume; - pLoopSound->fMinDist = fMinDist; - pLoopSound->fMaxDist = fMaxDist; - pLoopSound->fPitch = fPitch; - pLoopSound->iFlags = iFlags; - pLoopSound->bCombine = VectorCompare(vVelocity, vec_zero) == 0; + pLoopSound->pSfx = pSfx; + pLoopSound->bInUse = true; + pLoopSound->iStartTime = cls.realtime; + pLoopSound->fBaseVolume = fVolume; + pLoopSound->fMinDist = fMinDist; + pLoopSound->fMaxDist = fMaxDist; + pLoopSound->fPitch = fPitch; + pLoopSound->iFlags = iFlags; + pLoopSound->bCombine = VectorCompare(vVelocity, vec_zero) == 0; if (pLoopSound->bCombine) { for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { @@ -1309,11 +1484,16 @@ void S_OPENAL_AddLoopingSound( } } +/* +============== +S_OPENAL_StopLoopingSound +============== +*/ void S_OPENAL_StopLoopingSound(openal_loop_sound_t *pLoopSound) { - bool bMayStop; - int i; - openal_channel* pChannel; + bool bMayStop; + int i; + openal_channel *pChannel; if (!pLoopSound->bPlaying) { return; @@ -1331,24 +1511,33 @@ void S_OPENAL_StopLoopingSound(openal_loop_sound_t *pLoopSound) if (bMayStop) { if (s_show_sounds->integer > 0) { - Com_DPrintf("%d (#%i) - stopped loop - %s\n", cl.serverTime, pLoopSound->iChannel, openal.channel[pLoopSound->iChannel]->pSfx->name); + Com_DPrintf( + "%d (#%i) - stopped loop - %s\n", + cl.serverTime, + pLoopSound->iChannel, + openal.channel[pLoopSound->iChannel]->pSfx->name + ); } openal.channel[pLoopSound->iChannel]->force_free(); } - pLoopSound->pSfx = NULL; + pLoopSound->pSfx = NULL; pLoopSound->bPlaying = false; if (pLoopSound->bCombine) { for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { - if (openal.loop_sounds[i].pSfx == pLoopSound->pSfx) - { + if (openal.loop_sounds[i].pSfx == pLoopSound->pSfx) { openal.loop_sounds[i].bPlaying = false; - openal.loop_sounds[i].pSfx = NULL; + openal.loop_sounds[i].pSfx = NULL; } } } } +/* +============== +S_OPENAL_ClearLoopingSounds +============== +*/ void S_OPENAL_ClearLoopingSounds() { int i; @@ -1358,6 +1547,11 @@ void S_OPENAL_ClearLoopingSounds() } } +/* +============== +S_OPENAL_StopLoopingSounds +============== +*/ void S_OPENAL_StopLoopingSounds() { int i; @@ -1368,12 +1562,17 @@ void S_OPENAL_StopLoopingSounds() } } +/* +============== +S_OPENAL_StopSound +============== +*/ void S_OPENAL_StopSound(int iEntNum, int iEntChannel) { int i; for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { - openal_channel* pChannel = openal.channel[i]; + openal_channel *pChannel = openal.channel[i]; if (!pChannel->is_free() && pChannel->iEntNum == iEntNum && pChannel->iEntChannel == iEntChannel) { pChannel->end_sample(); break; @@ -1381,6 +1580,11 @@ void S_OPENAL_StopSound(int iEntNum, int iEntChannel) } } +/* +============== +S_OPENAL_StopAllSounds +============== +*/ void S_OPENAL_StopAllSounds(qboolean bStopMusic) { int i; @@ -1390,7 +1594,7 @@ void S_OPENAL_StopAllSounds(qboolean bStopMusic) } for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { - openal_channel* pChannel = openal.channel[i]; + openal_channel *pChannel = openal.channel[i]; if (pChannel) { pChannel->force_free(); } @@ -1400,21 +1604,24 @@ void S_OPENAL_StopAllSounds(qboolean bStopMusic) MUSIC_FreeAllSongs(); S_TriggeredMusic_Stop(); } - // FIXME: unimplemented } +/* +============== +S_OPENAL_Start2DLoopSound +============== +*/ static int S_OPENAL_Start2DLoopSound( openal_loop_sound_t *pLoopSound, float fVolume, float fVolumeToPlay, float fMinDistance, const vec3_t vLoopOrigin ) { - int iChannel; - int iSoundOFfset; - openal_channel* pChannel; + int iChannel; + int iSoundOFfset; + openal_channel *pChannel; if (pLoopSound->pSfx->iFlags & SFX_FLAG_NO_DATA) { iChannel = S_OPENAL_PickChannel2DStreamed(0, 0); - } - else { + } else { iChannel = S_OPENAL_PickChannel2D(0, 0); } @@ -1440,17 +1647,17 @@ static int S_OPENAL_Start2DLoopSound( return -1; } - pChannel->iEntNum = 0; + pChannel->iEntNum = 0; pChannel->iEntChannel = 0; - pChannel->pSfx = pLoopSound->pSfx; + pChannel->pSfx = pLoopSound->pSfx; pChannel->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; pChannel->iBaseRate = pChannel->sample_playback_rate(); VectorCopy(vLoopOrigin, pChannel->vOrigin); - pChannel->set_sample_offset((int)(pLoopSound->pSfx->info.width - * pLoopSound->pSfx->info.rate - * (float)(cls.realtime - pLoopSound->iStartTime) - / 1000.0) - % pLoopSound->pSfx->length); + pChannel->set_sample_offset( + (int)(pLoopSound->pSfx->info.width * pLoopSound->pSfx->info.rate + * (float)(cls.realtime - pLoopSound->iStartTime) / 1000.0) + % pLoopSound->pSfx->length + ); pChannel->set_sample_loop_count(0); pChannel->fVolume = fVolumeToPlay; @@ -1463,6 +1670,11 @@ static int S_OPENAL_Start2DLoopSound( return iChannel; } +/* +============== +S_OPENAL_Start3DLoopSound +============== +*/ static int S_OPENAL_Start3DLoopSound( openal_loop_sound_t *pLoopSound, float fVolumeToPlay, @@ -1472,25 +1684,24 @@ static int S_OPENAL_Start3DLoopSound( const vec3_t vListenerOrigin ) { - int iChannel; - vec3_t vDir; - int iSoundOffset; - openal_channel* pChan3D; + int iChannel; + vec3_t vDir; + int iSoundOffset; + openal_channel *pChan3D; if (pLoopSound->pSfx->iFlags & SFX_FLAG_NO_DATA) { return -1; } iChannel = S_OPENAL_PickChannel3D(0, 0); - if (iChannel < 0) - { + if (iChannel < 0) { Com_DPrintf("Could not find a free channel\n"); return iChannel; } pChan3D = &openal.chan_3D[iChannel]; pChan3D->force_free(); - pChan3D->iEntNum = 0; + pChan3D->iEntNum = 0; pChan3D->iEntChannel = 0; pChan3D->set_3d(); @@ -1500,16 +1711,16 @@ static int S_OPENAL_Start3DLoopSound( } pChan3D->set_position(vLoopOrigin[0] / 52.49f, pLoopSound->vVelocity[1] / 52.49f, vLoopOrigin[2] / 52.49f); - pChan3D->set_velocity(pLoopSound->vVelocity[0] / 52.49f, vLoopOrigin[1] / 52.49f, pLoopSound->vVelocity[2] / 52.49f); + pChan3D->set_velocity( + pLoopSound->vVelocity[0] / 52.49f, vLoopOrigin[1] / 52.49f, pLoopSound->vVelocity[2] / 52.49f + ); pChan3D->pSfx = pLoopSound->pSfx; pChan3D->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; pChan3D->iBaseRate = pChan3D->sample_playback_rate(); - iSoundOffset = (int)((int)pLoopSound->pSfx->info.width - * pLoopSound->pSfx->info.rate - * (float)(cls.realtime - pLoopSound->iStartTime) - / 1000.0) - % pLoopSound->pSfx->length; + iSoundOffset = (int)((int)pLoopSound->pSfx->info.width * pLoopSound->pSfx->info.rate + * (float)(cls.realtime - pLoopSound->iStartTime) / 1000.0) + % pLoopSound->pSfx->length; pChan3D->set_sample_offset(iSoundOffset); pChan3D->set_sample_loop_count(0); pChan3D->fVolume = fVolumeToPlay; @@ -1521,6 +1732,11 @@ static int S_OPENAL_Start3DLoopSound( return iChannel; } +/* +============== +S_OPENAL_UpdateLoopSound +============== +*/ static bool S_OPENAL_UpdateLoopSound( openal_loop_sound_t *pLoopSound, float fVolumeToPlay, @@ -1531,400 +1747,2133 @@ static bool S_OPENAL_UpdateLoopSound( const vec3_t vLoopOrigin ) { - // FIXME: unimplemented - return false; + openal_channel *pChannel; + float fVolume; + float fMaxVolume; + vec3_t vDir; + float fDistance; + + pChannel = openal.channel[pLoopSound->iChannel]; + if (!pChannel) { + return false; + } + + if (pChannel->pSfx != pLoopSound->pSfx) { + pLoopSound->bPlaying = 0; + return false; + } + + pChannel->iStartTime = cl.serverTime; + + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3) + || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { + vec3_t vOrigin; + int iPan; + + pChannel->fVolume = fVolumeToPlay / 84.0; + fVolume = S_GetBaseVolume() * pChannel->fVolume; + fMaxVolume = fVolume; + + if (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN) { + // Center the sound + iPan = 64; + } else { + VectorCopy(vLoopOrigin, vOrigin); + iPan = S_OPENAL_SpatializeStereoSound(vListenerOrigin, vTempAxis, vOrigin); + + VectorSubtract(vListenerOrigin, vOrigin, vDir); + // Clamp the volume by distance + fDistance = VectorLength(vDir); + if (pChannel->fMinDist >= fDistance) { + fVolume = fMaxVolume; + } else { + fVolume = pChannel->fMinDist / fDistance * fMaxVolume; + } + } + + pChannel->set_gain(fVolume); + pChannel->set_sample_pan(iPan); + } else { + pChannel->set_position(vLoopOrigin[0] / 52.49f, vLoopOrigin[1] / 52.49f, vLoopOrigin[2] / 52.49f); + pChannel->fVolume = fVolumeToPlay; + pChannel->set_gain(fVolumeToPlay); + } + + if (s_bReverbChanged) { + // Make sure to update the reverb + S_OPENAL_reverb(pLoopSound->iChannel, s_iReverbType, s_fReverbLevel); + } + + return true; } +/* +============== +S_OPENAL_AddLoopSounds +============== +*/ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) { - // FIXME: unimplemented + int i, j; + static int iLoopFrame = 0; + float fDistance; + int iChannel; + vec3_t vListenerOrigin; + vec3_t vLoopOrigin; + openal_loop_sound_t *pLoopSound; + float fTotalVolume; + float fVolumeToPlay; + float fMinDistance, fMaxDistance; + float fVolume; + float fPitch; + float fMaxVolume, fMaxFactor; + openal_channel *pChannel; + bool bAlreadyAdded[MAX_OPENAL_LOOP_SOUNDS] = {false}; + vec3_t alvec; + + qalGetListenerfv(AL_POSITION, alvec); + VectorScale(alvec, 52.49f, vListenerOrigin); + + for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) { + vec3_t vDir; + + if (bAlreadyAdded[i]) { + continue; + } + + pLoopSound = &openal.loop_sounds[i]; + if (!pLoopSound->pSfx) { + continue; + } + pChannel = openal.channel[pLoopSound->iChannel]; + + fMinDistance = pLoopSound->fMinDist; + if (fMinDistance < 0) { + fMinDistance = 200; + } + + fMaxDistance = pLoopSound->fMaxDist; + if (fMaxDistance < 0) { + fMaxDistance = fMinDistance * 64; + } + + fVolume = pLoopSound->fBaseVolume; + if (fVolume < 0) { + fVolume = 1; + } + fVolume = fVolume * s_fAmbientVolume; + + fTotalVolume = 0.0; + fMaxVolume = 0.0; + + if (pLoopSound->bPlaying) { + pChannel->fNewPitchMult = pLoopSound->fPitch; + } + + if (pLoopSound->bCombine) { + for (j = 0; j < MAX_LOOP_SOUNDS; j++) { + openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j]; + + if (pLoopSound2->pSfx == pLoopSound->pSfx) { + VectorSubtract(pLoopSound2->vOrigin, vListenerOrigin, vDir); + VectorCopy(vDir, pLoopSound2->vRelativeOrigin); + fDistance = VectorLength(pLoopSound2->vRelativeOrigin); + + if (fDistance <= fMinDistance) { + fVolumeToPlay = fVolume; + } else if (fDistance >= fMaxDistance) { + fVolumeToPlay = 0; + } else { + fVolumeToPlay = fMinDistance * fMinDistance * fVolume / (fDistance * fDistance); + } + + if (fMaxVolume < fVolumeToPlay) { + fMaxVolume = fVolumeToPlay; + } + fTotalVolume += fVolumeToPlay; + bAlreadyAdded[j] = true; + } + } + } else { + VectorSubtract(pLoopSound->vOrigin, vListenerOrigin, vDir); + VectorCopy(vDir, pLoopSound->vRelativeOrigin); + fDistance = VectorLength(pLoopSound->vRelativeOrigin); + + if (fDistance <= fMinDistance) { + fTotalVolume = fVolume; + } else if (fDistance >= fMaxDistance) { + fTotalVolume = 0; + } else { + fTotalVolume = fMinDistance * fMinDistance * fVolume / (fDistance * fDistance); + } + pLoopSound->fVolume = fTotalVolume; + fMaxVolume = fTotalVolume; + } + + fMaxFactor = sfx_infos[pLoopSound->pSfx->sfx_info_index].max_factor; + if (fMaxFactor >= 1 && fMaxVolume * fMaxFactor < fTotalVolume) { + fTotalVolume = fMaxVolume * fMaxFactor; + } + + if (fTotalVolume <= 0 && !(pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { + if (pLoopSound->bPlaying) { + if (s_show_sounds->integer > 0) { + Com_DPrintf( + "%d (#%i) - stopped loop - %s\n", + cl.serverTime, + pLoopSound->iChannel, + openal.channel[pLoopSound->iChannel]->pSfx->name + ); + } + + pChannel->stop(); + pLoopSound->bPlaying = false; + if (pLoopSound->bCombine) { + for (j = 0; j < MAX_LOOP_SOUNDS; j++) { + openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j]; + + if (pLoopSound2->pSfx == pLoopSound->pSfx) { + pLoopSound2->bPlaying = false; + } + } + } + } + + continue; + } + + VectorClear(vLoopOrigin); + + if (pLoopSound->bCombine) { + for (j = 0; j < MAX_LOOP_SOUNDS; j++) { + openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j]; + + if (pLoopSound2->pSfx == pLoopSound->pSfx) { + VectorNormalize(pLoopSound2->vRelativeOrigin); + + VectorScale( + pLoopSound2->vRelativeOrigin, pLoopSound2->fVolume / fTotalVolume, pLoopSound2->vRelativeOrigin + ); + VectorAdd(pLoopSound2->vRelativeOrigin, vLoopOrigin, vLoopOrigin); + } + } + + VectorNormalize(vLoopOrigin); + VectorMA(vListenerOrigin, fMinDistance * 0.5f, vLoopOrigin, vLoopOrigin); + } else { + VectorCopy(pLoopSound->vOrigin, vLoopOrigin); + } + + if (pLoopSound->bPlaying) { + S_OPENAL_UpdateLoopSound( + pLoopSound, + S_GetBaseVolume() * 84.0 * fTotalVolume, + fMinDistance, + fMaxDistance, + vListenerOrigin, + vTempAxis, + vLoopOrigin + ); + + continue; + } + + if (s_show_sounds->integer > 0) { + Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name); + } + + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3) + || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { + iChannel = S_OPENAL_Start2DLoopSound( + pLoopSound, fVolume, S_GetBaseVolume() * 84.0 * fTotalVolume, fMinDistance, vLoopOrigin + ); + } else { + iChannel = S_OPENAL_Start3DLoopSound( + pLoopSound, + S_GetBaseVolume() * 84.0 * fTotalVolume, + fMinDistance, + fMaxDistance, + vLoopOrigin, + vListenerOrigin + ); + } + + if (iChannel < 0) { + continue; + } + + pLoopSound->bPlaying = 1; + pLoopSound->iChannel = iChannel; + + if (pLoopSound->bCombine) { + for (j = 0; j < MAX_LOOP_SOUNDS; j++) { + openal_loop_sound_t *pLoopSound2 = &openal.loop_sounds[j]; + + if (pLoopSound2->pSfx == pLoopSound->pSfx) { + pLoopSound2->bPlaying = true; + pLoopSound2->iChannel = iChannel; + } + } + } + } } +/* +============== +S_OPENAL_Respatialize +============== +*/ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxis[3]) { - // FIXME: unimplemented + int i; + vec3_t vOrigin; + vec3_t vVelocity; + vec3_t vEntOrigin; + vec3_t vEntVelocity; + vec3_t vDir; + vec3_t vUp; + vec3_t vListenerOrigin; + int iPan; + vec3_t vTempAxis; + float fMaxVolume; + float fVolume; + float fDist; + openal_channel *pChannel; + vec3_t alvec {0}; + vec3_t alorientation[2]; + + if (cls.no_menus) { + return; + } + + s_iListenerNumber = iEntNum; + + // + // Velocity + // + qalListenerfv(AL_VELOCITY, alvec); + alDieIfError(); + + // + // Position + // + alvec[0] = -vHeadPos[0] / 52.49f; + alvec[1] = vHeadPos[2] / 52.49f; + alvec[2] = -vHeadPos[1] / 52.49f; + VectorCopy(alvec, vListenerOrigin); + qalListenerfv(AL_POSITION, alvec); + alDieIfError(); + + // + // Orientation + // + alorientation[0][0] = -vAxis[0][0]; + alorientation[0][1] = vAxis[2][0]; + alorientation[0][2] = -vAxis[1][0]; + alorientation[1][0] = -vAxis[0][2]; + alorientation[1][1] = vAxis[2][2]; + alorientation[1][2] = -vAxis[1][2]; + qalListenerfv(AL_ORIENTATION, (const ALfloat *)alorientation); + alDieIfError(); + + vTempAxis[0] = -vAxis[0][1]; + vTempAxis[1] = vAxis[2][1]; + vTempAxis[2] = -vAxis[1][1]; + + fVolume = 1; + iPan = 64; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + pChannel = openal.channel[i]; + fMaxVolume = S_GetBaseVolume() * pChannel->fVolume; + + if (!pChannel) { + continue; + } + + if (!pChannel->is_playing()) { + continue; + } + + if (pChannel->iFlags & CHANNEL_FLAG_PAUSED) { + continue; + } + + if (pChannel->iFlags & CHANNEL_FLAG_NO_ENTITY) { + VectorCopy(pChannel->vOrigin, vOrigin); + + if (pChannel->iFlags & CHANNEL_FLAG_LOCAL_LISTENER) { + VectorCopy(vListenerOrigin, vOrigin); + if (i >= MAX_OPENAL_CHANNELS_3D) { + fVolume = fMaxVolume; + iPan = 64; + } else { + pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + } + } else { + if (i >= MAX_OPENAL_CHANNELS_3D) { + iPan = S_OPENAL_SpatializeStereoSound(vListenerOrigin, vTempAxis, vOrigin); + VectorSubtract(vListenerOrigin, vOrigin, vDir); + + fDist = VectorLength(vDir); + if (fDist <= pChannel->fMinDist + 0.001f) { + fVolume = fMaxVolume; + } else if (fDist >= pChannel->fMaxDist - 0.001f) { + fVolume = 0; + } else { + fVolume = (1.0 - (fDist - pChannel->fMinDist) / (pChannel->fMaxDist - pChannel->fMinDist)) + * fMaxVolume; + } + } else { + pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + } + } + } else if (pChannel->iFlags & CHANNEL_FLAG_LOCAL_LISTENER) { + VectorCopy(vListenerOrigin, vOrigin); + if (i >= MAX_OPENAL_CHANNELS_3D) { + fVolume = fMaxVolume; + iPan = 64; + } else { + pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + } + } else { + if (s_entity[pChannel->iEntNum].time < pChannel->iTime) { + VectorCopy(pChannel->vOrigin, vOrigin); + if (!(pChannel->iFlags & CHANNEL_FLAG_LOOPING)) { + pChannel->end_sample(); + continue; + } + } else { + VectorCopy(s_entity[pChannel->iEntNum].position, vEntOrigin); + vOrigin[1] = vEntOrigin[2]; + vOrigin[0] = -vEntOrigin[0]; + vOrigin[2] = -vEntOrigin[1]; + VectorCopy(vOrigin, pChannel->vOrigin); + pChannel->iTime = s_entity[pChannel->iEntNum].time; + } + + if (s_entity[pChannel->iEntNum].use_listener) { + VectorCopy(vListenerOrigin, vOrigin); + } + + if (pChannel->iEntNum == s_iListenerNumber) { + if (vListenerOrigin[0] == vOrigin[0] && vListenerOrigin[2] == vOrigin[2]) { + float fDelta = vListenerOrigin[1] - vOrigin[1]; + + if (fDelta > 89.9f && fDelta < 90.09f) { + VectorCopy(vListenerOrigin, vOrigin); + } + } + } + + if (i >= MAX_OPENAL_CHANNELS_3D) { + iPan = S_OPENAL_SpatializeStereoSound(vListenerOrigin, vTempAxis, vOrigin); + VectorSubtract(vListenerOrigin, vOrigin, vDir); + fDist = VectorLength(vDir); + if (fDist <= pChannel->fMinDist + 0.001f) { + fVolume = fMaxVolume; + } else if (fDist >= pChannel->fMaxDist - 0.001f) { + fVolume = 0; + } else { + fVolume = + (1.0 - (fDist - pChannel->fMinDist) / (pChannel->fMaxDist - pChannel->fMinDist)) * fMaxVolume; + } + } else { + pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + VectorCopy(s_entity[pChannel->iEntNum].velocity, vEntVelocity); + + vVelocity[0] = -vEntVelocity[0] / 52.49f / 500.f; + vVelocity[1] = vEntVelocity[2] / 52.49f / 500.f; + vVelocity[2] = -vEntVelocity[1] / 52.49f / 500.f; + pChannel->set_velocity(vVelocity[0] / 52.49f, vVelocity[1] / 52.49f, vVelocity[2] / 52.49f); + } + } + + if (i >= MAX_OPENAL_CHANNELS_3D) { + pChannel->set_gain(fVolume); + pChannel->set_sample_pan(iPan); + } + + if (s_bReverbChanged) { + S_OPENAL_reverb(i, s_iReverbType, s_fReverbLevel); + } + } + + S_OPENAL_AddLoopSounds(vTempAxis); + s_bReverbChanged = false; } +/* +============== +S_OPENAL_SpatializeStereoSound +============== +*/ static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin) { - // FIXME: unimplemented - return 0; + float lscale, rscale; + vec3_t source_vec; + int pan; + + VectorSubtract(origin, listener_origin, source_vec); + VectorNormalize(source_vec); + + pan = s_separation->value + (1.f - s_separation->value) * -DotProduct(listener_left, source_vec); + + if (pan < 0) { + pan = 0; + } + + return pan * 128.f; } +/* +============== +S_OPENAL_reverb +============== +*/ static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel) { - // FIXME: unimplemented + // No reverb. } +/* +============== +S_OPENAL_SetReverb +============== +*/ void S_OPENAL_SetReverb(int iType, float fLevel) { - // FIXME: unimplemented + s_fReverbLevel = fLevel; + s_iReverbType = iType; + if (al_use_reverb) { + s_bReverbChanged = true; + } } +/* +============== +S_OPENAL_Update +============== +*/ void S_OPENAL_Update() { - // FIXME: unimplemented + int i; + openal_channel *pChannel; + + if (cl.snap.ps.stats[STAT_CINEMATIC]) { + S_SetGlobalAmbientVolumeLevel(0.5f); + } else { + S_SetGlobalAmbientVolumeLevel(1.f); + } + + if (paused->integer && !s_bSoundPaused) { + S_PauseSound(); + } else if (!paused->integer && s_bSoundPaused) { + S_UnpauseSound(); + } + + if (s_bFading) { + s_fFadeVolume = 1.f - (cls.realtime - s_fFadeStartTime) / (s_fFadeStopTime - s_fFadeStartTime); + if (s_fFadeVolume < 0) { + s_fFadeVolume = 0; + } + music_volume_changed = true; + } + + if (s_volume->modified) { + if (s_volume->value > 1) { + Cvar_Set("s_volume", "1.0"); + } else if (s_volume->value < 0) { + Cvar_Set("s_volume", "0.0"); + } + + music_volume_changed = true; + s_volume->modified = 0; + al_current_volume = Square(s_volume->value * s_volume->value); + qalListenerf(AL_GAIN, al_current_volume); + alDieIfError(); + } + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + pChannel = openal.channel[i]; + if (!pChannel) { + continue; + } + + if (!pChannel->is_playing()) { + continue; + } + + if (pChannel->fNewPitchMult <= 0) { + continue; + } + + pChannel->set_sample_playback_rate(pChannel->iBaseRate * pChannel->fNewPitchMult); + pChannel->fNewPitchMult = 0; + } + + if (s_speaker_type->modified) { + if (s_speaker_type->integer) { + Com_Printf("FIXME: Allow different speaker types in OpenAL code.\n"); + Cvar_Set("s_speaker_type", "0"); + } + s_speaker_type->modified = false; + } + + if (s_reverb->modified) { + s_reverb->modified = false; + Com_Printf("FIXME: Allow reverb toggle at runtime in OpenAL code.\n"); + } + + if (s_show_num_active_sounds->integer == 1) { + int num = 0; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + pChannel = openal.channel[i]; + if (pChannel && pChannel->is_playing()) { + ++num; + } + } + Com_DPrintf("Number of active sounds = %d\n", num); + } + + Music_Update(); + + for (i = 0; i < MAX_LOOP_SOUNDS; i++) { + if (!openal.loop_sounds[i].bInUse) { + S_OPENAL_StopLoopingSound(&openal.loop_sounds[i]); + } + } } +/* +============== +S_IsSoundPlaying +============== +*/ qboolean S_IsSoundPlaying(int channel_number, const char *sfxName) { - // FIXME: unimplemented - return qfalse; + openal_channel *pChannel = openal.channel[channel_number]; + if (!pChannel) { + return false; + } + + if (s_bSoundPaused) { + return false; + } + + if (!pChannel->is_playing()) { + return false; + } + + if (!pChannel->pSfx || pChannel->pSfx == (sfx_t *)-16) { + return false; + } + + return !strcmp(sfxName, pChannel->pSfx->name); } +/* +============== +S_StoreBase +============== +*/ static void S_StoreBase(channelbasesavegame_t *pBase, openal_channel *pChannel) { - // FIXME: unimplemented + if (!pChannel) { + return; + } + + if (pChannel->iEntChannel == CHAN_MENU || pChannel->is_free()) { + pBase->bPlaying = false; + pBase->iOffset = 0; + pBase->iLoopCount = 0; + pBase->sfx.szName[0] = 0; + pBase->sfx.iFlags = 0; + pBase->fNewPitchMult = 1.f; + pBase->iBaseRate = pChannel->iBaseRate; + pBase->iStatus = 0; + } else { + pBase->bPlaying = true; + pBase->iOffset = pChannel->sample_offset(); + pBase->iLoopCount = pChannel->sample_loop_count(); + memcpy(pBase->sfx.szName, pChannel->pSfx->name, sizeof(pBase->sfx.szName)); + pBase->sfx.iFlags = pChannel->pSfx->iFlags; + pBase->iBaseRate = pChannel->iBaseRate; + pBase->iStatus = 0; + pBase->fNewPitchMult = (float)pBase->iBaseRate / (float)pChannel->sample_playback_rate(); + } + + pBase->iStartTime = pChannel->iStartTime - cl.serverTime; + pBase->iEndTime = pChannel->iEndTime - cl.serverTime; + pBase->iEntChannel = pChannel->iEntChannel; + pBase->iEntNum = pChannel->iEntNum; + pBase->iFlags = pChannel->iFlags; + pBase->fMaxDist = pChannel->fMaxDist; + pBase->fMinDist = pChannel->fMinDist; + pBase->iNextCheckObstructionTime = 0; + VectorCopy(pChannel->vOrigin, pBase->vOrigin); + pBase->iTime = pChannel->iTime - cl.serverTime; + pBase->fVolume = pChannel->fVolume; } +/* +============== +S_StartSoundFromBase +============== +*/ static void S_StartSoundFromBase(channelbasesavegame_t *pBase, openal_channel *pChannel, sfx_t *pSfx, bool bStartUnpaused) { - // FIXME: unimplemented + if (!pChannel->set_sfx(pSfx)) { + Com_DPrintf("Set sample error - %s\n", pSfx->name); + pChannel->iFlags &= ~CHANNEL_FLAG_PLAYABLE; + return; + } + + pChannel->iBaseRate = pChannel->sample_playback_rate(); + pChannel->set_gain(pChannel->fVolume); + pChannel->set_sample_offset(pBase->iOffset); + pChannel->set_sample_playback_rate(pChannel->iBaseRate * pBase->fNewPitchMult); + + if (sfx_infos[pSfx->sfx_info_index].loop_start != -1) { + pChannel->set_sample_loop_block( + sfx_infos[pSfx->sfx_info_index].loop_start, sfx_infos[pSfx->sfx_info_index].loop_end + ); + pChannel->set_sample_loop_count(1); + pChannel->iFlags |= CHANNEL_FLAG_LOOPING; + if (s_show_sounds->integer > 0) { + Com_DPrintf( + "loopblock - %d to %d\n", + sfx_infos[pSfx->sfx_info_index].loop_start, + sfx_infos[pSfx->sfx_info_index].loop_end + ); + } + } else { + pChannel->set_sample_loop_count(1); + } + + if (bStartUnpaused) { + pChannel->resume_sample(); + } else { + pChannel->iFlags |= CHANNEL_FLAG_PLAYABLE; + } } +/* +============== +S_LoadBase +============== +*/ static void S_LoadBase(channelbasesavegame_t *pBase, openal_channel *pChannel, bool bStartUnpaused) { - // FIXME: unimplemented + sfxHandle_t handle; + + if (!pChannel) { + return; + } + + if (!pBase->bPlaying) { + return; + } + + if (strstr(pBase->sfx.szName, "null.wav")) { + return; + } + + handle = S_RegisterSound(pBase->sfx.szName, (pBase->sfx.iFlags & SFX_FLAG_DEFAULT_SOUND), false); + + pChannel->iBaseRate = pBase->iBaseRate; + pChannel->iStartTime = pBase->iStartTime; + pChannel->iEndTime = pBase->iEndTime; + pChannel->iEntChannel = pBase->iEntChannel; + pChannel->iEntNum = pBase->iEntNum; + pChannel->iFlags = pBase->iFlags; + pChannel->fMaxDist = pBase->fMaxDist; + pChannel->fMinDist = pBase->fMinDist; + pChannel->fNewPitchMult = pBase->fNewPitchMult; + VectorCopy(pBase->vOrigin, pChannel->vOrigin); + pChannel->iTime = pBase->iTime; + pChannel->fVolume = pBase->fVolume; + pChannel->pSfx = &s_knownSfx[handle]; + + S_StartSoundFromBase(pBase, pChannel, &s_knownSfx[handle], bStartUnpaused); } +/* +============== +S_SaveData +============== +*/ void S_SaveData(soundsystemsavegame_t *pSave) { - // FIXME: unimplemented + int i; + bool bSoundWasUnpaused; + + bSoundWasUnpaused = !s_bSoundPaused; + if (!s_bSoundPaused) { + S_PauseSound(); + } + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + S_StoreBase(&pSave->Channels[i], openal.channel[i]); + } + + if (bSoundWasUnpaused) { + S_UnpauseSound(); + } } +/* +============== +S_ReLoad +============== +*/ void S_ReLoad(soundsystemsavegame_t *pSave) { - // FIXME: unimplemented + int i; + bool bSoundWasUnpaused; + + bSoundWasUnpaused = !s_bSoundPaused; + if (!s_bSoundPaused) { + S_PauseSound(); + } + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + S_LoadBase(&pSave->Channels[i], openal.channel[i], bSoundWasUnpaused); + } + + if (bSoundWasUnpaused) { + S_UnpauseSound(); + } } +/* +============== +S_InitBase +============== +*/ static void S_InitBase(channelbasesavegame_t *pBase) { - // FIXME: unimplemented + if (!pBase->bPlaying) { + return; + } + + if (strstr(pBase->sfx.szName, "null.wav")) { + return; + } + + SV_AddSvsTimeFixup(&pBase->iStartTime); + SV_AddSvsTimeFixup(&pBase->iEndTime); + SV_AddSvsTimeFixup(&pBase->iTime); } +/* +============== +S_LoadData +============== +*/ void S_LoadData(soundsystemsavegame_t *pSave) { - // FIXME: unimplemented + int i; + + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + S_InitBase(&pSave->Channels[i]); + } } +/* +============== +openal_channel::set_velocity +============== +*/ void openal_channel::set_velocity(float v0, float v1, float v2) { - // FIXME: unimplemented + qalSource3f(source, AL_VELOCITY, v0, v1, v2); + alDieIfError(); } +/* +============== +openal_channel::set_position +============== +*/ void openal_channel::set_position(float v0, float v1, float v2) { - // FIXME: unimplemented + qalSource3f(source, AL_POSITION, v0, v1, v2); + alDieIfError(); } +/* +============== +openal_channel::set_gain +============== +*/ void openal_channel::set_gain(float gain) { - // FIXME: unimplemented + qalSourcef(source, AL_GAIN, gain); + alDieIfError(); } +/* +============== +openal_channel::set_no_3d +============== +*/ void openal_channel::set_no_3d() { - // FIXME: unimplemented + qalSource3f(source, AL_POSITION, 0, 0, 0); + alDieIfError(); + qalSource3f(source, AL_VELOCITY, 0, 0, 0); + alDieIfError(); + qalSourcei(source, AL_SOURCE_RELATIVE, true); + alDieIfError(); + qalSourcei(source, AL_LOOPING, false); + alDieIfError(); + qalSourcei(source, AL_ROLLOFF_FACTOR, 0); + alDieIfError(); + qalSourcef(source, AL_GAIN, S_GetBaseVolume()); + alDieIfError(); } +/* +============== +openal_channel::set_3d +============== +*/ void openal_channel::set_3d() { - // FIXME: unimplemented + qalSourcei(source, AL_SOURCE_RELATIVE, true); + alDieIfError(); + qalSourcei(source, AL_LOOPING, false); + alDieIfError(); + qalSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + alDieIfError(); + qalSourcef(source, AL_GAIN, S_GetBaseVolume()); + alDieIfError(); } +/* +============== +openal_channel::play +============== +*/ void openal_channel::play() { - // FIXME: unimplemented + qalSourcePlay(source); + alDieIfError(); } +/* +============== +openal_channel::pause +============== +*/ void openal_channel::pause() { - // FIXME: unimplemented + qalSourcePause(source); + alDieIfError(); } +/* +============== +openal_channel::stop +============== +*/ void openal_channel::stop() { - // FIXME: unimplemented + qalSourceStop(source); + alDieIfError(); } +/* +============== +openal_channel::get_state +============== +*/ ALint openal_channel::get_state() { - // FIXME: unimplemented - return 0; + ALint retval; + + qalGetSourcei(source, AL_SOURCE_STATE, &retval); + alDieIfError(); + + return retval; } +/* +============== +openal_channel::is_free +============== +*/ bool openal_channel::is_free() { - // FIXME: unimplemented - return false; + ALint state = get_state(); + + return state == AL_INITIAL || state == AL_STOPPED; } +/* +============== +openal_channel::is_paused +============== +*/ bool openal_channel::is_paused() { - // FIXME: unimplemented - return false; + ALint state = get_state(); + + return state == AL_PAUSED; } +/* +============== +openal_channel::is_playing +============== +*/ bool openal_channel::is_playing() { - // FIXME: unimplemented - return false; + ALint state = get_state(); + + return state == AL_PLAYING; } +/* +============== +openal_channel::force_free +============== +*/ void openal_channel::force_free() { - // FIXME: unimplemented + stop(); } +/* +============== +openal_channel::set_sfx +============== +*/ bool openal_channel::set_sfx(sfx_t *pSfx) { - // FIXME: unimplemented - return false; + ALfloat freq; + + this->pSfx = pSfx; + if (!pSfx->buffer || !qalIsBuffer(pSfx->buffer)) { + if (pSfx->iFlags & SFX_FLAG_MP3) { + qalGenBuffers(1, &pSfx->buffer); + alDieIfError(); + + if (!_alutLoadMP3_LOKI(pSfx->buffer, pSfx->data, pSfx->length)) { + qalDeleteBuffers(1, &pSfx->buffer); + alDieIfError(); + + Com_Printf("OpenAL: Failed to load MP3.\n"); + return false; + } + + alDieIfError(); + } else { + ALenum fmt = 0; + + if (pSfx->info.channels == 1) { + if (pSfx->info.width == 1) { + fmt = AL_FORMAT_MONO8; + } else if (pSfx->info.width == 2) { + fmt = AL_FORMAT_MONO16; + } + } else if (pSfx->info.channels == 2) { + if (pSfx->info.width == 1) { + fmt = AL_FORMAT_STEREO8; + } else if (pSfx->info.width == 2) { + fmt = AL_FORMAT_STEREO16; + } + } + + if (!fmt) { + Com_Printf( + "OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n", + pSfx->info.channels, + (int)(pSfx->info.width * 8.f), + pSfx->name + ); + return false; + } + + qalGenBuffers(1, &pSfx->buffer); + alDieIfError(); + + qalBufferData( + pSfx->buffer, + fmt, + &pSfx->data[pSfx->info.dataofs], + pSfx->info.samples * pSfx->info.width, + pSfx->info.rate + ); + alDieIfError(); + } + } + + qalSourceStop(source); + alDieIfError(); + + qalSourcei(source, AL_BUFFER, pSfx->buffer); + alDieIfError(); + + // Get the base frequency + qalGetBufferfv(pSfx->buffer, AL_FREQUENCY, &freq); + alDieIfError(); + + iBaseRate = freq; + + return true; } +/* +============== +openal_channel::start_sample +============== +*/ void openal_channel::start_sample() { - // FIXME: unimplemented + play(); } +/* +============== +openal_channel::stop_sample +============== +*/ void openal_channel::stop_sample() { - // FIXME: unimplemented + pause(); } +/* +============== +openal_channel::resume_sample +============== +*/ void openal_channel::resume_sample() { - // FIXME: unimplemented + play(); } +/* +============== +openal_channel::end_sample +============== +*/ void openal_channel::end_sample() { - // FIXME: unimplemented + stop(); } -void openal_channel::set_sample_pan(S32 pan) -{ - // FIXME: unimplemented -} +/* +============== +openal_channel::set_sample_pan +============== +*/ +void openal_channel::set_sample_pan(S32 pan) {} -void openal_channel::set_sample_playback_rate(S32 rate) -{ - // FIXME: unimplemented -} +/* +============== +openal_channel::set_sample_playback_rate +============== +*/ +void openal_channel::set_sample_playback_rate(S32 rate) {} +/* +============== +openal_channel::sample_playback_rate +============== +*/ S32 openal_channel::sample_playback_rate() { - // FIXME: unimplemented - return 0; + return 22050; } +/* +============== +openal_channel::sample_volume +============== +*/ S32 openal_channel::sample_volume() { - // FIXME: unimplemented - return 0; + STUB_DESC("sample_volume"); + return 127; } +/* +============== +openal_channel::sample_offset +============== +*/ U32 openal_channel::sample_offset() { - // FIXME: unimplemented - return 0; + STUB_DESC("sample_offset"); + return 127; } +/* +============== +openal_channel::sample_ms_offset +============== +*/ U32 openal_channel::sample_ms_offset() { - // FIXME: unimplemented - return 0; + STUB_DESC("sample_ms_offset"); + return 127; } +/* +============== +openal_channel::sample_loop_count +============== +*/ U32 openal_channel::sample_loop_count() { - // FIXME: unimplemented - return 0; + ALuint queued; + ALuint processed; + S32 left; + + qalGetSourceiv(source, AL_BUFFERS_QUEUED, (ALint *)&queued); + alDieIfError(); + qalGetSourcei(source, AL_BUFFERS_PROCESSED, (ALint *)&processed); + alDieIfError(); + + left = queued + ~processed; + if (left < 0) { + left = 0; + } + return left; } +/* +============== +openal_channel::set_sample_offset +============== +*/ void openal_channel::set_sample_offset(U32 offset) { - // FIXME: unimplemented + STUB_DESC("sample_offset"); } +/* +============== +openal_channel::set_sample_ms_offset +============== +*/ void openal_channel::set_sample_ms_offset(U32 offset) { - // FIXME: unimplemented + STUB_DESC("sample_ms_offset"); } +/* +============== +openal_channel::set_sample_loop_count +============== +*/ void openal_channel::set_sample_loop_count(S32 count) { - // FIXME: unimplemented + ALuint processed; + + stop(); + + qalGetSourceiv(source, AL_BUFFERS_PROCESSED, (ALint *)&processed); + alDieIfError(); + + for (ALuint i = 0; i < processed; i++) { + ALuint bufName; + + qalSourceUnqueueBuffers(source, 1, &bufName); + alDieIfError(); + } + + for (S32 i = 0; i < count; i++) { + qalSourceQueueBuffers(source, 1, &buffer); + alDieIfError(); + } } +/* +============== +openal_channel::set_sample_loop_block +============== +*/ void openal_channel::set_sample_loop_block(S32 start_offset, S32 end_offset) { - // FIXME: unimplemented + STUB_DESC("sample_loop_block"); } +/* +============== +openal_channel::sample_status +============== +*/ U32 openal_channel::sample_status() { - // FIXME: unimplemented - return 0; + STUB_DESC("sample_status"); + return 127; } +/* +============== +MUSIC_LoadSoundtrackFile +============== +*/ qboolean MUSIC_LoadSoundtrackFile(const char *filename) { - // FIXME: unimplemented - return qfalse; + song_t *psong = NULL; + char args[MAX_MUSIC_SONGS][MAX_RES_NAME]; + int numargs; + char com_token[MAX_STRING_CHARS]; + char alias[128]; + char file[128]; + char load_path[128]; + char *buffer; + char path[MAX_RES_NAME]; + int i; + byte *data; + + if (strrchr(filename, '.')) { + Com_sprintf(path, sizeof(path), "%s", filename); + } else { + Com_sprintf(path, sizeof(path), "%s.mus", filename); + } + + FS_ReadFile(path, (void **)&data); + if (!data) { + Com_DPrintf("Couldn't load %s\n", path); + return false; + } + Com_DPrintf("SOUNDTRACK: Loading %s\n", path); + + MUSIC_StopAllSongs(); + music_numsongs = 0; + + buffer = (char *)data; + load_path[0] = 0; + + while (1) { + strcpy(com_token, COM_GetToken(&buffer, true)); + if (!com_token[0]) { + break; + } + + if (strlen(com_token) >= MAX_RES_NAME) { + Com_Printf("MUSIC_LoadSoundtrackFile: argument too long, truncating in %s\n", path); + com_token[MAX_RES_NAME - 1] = 0; + } + + numargs = 1; + strcpy(args[0], com_token); + + while (1) { + strcpy(com_token, COM_GetToken(&buffer, false)); + if (!com_token[0]) { + break; + } + + if (strlen(com_token) >= MAX_RES_NAME) { + Com_Printf("MUSIC_LoadSoundtrackFile: argument too long, truncating in %s\n", path); + com_token[MAX_RES_NAME - 1] = 0; + } + + strcpy(args[numargs], com_token); + numargs++; + } + + if (!Q_stricmp(args[0], "path")) { + strcpy(load_path, args[1]); + if (load_path[strlen(load_path) - 1] != '/' && load_path[strlen(load_path) - 1] != '\\') { + strcat(load_path, "/"); + } + } else if (args[0][0] == '!') { + for (i = 0; i < music_numsongs; i++) { + psong = &music_songs[i]; + if (!Q_stricmp(psong->alias, &args[0][1])) { + break; + } + } + + if (i == music_numsongs) { + Com_Printf("MUSIC_LoadSoundtrackFile: song %s not found, command skipped in %s.\n", &args[0][1], path); + continue; + } + + if (!Q_stricmp(args[1], "volume")) { + psong->volume = atoi(args[2]); + } else if (!Q_stricmp(args[1], "fadetime")) { + psong->fadetime = atoi(args[2]); + } else if (!Q_stricmp(args[1], "loop")) { + psong->flags |= 1; + } else if (!Q_stricmp(args[1], "restart")) { + psong->flags |= 2; + } else if (!Q_stricmp(args[1], "interrupt")) { + psong->fadetime = 0; + psong->flags |= 4 | 2; + } else { + Com_Printf( + "MUSIC_LoadSoundtrackFile: unknown command %s for song %s in %s.\n", args[1], &args[0][1], path + ); + } + } else if (numargs > 1) { + strcpy(alias, args[0]); + strcpy(file, load_path); + strcat(file, args[1]); + } else { + strcpy(file, load_path); + strcat(file, args[1]); + + strncpy(alias, args[0], strlen(args[0]) - 4); + file[strlen(args[0]) + MAX_RES_NAME * 2 - 4] = 0; + + if (music_numsongs >= MAX_MUSIC_SONGS) { + Com_Printf("MUSIC_LoadSoundtrackFile: Too many songs in %s, skipping %s.\n", path, alias); + continue; + } + + psong = &music_songs[music_numsongs]; + strcpy(psong->alias, alias); + strcpy(psong->path, file); + music_songs[music_numsongs].fadetime = 1.0; + music_songs[music_numsongs].volume = 1.0; + music_songs[music_numsongs].flags = 0; + music_songs[music_numsongs].current_pos = 0; + music_songs[music_numsongs].mood_num = MusicMood_NameToNum(alias); + music_numsongs++; + } + } + + if (!music_numsongs) { + Com_Printf("MUSIC_LoadSoundtrackFile: could not load %s, no songs defined.\n", path); + FS_FreeFile(data); + return false; + } + + music_currentsong = -1; + FS_FreeFile(data); + + if (music_current_mood == mood_none) { + MUSIC_UpdateMood(mood_normal, mood_normal); + } + + return true; } +/* +============== +MUSIC_SongValid +============== +*/ qboolean MUSIC_SongValid(const char *mood) { - // FIXME: unimplemented - return qfalse; + return MUSIC_FindSong(mood) != -1; } +/* +============== +MUSIC_Loaded +============== +*/ qboolean MUSIC_Loaded() { - // FIXME: unimplemented - return qfalse; + return music_loaded; } +/* +============== +Music_Update +============== +*/ void Music_Update() { - // FIXME: unimplemented + int currentsong; + + if (!s_bSoundStarted) { + return; + } + + if (!music_active) { + return; + } + + if (s_bSoundPaused) { + return; + } + + MUSIC_CheckForStoppedSongs(); + + if (!MUSIC_Loaded() && music_active && strlen(current_soundtrack)) { + MUSIC_LoadSoundtrackFile(current_soundtrack); + music_loaded = true; + } + + if (music_currentsong >= 0) { + currentsong = music_songs[music_currentsong].mood_num; + } else { + currentsong = -1; + } + + if (!music_current_mood) { + if (MUSIC_Playing()) { + MUSIC_StopAllSongs(); + } + } else if (music_current_mood != currentsong) { + const char *mood = MusicMood_NumToName(music_current_mood); + if (MUSIC_SongValid(mood) && MUSIC_Loaded() && strlen(current_soundtrack)) { + Com_DebugPrintf("Playing %s.\n", mood); + MUSIC_PlaySong(mood); + } + } + + if (new_music_volume != music_volume) { + if (music_volume_fade_time > 0) { + if (music_volume_direction == 0) { + music_volume = (cls.realtime - music_volume_start_time) * (new_music_volume - old_music_volume) + / (music_volume_fade_time * 1000.f) + + old_music_volume; + + if (music_volume > new_music_volume) { + music_volume = new_music_volume; + music_volume_changed = 1; + } else { + music_volume_changed = 1; + } + } else if (music_volume_direction == 1) { + music_volume = 1.0 + - (cls.realtime - music_volume_start_time) * (old_music_volume - new_music_volume) + / (music_volume_fade_time * 1000.f); + + if (music_volume >= new_music_volume) { + music_volume_changed = true; + } else { + music_volume = new_music_volume; + music_volume_changed = true; + } + } else { + music_volume_changed = true; + } + } else { + music_volume = new_music_volume; + music_volume_changed = true; + } + } + + MUSIC_UpdateMusicVolumes(); } +/* +============== +MUSIC_SongEnded +============== +*/ void MUSIC_SongEnded() { - // FIXME: unimplemented + Com_DPrintf( + "MUSIC: Song ended, changing from [ %s ] to [ %s ]\n", + MusicMood_NumToName(music_current_mood), + MusicMood_NumToName(music_fallback_mood) + ); + music_current_mood = music_fallback_mood; } +/* +============== +MUSIC_NewSoundtrack +============== +*/ void MUSIC_NewSoundtrack(const char *name) { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + if (!Q_stricmp(name, current_soundtrack)) { + return; + } + + // Fixed in OPM + // Make sure to not get past the end of the buffer + //strcpy(current_soundtrack, name); + Q_strncpyz(current_soundtrack, name, sizeof(current_soundtrack)); + + if (!Q_stricmp(current_soundtrack, "none") || !Q_stricmp(current_soundtrack, "")) { + music_active = qfalse; + if (MUSIC_Playing()) { + MUSIC_StopAllSongs(); + } else { + music_active = qtrue; + MUSIC_LoadSoundtrackFile(name); + music_loaded = qtrue; + } + } } +/* +============== +MUSIC_UpdateMood +============== +*/ void MUSIC_UpdateMood(int current, int fallback) { - // FIXME: unimplemented + static int last_current_mood = -1; + static int last_fallback_mood = -1; + static int current_mood = -1; + static int fallback_mood = -1; + qboolean was_action; + + if (current == current_mood && fallback == fallback_mood) { + return; + } + + was_action = current == last_current_mood && fallback == last_fallback_mood && current_mood == mood_action; + last_current_mood = current_mood; + last_fallback_mood = fallback_mood; + current_mood = current; + music_current_mood = current; + fallback_mood = fallback; + music_fallback_mood = fallback; + music_active = qtrue; + + Com_DPrintf( + "MUSIC: changing from [ %s | %s ] to [ %s | %s ]\n", + MusicMood_NumToName(last_current_mood), + MusicMood_NumToName(last_fallback_mood), + MusicMood_NumToName(current_mood), + MusicMood_NumToName(fallback) + ); + + if (was_action) { + int songnum = MUSIC_FindSong(MusicMood_NumToName(current_mood)); + + if (songnum != -1 && (music_songs[songnum].flags & 4)) { + Com_DPrintf( + "MUSIC: restoring music from action state, skipping [ %s ] for [ %s ]\n", + MusicMood_NumToName(current_mood), + MusicMood_NumToName(fallback_mood) + ); + music_current_mood = music_fallback_mood; + } + } } +/* +============== +MUSIC_UpdateVolume +============== +*/ void MUSIC_UpdateVolume(float volume, float fade_time) { - // FIXME: unimplemented + if (new_music_volume == volume && music_volume_fade_time == fade_time) { + return; + } + + old_music_volume = music_volume; + new_music_volume = volume; + music_volume_fade_time = fade_time; + music_volume_start_time = cls.realtime; + + if (volume > music_volume) { + music_volume_direction = 0; + } else if (volume < music_volume) { + music_volume_direction = 1; + } } +/* +============== +MUSIC_StopAllSongs +============== +*/ void MUSIC_StopAllSongs() { - // FIXME: unimplemented + for (int i = 0; i < MAX_OPENAL_SONGS; i++) { + MUSIC_StopChannel(i); + } + + music_currentsong = -1; } +/* +============== +MUSIC_FreeAllSongs +============== +*/ void MUSIC_FreeAllSongs() { - // FIXME: unimplemented + MUSIC_StopAllSongs(); + MUSIC_UpdateMood(mood_none, mood_none); + current_soundtrack[0] = 0; + music_loaded = false; } +/* +============== +MUSIC_Playing +============== +*/ qboolean MUSIC_Playing() { - // FIXME: unimplemented - return qfalse; + return MUSIC_CurrentSongChannel() != -1; } +/* +============== +MUSIC_FindSong +============== +*/ int MUSIC_FindSong(const char *name) { - // FIXME: unimplemented - return 0; + int i; + + for (i = 0; i < music_numsongs; i++) { + if (!Q_stricmp(music_songs[i].alias, name)) { + return i; + } + } + + return -1; } +/* +============== +S_loadsoundtrack +============== +*/ void S_loadsoundtrack() { - // FIXME: unimplemented + if (Cmd_Argc() != 2) { + Com_Printf("loadsoundtrack \n"); + return; + } + + MUSIC_LoadSoundtrackFile(Cmd_Argv(1)); + music_loaded = true; + Q_strncpyz(current_soundtrack, Cmd_Argv(1), sizeof(current_soundtrack)); } +/* +============== +S_CurrentSoundtrack +============== +*/ const char *S_CurrentSoundtrack() { - // FIXME: unimplemented - return NULL; + return current_soundtrack; } +/* +============== +S_PlaySong +============== +*/ void S_PlaySong() { - // FIXME: unimplemented + if (Cmd_Argc() != 2) { + Com_Printf("playsong \n"); + return; + } + + MUSIC_PlaySong(Cmd_Argv(1)); + music_active = true; } +/* +============== +MUSIC_CurrentSongChannel +============== +*/ int MUSIC_CurrentSongChannel() { - // FIXME: unimplemented - return 0; + int channel_number = -1; + int ch_idx = 0; + + for (ch_idx = 0; ch_idx < MAX_OPENAL_SONGS; ch_idx++) { + if (openal.chan_song[ch_idx].is_playing() && openal.chan_song[ch_idx].song_number == music_currentsong) { + channel_number = ch_idx; + } + } + + return channel_number; } +/* +============== +MUSIC_StopChannel +============== +*/ void MUSIC_StopChannel(int channel_number) { - // FIXME: unimplemented + openal_channel *channel = &openal.chan_song[channel_number]; + + channel->pause(); + if (music_songs[channel->song_number].flags & 2) { + music_songs[channel->song_number].current_pos = 0; + } else { + music_songs[channel->song_number].current_pos = channel->sample_ms_offset(); + } + + channel->stop(); } +/* +============== +MUSIC_PlaySong +============== +*/ qboolean MUSIC_PlaySong(const char *alias) { - // FIXME: unimplemented - return qfalse; + int channel_number; + song_t *song; + int songnum; + int channel_to_play_on; + int fading_song; + openal_channel *song_channel; + unsigned int loop_start; + int rate; + + fading_song = 0; + songnum = MUSIC_FindSong(alias); + + if (songnum == -1) { + return true; + } + + song = &music_songs[songnum]; + + if (MUSIC_Playing() && songnum == music_currentsong) { + return true; + } + + channel_number = MUSIC_CurrentSongChannel(); + music_currentsong = songnum; + + if (channel_number != -1) { + if (song->flags & 4) { + MUSIC_StopChannel(channel_number); + } else { + song_channel = &openal.chan_song[channel_number]; + song_channel->fading = FADE_OUT; + song_channel->fade_time = (int)song->fadetime; + song_channel->fade_start_time = cls.realtime; + fading_song = true; + } + } + channel_to_play_on = (fading_song != 0) && (channel_number == 0); + song_channel = &openal.chan_song[channel_to_play_on]; + + if (song_channel->is_playing() || song_channel->is_paused()) { + MUSIC_StopChannel(channel_to_play_on); + } + + if (!S_OPENAL_LoadMP3(FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), song->path), song_channel)) { + Com_DPrintf("Could not start music file '%s'!", song->path); + return false; + } + + rate = song_channel->sample_playback_rate(); + + song_channel->song_number = songnum; + if (song->current_pos) { + song_channel->set_sample_ms_offset(song->current_pos); + } else { + song_channel->set_sample_offset(rate * 0.063f); + } + + if (song->flags & 1) { + song_channel->set_sample_loop_count(0); + song_channel->set_sample_loop_block(rate * 0.063f, -1); + } else { + song_channel->set_sample_loop_count(1); + } + + if (fading_song) { + song_channel->fading = FADE_IN; + song_channel->fade_time = (int)song->fadetime; + song_channel->set_gain(0.0); + song_channel->fade_start_time = cls.realtime; + } else { + song_channel->fading = FADE_NONE; + song_channel->set_gain(S_GetBaseVolume() * (song->volume * s_ambientVolume->value) * 84.f); + } + + song_channel->play(); + + return true; } +/* +============== +MUSIC_UpdateMusicVolumes +============== +*/ void MUSIC_UpdateMusicVolumes() { - // FIXME: unimplemented + int i; + unsigned int current_time; + float new_volume, max_volume; + + if (s_ambientVolume->modified || music_volume_changed) { + s_ambientVolume->modified = false; + + for (i = 0; i < MAX_OPENAL_SONGS; i++) { + if (!openal.chan_song[i].is_playing() && !openal.chan_song[i].is_paused()) { + continue; + } + + if (openal.chan_song[i].fading != FADE_NONE) { + continue; + } + + openal.chan_song[i].set_gain( + S_GetBaseVolume() * (music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value) + * 84.0 * music_volume + ); + } + } + + for (i = 0; i < MAX_OPENAL_SONGS; i++) { + if (!openal.chan_song[i].is_playing() && !openal.chan_song[i].is_paused()) { + continue; + } + + switch (openal.chan_song[i].fading) { + case fade_t::FADE_IN: + max_volume = music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value; + new_volume = (unsigned int)(cls.realtime - openal.chan_song[i].fade_start_time) + / (openal.chan_song[i].fade_time * 1000.f) * max_volume; + + if (new_volume > max_volume) { + openal.chan_song[i].set_gain(S_GetBaseVolume() * (max_volume * 84.f * music_volume)); + openal.chan_song[i].fading = FADE_NONE; + } else { + openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * 84.f * music_volume)); + } + break; + case fade_t::FADE_OUT: + max_volume = music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value; + new_volume = (unsigned int)(cls.realtime - openal.chan_song[i].fade_start_time) + / (openal.chan_song[i].fade_time * 1000.f) * max_volume; + + if (new_volume > 0) { + openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * 84.f * music_volume)); + } else { + MUSIC_StopChannel(i); + } + break; + default: + break; + } + } + + if (s_musicVolume->modified || music_volume_changed) { + s_musicVolume->modified = false; + if (openal.chan_trig_music.is_playing() || openal.chan_trig_music.is_paused()) { + openal.chan_trig_music.set_gain( + S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * 84.f + ); + } + } + + music_volume_changed = false; } +/* +============== +MUSIC_CheckForStoppedSongs +============== +*/ void MUSIC_CheckForStoppedSongs() { - // FIXME: unimplemented + int i; + + for (i = 0; i < MAX_OPENAL_SONGS; i++) { + if (!openal.chan_song[i].is_playing()) { + continue; + } + + if (openal.chan_song[i].sample_loop_count()) { + continue; + } + + MUSIC_FindSong(MusicMood_NumToName(music_fallback_mood)); + if (!openal.chan_song[i].is_playing() && !openal.chan_song[i].is_paused()) { + MUSIC_SongEnded(); + } + } } +/* +============== +S_TriggeredMusic_SetupHandle +============== +*/ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffset, qboolean autostart) { - // FIXME: unimplemented + char *pszFilename; + const char *pszRealName; + float fVolume = 1.0; + AliasListNode_t *pSoundAlias = NULL; + + if (!s_bSoundStarted) { + return; + } + + if (openal.chan_trig_music.is_playing() || openal.chan_trig_music.is_paused()) { + Com_DPrintf("Didn't start new triggered music because some was already playing\n"); + return; + } + + openal.chan_trig_music.stop(); + // Fixed in OPM + // Use strncpy instead + //strcpy(openal.tm_filename, pszName); + Q_strncpyz(openal.tm_filename, pszName, sizeof(openal.tm_filename)); + + openal.tm_loopcount = iLoopCount; + openal.chan_trig_music.set_sample_loop_count(iLoopCount); + pszRealName = Alias_FindRandom(pszName, &pSoundAlias); + + if (!pszRealName) { + pszRealName = pszName; + } else if (pSoundAlias) { + fVolume = random() * pSoundAlias->volumeMod + pSoundAlias->volume; + } + + pszFilename = FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), pszRealName); + + if (!S_OPENAL_LoadMP3(pszFilename, &openal.chan_trig_music)) { + S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_trig_music); + Com_DPrintf("Could not start triggered music '%s'\n", pszName); + return; + } + + openal.chan_trig_music.fVolume = fVolume; + openal.chan_trig_music.set_gain(S_GetBaseVolume() * (fVolume * s_musicVolume->value) * 84.f); + openal.chan_trig_music.set_sample_loop_count(iLoopCount); + openal.chan_trig_music.set_sample_offset(iOffset); + + if (autostart) { + openal.chan_trig_music.play(); + } } +/* +============== +S_TriggeredMusic_Start +============== +*/ void S_TriggeredMusic_Start() { - // FIXME: unimplemented + if (Cmd_Argc() != 2) { + Com_Printf("tmstart \n"); + return; + } + + S_TriggeredMusic_SetupHandle(Cmd_Argv(1), 1, 0, true); } +/* +============== +S_TriggeredMusic_StartLoop +============== +*/ void S_TriggeredMusic_StartLoop() { - // FIXME: unimplemented + if (Cmd_Argc() != 2) { + Com_Printf("tmstartloop \n"); + return; + } + + S_TriggeredMusic_SetupHandle(Cmd_Argv(1), 0, 0, true); } +/* +============== +S_TriggeredMusic_Stop +============== +*/ void S_TriggeredMusic_Stop() { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + openal.chan_trig_music.stop(); } +/* +============== +S_TriggeredMusic_Pause +============== +*/ void S_TriggeredMusic_Pause() { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + if (openal.chan_trig_music.is_playing()) { + openal.chan_trig_music.pause(); + } } +/* +============== +S_TriggeredMusic_Unpause +============== +*/ void S_TriggeredMusic_Unpause() { - // FIXME: unimplemented + if (!s_bSoundStarted) { + return; + } + + if (openal.chan_trig_music.is_paused()) { + openal.chan_trig_music.play(); + } + + openal.chan_trig_music.set_gain(S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * 84.f); } +/* +============== +S_TriggeredMusic_PlayIntroMusic +============== +*/ void S_TriggeredMusic_PlayIntroMusic() { - // FIXME: unimplemented + S_TriggeredMusic_SetupHandle("sound/music/mus_MainTheme.mp3", 0, 0, true); } +/* +============== +S_StopMovieAudio +============== +*/ void S_StopMovieAudio() { - // FIXME: unimplemented + STUB_DESC("sound stuff."); } +/* +============== +S_SetupMovieAudio +============== +*/ void S_SetupMovieAudio(const char *pszMovieName) { - // FIXME: unimplemented + STUB_DESC("sound stuff"); } +/* +============== +S_CurrentMoviePosition +============== +*/ int S_CurrentMoviePosition() { - // FIXME: unimplemented + STUB_DESC("sound stuff"); return 0; } From 9b63625c2ba6625779d50728466fb58db5466c37 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:27:10 +0100 Subject: [PATCH 0024/2040] Add snd_codec --- code/client/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index af694882..c1761c24 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -32,7 +32,7 @@ if (USE_SOUND_NEW) endif() list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.c$") - file(GLOB_RECURSE SOURCES_CLIENT_SND "./snd_*_new.c*") + file(GLOB_RECURSE SOURCES_CLIENT_SND "./snd_*_new.c*" "./snd_codec*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) endif() From 2629ef17c3a3424d58dc625d78eeab2fca99d64b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:27:20 +0100 Subject: [PATCH 0025/2040] Made snd_codec c++ aware --- code/client/snd_codec.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/client/snd_codec.h b/code/client/snd_codec.h index 49970dff..1ec4b110 100644 --- a/code/client/snd_codec.h +++ b/code/client/snd_codec.h @@ -27,6 +27,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../qcommon/qcommon.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct snd_info_s { int rate; @@ -113,4 +117,8 @@ void S_OggOpus_CodecCloseStream(snd_stream_t *stream); int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); #endif // USE_CODEC_OPUS +#ifdef __cplusplus +} +#endif + #endif // !_SND_CODEC_H_ From 4e8a51db81704d1587c8c8db3fb68cc4d50d86ef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:27:32 +0100 Subject: [PATCH 0026/2040] Fixed Wav not loading properly --- code/client/snd_mem_new.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/code/client/snd_mem_new.c b/code/client/snd_mem_new.c index b9eee6c6..8317fc54 100644 --- a/code/client/snd_mem_new.c +++ b/code/client/snd_mem_new.c @@ -45,11 +45,11 @@ short int GetLittleShort() } val; # ifdef Q3_LITTLE_ENDIAN - val.bytes[1] = data_p[0]; - val.bytes[0] = data_p[1]; -# else val.bytes[0] = data_p[0]; val.bytes[1] = data_p[1]; +# else + val.bytes[0] = data_p[1]; + val.bytes[1] = data_p[0]; # endif data_p += sizeof(short); @@ -69,15 +69,15 @@ int GetLittleLong() } val; # ifdef Q3_LITTLE_ENDIAN - val.bytes[3] = data_p[0]; - val.bytes[2] = data_p[1]; - val.bytes[1] = data_p[2]; - val.bytes[0] = data_p[3]; -# else val.bytes[0] = data_p[0]; val.bytes[1] = data_p[1]; val.bytes[2] = data_p[2]; val.bytes[3] = data_p[3]; +# else + val.bytes[0] = data_p[3]; + val.bytes[1] = data_p[2]; + val.bytes[2] = data_p[1]; + val.bytes[3] = data_p[0]; # endif data_p += sizeof(int); @@ -99,11 +99,11 @@ void SetLittleShort(int i) val.value = i; # ifdef Q3_LITTLE_ENDIAN - data_p[0] = val.bytes[1]; - data_p[1] = val.bytes[0]; -# else data_p[0] = val.bytes[0]; data_p[1] = val.bytes[1]; +# else + data_p[0] = val.bytes[1]; + data_p[1] = val.bytes[0]; # endif data_p += sizeof(short); @@ -124,15 +124,15 @@ void SetLittleLong(int i) val.value = i; # ifdef Q3_LITTLE_ENDIAN - data_p[0] = val.bytes[3]; - data_p[1] = val.bytes[2]; - data_p[2] = val.bytes[1]; - data_p[3] = val.bytes[0]; -# else data_p[0] = val.bytes[0]; data_p[1] = val.bytes[1]; data_p[2] = val.bytes[2]; data_p[3] = val.bytes[3]; +# else + data_p[0] = val.bytes[3]; + data_p[1] = val.bytes[2]; + data_p[2] = val.bytes[1]; + data_p[3] = val.bytes[0]; # endif data_p += sizeof(int); @@ -166,7 +166,7 @@ void FindNextChunk(const char *name) value++; value &= ~1; - last_chunk = data_p + value * 8; + last_chunk = data_p + value + 8; if (!strncmp((const char *)data_p, name, 4u)) { return; } From 3418691f88bc8f45762cc0a18ce873ab9cffe116 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:27:43 +0100 Subject: [PATCH 0027/2040] Added S_NeedFullRestart and S_ReLoad --- code/client/snd_local_new.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 8fcd7e6a..707ecc1e 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -218,6 +218,8 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo void S_PrintInfo(); void S_DumpInfo(); +qboolean S_NeedFullRestart(); +void S_ReLoad(soundsystemsavegame_t* pSave); extern cvar_t *s_show_sounds; From 5ae88b816dc5c1858f8fc1f0fd41f57411c51b58 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:27:56 +0100 Subject: [PATCH 0028/2040] Initialize pSoundAlias to NULL --- code/client/snd_dma_new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index 35c78787..816e6043 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -520,7 +520,7 @@ void S_StartLocalSound(const char *sound_name, qboolean force_load) { sfxHandle_t sfxHandle; const char *name; - AliasListNode_t *pSoundAlias; + AliasListNode_t *pSoundAlias = NULL; if (!s_bSoundStarted) { return; From 187ee87f10fa77564584881746e5bad0bad38017 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:28:13 +0100 Subject: [PATCH 0029/2040] Make sure to initialize new sound system --- code/client/cl_main.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 5f836f81..8d63814e 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -1579,8 +1579,44 @@ void CL_Snd_Restart_f( void ) { S_Shutdown(); S_Init(); #else + qboolean full; + soundsystemsavegame_t save; + char tm_filename[MAX_RES_NAME]; + int tm_loopcount; + int tm_offset; + char current_soundtrack[128]; + + full = S_NeedFullRestart(); + + // + // FIXME: there is a stub function + tm_loopcount = 0; + tm_offset = 0; + // + + SV_ClearSvsTimeFixups(); + + S_SaveData(&save); + strcpy(current_soundtrack, S_CurrentSoundtrack()); + S_Shutdown(qfalse); S_Init(qfalse); + + s_bSoundPaused = true; + + S_LoadData(&save); + + SV_FinishSvsTimeFixups(); + S_ReLoad(&save); + + if (tm_filename[0]) { + S_TriggeredMusic_SetupHandle(tm_filename, tm_loopcount, tm_offset, 0); + } + + MUSIC_NewSoundtrack(current_soundtrack); + if (full) { + CL_Vid_Restart_f(); + } #endif CL_Vid_Restart_f(); @@ -2486,6 +2522,7 @@ void CL_Frame ( int msec ) { && !com_sv_running->integer ) { // if disconnected, bring up the menu S_StopAllSounds2( qtrue ); + S_TriggeredMusic_PlayIntroMusic(); UI_MenuEscape( "main" ); } @@ -3400,6 +3437,8 @@ void CL_Init( void ) { #if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW S_Init2(); +#else + S_Init(qtrue); #endif // fixme: should we leave it? From 1234bd89c7833ca5c712cf47bd7e84204ccc113a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:54:10 +0100 Subject: [PATCH 0030/2040] Fixed wrong configstring for the soundtrack --- code/fgame/g_utils.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/code/fgame/g_utils.cpp b/code/fgame/g_utils.cpp index 7eb27bf1..828271c7 100644 --- a/code/fgame/g_utils.cpp +++ b/code/fgame/g_utils.cpp @@ -1549,22 +1549,20 @@ void RestoreMusicVolume(float fade_time) } void ChangeSoundtrack(const char *soundtrack) - { level.saved_soundtrack = level.current_soundtrack; level.current_soundtrack = soundtrack; - gi.setConfigstring(CS_SOUNDTRACK, soundtrack); + gi.setConfigstring(CS_MUSIC, soundtrack); gi.DPrintf("soundtrack switched to %s.\n", soundtrack); } void RestoreSoundtrack(void) - { if (level.saved_soundtrack.length()) { level.current_soundtrack = level.saved_soundtrack; level.saved_soundtrack = ""; - gi.setConfigstring(CS_SOUNDTRACK, level.current_soundtrack.c_str()); + gi.setConfigstring(CS_MUSIC, level.current_soundtrack.c_str()); gi.DPrintf("soundtrack restored %s.\n", level.current_soundtrack.c_str()); } } From 1fd7bd3fa53e98782c2d09345f226a2ff878a5d0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:54:41 +0100 Subject: [PATCH 0031/2040] Fixed MP3 loading and improperly configured channels --- code/client/snd_openal_new.cpp | 166 +++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 27 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index e86fa40a..c97d34cf 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -26,8 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include "snd_openal_new.h" # include "client.h" # include "../server/server.h" - -# include +# include "snd_codec.h" typedef struct { char *funcname; @@ -53,6 +52,8 @@ cvar_t *s_show_sounds; cvar_t *s_speaker_type; cvar_t *s_obstruction_cal_time; cvar_t *s_lastSoundTime; +// Added in OPM +cvar_t *s_openaldriver; static float reverb_table[] = { 0.5f, 0.25f, 0.417f, 0.653f, 0.208f, 0.5f, 0.403f, 0.5f, 0.5f, @@ -100,9 +101,22 @@ static void S_OPENAL_Pitch(); static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin); static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); +static bool S_OPENAL_LoadMP3_Codec(const char* _path, openal_channel* chan); # define alDieIfError() __alDieIfError(__FILE__, __LINE__) +#if defined(_WIN64) +#define ALDRIVER_DEFAULT "OpenAL64.dll" +#elif defined(_WIN32) +#define ALDRIVER_DEFAULT "OpenAL32.dll" +#elif defined(__APPLE__) +#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" +#elif defined(__OpenBSD__) +#define ALDRIVER_DEFAULT "libopenal.so" +#else +#define ALDRIVER_DEFAULT "libopenal.so.1" +#endif + /* ============== __alDieIfError @@ -242,7 +256,7 @@ static bool S_OPENAL_InitContext() const char *dev; int attrlist[6]; - dev = 0; + dev = NULL; if (s_openaldevice) { dev = s_openaldevice->string; } @@ -316,15 +330,18 @@ S_OPENAL_InitExtensions */ static bool S_OPENAL_InitExtensions() { + Com_Printf("AL extensions ignored\n"); + return true; + extensions_table_t extensions_table[4] = { "alutLoadMP3_LOKI", - (void **)_alutLoadMP3_LOKI, + (void **)&_alutLoadMP3_LOKI, true, "alReverbScale_LOKI", - (void **)_alReverbScale_LOKI, + (void **)&_alReverbScale_LOKI, true, "alReverbDelay_LOKI", - (void **)_alReverbDelay_LOKI, + (void **)&_alReverbDelay_LOKI, true }; extensions_table_t *i; @@ -387,7 +404,7 @@ static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) qalGenSources(1, &chan->source); alDieIfError(); - qalSourcei(chan->source, 514, 1); + qalSourcei(chan->source, AL_SOURCE_RELATIVE, 1); alDieIfError(); return true; @@ -423,6 +440,17 @@ qboolean S_OPENAL_Init() s_show_sounds = Cvar_Get("s_show_sounds", "0", 0); s_speaker_type = Cvar_Get("s_speaker_type", "0", CVAR_ARCHIVE); s_obstruction_cal_time = Cvar_Get("s_obstruction_cal_time", "500", CVAR_ARCHIVE); + // + // Added in OPM + // Initialize the AL driver DLL + s_openaldriver = Cvar_Get("s_openaldriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH | CVAR_PROTECTED); + + if (!QAL_Init(s_openaldriver->string)) { + Com_Printf("Failed to load library: \"%s\".\n", s_openaldriver->string); + if (!Q_stricmp(s_openaldriver->string, ALDRIVER_DEFAULT) || !QAL_Init(ALDRIVER_DEFAULT)) { + return qfalse; + } + } if (!Cvar_Get("s_initsound", "1", 0)->integer) { Com_Printf("OpenAL: s_initsound set to zero...disabling audio.\n"); @@ -461,19 +489,19 @@ qboolean S_OPENAL_Init() } for (i = 0; i < MAX_OPENAL_CHANNELS_2D; i++) { - if (!S_OPENAL_InitChannel(i, &openal.chan_2D[i])) { + if (!S_OPENAL_InitChannel(i + MAX_OPENAL_CHANNELS_3D, &openal.chan_2D[i])) { return false; } } for (i = 0; i < MAX_OPENAL_CHANNELS_2D_STREAM; i++) { - if (!S_OPENAL_InitChannel(i, &openal.chan_2D_stream[i])) { + if (!S_OPENAL_InitChannel(i + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D, &openal.chan_2D_stream[i])) { return false; } } for (i = 0; i < MAX_OPENAL_SONGS; i++) { - if (!S_OPENAL_InitChannel(i, &openal.chan_song[i])) { + if (!S_OPENAL_InitChannel(i + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM, &openal.chan_song[i])) { return false; } } @@ -482,11 +510,11 @@ qboolean S_OPENAL_Init() return false; } - if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_mp3)) { + if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_trig_music)) { return false; } - if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_MOVIE_ID, &openal.chan_mp3)) { + if (!S_OPENAL_InitChannel(OPENAL_CHANNEL_MOVIE_ID, &openal.chan_movie)) { return false; } @@ -504,6 +532,9 @@ qboolean S_OPENAL_Init() s_bProvidersEmunerated = true; al_initialized = true; + // Added in OPM + S_CodecInit(); + return true; } @@ -690,6 +721,8 @@ S_OPENAL_LoadMP3 */ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) { + return S_OPENAL_LoadMP3_Codec(_path, chan); + char path[MAX_QPATH]; FILE *in; size_t len; @@ -2754,7 +2787,7 @@ openal_channel::set_sfx */ bool openal_channel::set_sfx(sfx_t *pSfx) { - ALfloat freq; + ALfloat freq = 0; this->pSfx = pSfx; if (!pSfx->buffer || !qalIsBuffer(pSfx->buffer)) { @@ -2974,7 +3007,7 @@ openal_channel::set_sample_loop_count */ void openal_channel::set_sample_loop_count(S32 count) { - ALuint processed; + ALuint processed = 0; stop(); @@ -3116,16 +3149,18 @@ qboolean MUSIC_LoadSoundtrackFile(const char *filename) "MUSIC_LoadSoundtrackFile: unknown command %s for song %s in %s.\n", args[1], &args[0][1], path ); } - } else if (numargs > 1) { - strcpy(alias, args[0]); - strcpy(file, load_path); - strcat(file, args[1]); } else { - strcpy(file, load_path); - strcat(file, args[1]); + if (numargs > 1) { + strcpy(alias, args[0]); + strcpy(file, load_path); + strcat(file, args[1]); + } else { + strcpy(file, load_path); + strcat(file, args[1]); - strncpy(alias, args[0], strlen(args[0]) - 4); - file[strlen(args[0]) + MAX_RES_NAME * 2 - 4] = 0; + strncpy(alias, args[0], strlen(args[0]) - 4); + file[strlen(args[0]) + MAX_RES_NAME * 2 - 4] = 0; + } if (music_numsongs >= MAX_MUSIC_SONGS) { Com_Printf("MUSIC_LoadSoundtrackFile: Too many songs in %s, skipping %s.\n", path, alias); @@ -3301,11 +3336,11 @@ void MUSIC_NewSoundtrack(const char *name) music_active = qfalse; if (MUSIC_Playing()) { MUSIC_StopAllSongs(); - } else { - music_active = qtrue; - MUSIC_LoadSoundtrackFile(name); - music_loaded = qtrue; } + } else { + music_active = qtrue; + MUSIC_LoadSoundtrackFile(name); + music_loaded = qtrue; } } @@ -3742,7 +3777,8 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs pszFilename = FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), pszRealName); - if (!S_OPENAL_LoadMP3(pszFilename, &openal.chan_trig_music)) { + //if (!S_OPENAL_LoadMP3(pszFilename, &openal.chan_trig_music)) { + if (!S_OPENAL_LoadMP3(pszRealName, &openal.chan_trig_music)) { S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_trig_music); Com_DPrintf("Could not start triggered music '%s'\n", pszName); return; @@ -3877,4 +3913,80 @@ int S_CurrentMoviePosition() return 0; } + +/* +================= +S_AL_Format +================= +*/ +static ALuint S_OPENAL_Format(int width, int channels) +{ + ALuint format = AL_FORMAT_MONO16; + + // Work out format + if (width == 1) + { + if (channels == 1) + format = AL_FORMAT_MONO8; + else if (channels == 2) + format = AL_FORMAT_STEREO8; + } + else if (width == 2) + { + if (channels == 1) + format = AL_FORMAT_MONO16; + else if (channels == 2) + format = AL_FORMAT_STEREO16; + } + + return format; +} + +/* +============== +S_OPENAL_LoadMP3_Codec +============== +*/ +static bool S_OPENAL_LoadMP3_Codec(const char* _path, openal_channel* chan) { + void* data; + snd_info_t info; + ALuint format; + + // Try to load + data = S_CodecLoad(_path, &info); + if (!data) { + return false; + } + + format = S_OPENAL_Format(info.width, info.channels); + + // Create a buffer + qalGenBuffers(1, &chan->buffer); + alDieIfError(); + + // Fill the buffer + if (info.size == 0) + { + // We have no data to buffer, so buffer silence + byte dummyData[2] = { 0 }; + + qalBufferData(chan->buffer, AL_FORMAT_MONO16, (void*)dummyData, 2, 22050); + } + else { + qalBufferData(chan->buffer, format, data, info.size, info.rate); + } + + alDieIfError(); + + // Free the memory + Hunk_FreeTempMemory(data); + + qalSourcei(chan->source, AL_BUFFER, chan->buffer); + alDieIfError(); + + chan->set_no_3d(); + + return true; +} + #endif From ad917d96c8353782f9f43272a7ef6a0d4e00e5dd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:33:07 +0100 Subject: [PATCH 0032/2040] Use roundf() for more clarity --- code/fgame/scriptthread.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index 7146f58b..f4b4a4ca 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -2707,12 +2707,12 @@ void ScriptThread::EventDelayThrow(Event *ev) void ScriptThread::EventWait(Event *ev) { - Wait((int)(ev->GetFloat(1) * 1000.0f + 0.5f)); + Wait((int)roundf(ev->GetFloat(1) * 1000.0f)); } void ScriptThread::EventWaitFrame(Event *ev) { - Wait((int)(level.frametime * 1000.0f + 0.5f)); + Wait((int)roundf(level.frametime * 1000.0f)); } void ScriptThread::EventResume(Event *ev) @@ -4022,7 +4022,7 @@ void ScriptThread::EventDebugInt3(Event *ev) void ScriptThread::EventTimeout(Event *ev) { - Director.maxTime = ev->GetFloat(1) * 1000.0f + 0.5f; + Director.maxTime = roundf(ev->GetFloat(1) * 1000.0f); } void ScriptThread::EventLandmineDamage(Event *ev) @@ -4139,7 +4139,7 @@ void ScriptThread::EventEarthquake(Event *ev) { earthquake_t e; - e.duration = (int)(ev->GetFloat(1) * 1000.0f + 0.5f); + e.duration = (int)roundf(ev->GetFloat(1) * 1000.0f); if (e.duration <= 0) { return; } From 56b2971deecc00d48dc33716cc3963b92d3f7622 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:44:32 +0100 Subject: [PATCH 0033/2040] Fixed AL positioning and volume --- code/client/snd_openal_new.cpp | 195 +++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index c97d34cf..666cfce2 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -101,21 +101,21 @@ static void S_OPENAL_Pitch(); static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin); static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); -static bool S_OPENAL_LoadMP3_Codec(const char* _path, openal_channel* chan); +static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan); # define alDieIfError() __alDieIfError(__FILE__, __LINE__) -#if defined(_WIN64) -#define ALDRIVER_DEFAULT "OpenAL64.dll" -#elif defined(_WIN32) -#define ALDRIVER_DEFAULT "OpenAL32.dll" -#elif defined(__APPLE__) -#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" -#elif defined(__OpenBSD__) -#define ALDRIVER_DEFAULT "libopenal.so" -#else -#define ALDRIVER_DEFAULT "libopenal.so.1" -#endif +# if defined(_WIN64) +# define ALDRIVER_DEFAULT "OpenAL64.dll" +# elif defined(_WIN32) +# define ALDRIVER_DEFAULT "OpenAL32.dll" +# elif defined(__APPLE__) +# define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" +# elif defined(__OpenBSD__) +# define ALDRIVER_DEFAULT "libopenal.so" +# else +# define ALDRIVER_DEFAULT "libopenal.so.1" +# endif /* ============== @@ -404,7 +404,7 @@ static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) qalGenSources(1, &chan->source); alDieIfError(); - qalSourcei(chan->source, AL_SOURCE_RELATIVE, 1); + qalSourcei(chan->source, AL_SOURCE_RELATIVE, true); alDieIfError(); return true; @@ -443,7 +443,7 @@ qboolean S_OPENAL_Init() // // Added in OPM // Initialize the AL driver DLL - s_openaldriver = Cvar_Get("s_openaldriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH | CVAR_PROTECTED); + s_openaldriver = Cvar_Get("s_openaldriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH | CVAR_PROTECTED); if (!QAL_Init(s_openaldriver->string)) { Com_Printf("Failed to load library: \"%s\".\n", s_openaldriver->string); @@ -501,7 +501,10 @@ qboolean S_OPENAL_Init() } for (i = 0; i < MAX_OPENAL_SONGS; i++) { - if (!S_OPENAL_InitChannel(i + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM, &openal.chan_song[i])) { + if (!S_OPENAL_InitChannel( + i + MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D + MAX_OPENAL_CHANNELS_2D_STREAM, + &openal.chan_song[i] + )) { return false; } } @@ -978,7 +981,8 @@ static qboolean S_OPENAL_ShouldStart(const vec3_t vOrigin, float fMinDist, float qalGetListenerfv(AL_POSITION, alvec); - VectorScale(alvec, 52.49f, vListenerOrigin); + //VectorScale(alvec, 52.49f, vListenerOrigin); + VectorCopy(alvec, vListenerOrigin); VectorSubtract(vOrigin, vListenerOrigin, vDir); return Square(fMaxDist) > VectorLengthSquared(vDir); @@ -1340,6 +1344,9 @@ void S_OPENAL_StartSound( pChannel->iEntChannel = iEntChannel; pChannel->iFlags &= ~(CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER); state = pChannel->get_state(); + // Fixed in OPM + // Setup the channel for 3D + pChannel->set_3d(); if (pChannel->iEntNum == iEntNum && (state == AL_PLAYING || state == AL_PAUSED) && pChannel->pSfx == pSfx) { bOnlyUpdate = true; @@ -1381,9 +1388,10 @@ void S_OPENAL_StartSound( pChannel->set_velocity(0, 0, 0); if (iEntNum == ENTITYNUM_NONE) { if (vOrigin) { - pChannel->vOrigin[0] = -vOrigin[0]; - pChannel->vOrigin[1] = vOrigin[2]; - pChannel->vOrigin[2] = -vOrigin[1]; + //pChannel->vOrigin[0] = -vOrigin[0]; + //pChannel->vOrigin[1] = vOrigin[2]; + //pChannel->vOrigin[2] = -vOrigin[1]; + VectorCopy(vOrigin, pChannel->vOrigin); } else { //VectorClear(vOrigin); // Fixed in OPM @@ -1391,17 +1399,22 @@ void S_OPENAL_StartSound( VectorClear(pChannel->vOrigin); } + /* pChannel->set_position( pChannel->vOrigin[0] / 52.49f, pChannel->vOrigin[1] / 52.49f, pChannel->vOrigin[2] / 52.49f ); + */ + pChannel->set_position(pChannel->vOrigin[0], pChannel->vOrigin[1], pChannel->vOrigin[2]); pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = 0; } else { pChannel->iEntNum = iEntNum; if (vOrigin) { - pChannel->vOrigin[0] = -*vOrigin; - pChannel->vOrigin[1] = vOrigin[2]; - pChannel->vOrigin[2] = -vOrigin[1]; + //pChannel->vOrigin[0] = -vOrigin[0]; + //pChannel->vOrigin[1] = vOrigin[2]; + //pChannel->vOrigin[2] = -vOrigin[1]; + VectorCopy(vOrigin, pChannel->vOrigin); + bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; pChannel->iTime = cl.serverTime - 1; if (bSupportWaitTillSoundDone) { @@ -1411,6 +1424,7 @@ void S_OPENAL_StartSound( VectorClear(pChannel->vOrigin); pChannel->iTime = 0; } + pChannel->set_position(pChannel->vOrigin[0], pChannel->vOrigin[1], pChannel->vOrigin[2]); } if (pSfxInfo->loop_start != -1) { @@ -1487,22 +1501,23 @@ void S_OPENAL_AddLoopingSound( return; } - pLoopSound = &openal.loop_sounds[iFreeLoopSound]; - pLoopSound->vOrigin[0] = -vOrigin[0]; - pLoopSound->vOrigin[1] = vOrigin[2]; - pLoopSound->vOrigin[2] = -vOrigin[1]; - pLoopSound->vVelocity[0] = -vVelocity[0] / 52.49f / 500.f; - pLoopSound->vVelocity[1] = vVelocity[2] / 52.49f / 500.f; - pLoopSound->vVelocity[2] = -vVelocity[1] / 52.49f / 500.f; - pLoopSound->pSfx = pSfx; - pLoopSound->bInUse = true; - pLoopSound->iStartTime = cls.realtime; - pLoopSound->fBaseVolume = fVolume; - pLoopSound->fMinDist = fMinDist; - pLoopSound->fMaxDist = fMaxDist; - pLoopSound->fPitch = fPitch; - pLoopSound->iFlags = iFlags; - pLoopSound->bCombine = VectorCompare(vVelocity, vec_zero) == 0; + pLoopSound = &openal.loop_sounds[iFreeLoopSound]; + pLoopSound->vOrigin[0] = -vOrigin[0]; + pLoopSound->vOrigin[1] = vOrigin[2]; + pLoopSound->vOrigin[2] = -vOrigin[1]; + //pLoopSound->vVelocity[0] = -vVelocity[0] / 52.49f / 500.f; + //pLoopSound->vVelocity[1] = vVelocity[2] / 52.49f / 500.f; + //pLoopSound->vVelocity[2] = -vVelocity[1] / 52.49f / 500.f; + VectorCopy(vVelocity, pLoopSound->vVelocity); + pLoopSound->pSfx = pSfx; + pLoopSound->bInUse = true; + pLoopSound->iStartTime = cls.realtime; + pLoopSound->fBaseVolume = fVolume; + pLoopSound->fMinDist = fMinDist; + pLoopSound->fMaxDist = fMaxDist; + pLoopSound->fPitch = fPitch; + pLoopSound->iFlags = iFlags; + pLoopSound->bCombine = VectorCompare(vVelocity, vec_zero) == 0; if (pLoopSound->bCombine) { for (i = 0; i < (MAX_OPENAL_CHANNELS_3D + MAX_OPENAL_CHANNELS_2D); i++) { @@ -1743,10 +1758,14 @@ static int S_OPENAL_Start3DLoopSound( return -1; } + /* pChan3D->set_position(vLoopOrigin[0] / 52.49f, pLoopSound->vVelocity[1] / 52.49f, vLoopOrigin[2] / 52.49f); pChan3D->set_velocity( pLoopSound->vVelocity[0] / 52.49f, vLoopOrigin[1] / 52.49f, pLoopSound->vVelocity[2] / 52.49f ); + */ + pChan3D->set_position(vLoopOrigin[0], pLoopSound->vVelocity[1], vLoopOrigin[2]); + pChan3D->set_velocity(pLoopSound->vVelocity[0], vLoopOrigin[1], pLoopSound->vVelocity[2]); pChan3D->pSfx = pLoopSound->pSfx; pChan3D->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; pChan3D->iBaseRate = pChan3D->sample_playback_rate(); @@ -1827,7 +1846,8 @@ static bool S_OPENAL_UpdateLoopSound( pChannel->set_gain(fVolume); pChannel->set_sample_pan(iPan); } else { - pChannel->set_position(vLoopOrigin[0] / 52.49f, vLoopOrigin[1] / 52.49f, vLoopOrigin[2] / 52.49f); + //pChannel->set_position(vLoopOrigin[0] / 52.49f, vLoopOrigin[1] / 52.49f, vLoopOrigin[2] / 52.49f); + pChannel->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]); pChannel->fVolume = fVolumeToPlay; pChannel->set_gain(fVolumeToPlay); } @@ -1865,7 +1885,7 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) vec3_t alvec; qalGetListenerfv(AL_POSITION, alvec); - VectorScale(alvec, 52.49f, vListenerOrigin); + //VectorScale(alvec, 52.49f, vListenerOrigin); for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) { vec3_t vDir; @@ -2090,9 +2110,10 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi // // Position // - alvec[0] = -vHeadPos[0] / 52.49f; - alvec[1] = vHeadPos[2] / 52.49f; - alvec[2] = -vHeadPos[1] / 52.49f; + //alvec[0] = -vHeadPos[0] / 52.49f; + //alvec[1] = vHeadPos[2] / 52.49f; + //alvec[2] = -vHeadPos[1] / 52.49f; + VectorCopy(vHeadPos, alvec); VectorCopy(alvec, vListenerOrigin); qalListenerfv(AL_POSITION, alvec); alDieIfError(); @@ -2100,18 +2121,27 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi // // Orientation // + /* alorientation[0][0] = -vAxis[0][0]; alorientation[0][1] = vAxis[2][0]; alorientation[0][2] = -vAxis[1][0]; alorientation[1][0] = -vAxis[0][2]; alorientation[1][1] = vAxis[2][2]; alorientation[1][2] = -vAxis[1][2]; + */ + alorientation[0][0] = vAxis[0][0]; + alorientation[0][1] = vAxis[0][1]; + alorientation[0][2] = vAxis[0][2]; + alorientation[1][0] = vAxis[2][0]; + alorientation[1][1] = vAxis[2][1]; + alorientation[1][2] = vAxis[2][2]; qalListenerfv(AL_ORIENTATION, (const ALfloat *)alorientation); alDieIfError(); - vTempAxis[0] = -vAxis[0][1]; - vTempAxis[1] = vAxis[2][1]; - vTempAxis[2] = -vAxis[1][1]; + //vTempAxis[0] = -vAxis[0][1]; + //vTempAxis[1] = vAxis[2][1]; + //vTempAxis[2] = -vAxis[1][1]; + VectorCopy(vAxis[0], vTempAxis); fVolume = 1; iPan = 64; @@ -2141,7 +2171,8 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi fVolume = fMaxVolume; iPan = 64; } else { - pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); } } else { if (i >= MAX_OPENAL_CHANNELS_3D) { @@ -2158,7 +2189,8 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi * fMaxVolume; } } else { - pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); } } } else if (pChannel->iFlags & CHANNEL_FLAG_LOCAL_LISTENER) { @@ -2167,7 +2199,8 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi fVolume = fMaxVolume; iPan = 64; } else { - pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); } } else { if (s_entity[pChannel->iEntNum].time < pChannel->iTime) { @@ -2178,9 +2211,10 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi } } else { VectorCopy(s_entity[pChannel->iEntNum].position, vEntOrigin); - vOrigin[1] = vEntOrigin[2]; - vOrigin[0] = -vEntOrigin[0]; - vOrigin[2] = -vEntOrigin[1]; + //vOrigin[1] = vEntOrigin[2] / 52.49f; + //vOrigin[0] = -vEntOrigin[0] / 52.49f; + //vOrigin[2] = -vEntOrigin[1] / 52.49f; + VectorCopy(vEntOrigin, vOrigin); VectorCopy(vOrigin, pChannel->vOrigin); pChannel->iTime = s_entity[pChannel->iEntNum].time; } @@ -2212,13 +2246,16 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi (1.0 - (fDist - pChannel->fMinDist) / (pChannel->fMaxDist - pChannel->fMinDist)) * fMaxVolume; } } else { - pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); + pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); VectorCopy(s_entity[pChannel->iEntNum].velocity, vEntVelocity); - vVelocity[0] = -vEntVelocity[0] / 52.49f / 500.f; - vVelocity[1] = vEntVelocity[2] / 52.49f / 500.f; - vVelocity[2] = -vEntVelocity[1] / 52.49f / 500.f; - pChannel->set_velocity(vVelocity[0] / 52.49f, vVelocity[1] / 52.49f, vVelocity[2] / 52.49f); + //vVelocity[0] = -vEntVelocity[0] / 52.49f / 500.f; + //vVelocity[1] = vEntVelocity[2] / 52.49f / 500.f; + //vVelocity[2] = -vEntVelocity[1] / 52.49f / 500.f; + VectorCopy(vEntVelocity, vVelocity); + //pChannel->set_velocity(vVelocity[0] / 52.49f, vVelocity[1] / 52.49f, vVelocity[2] / 52.49f); + pChannel->set_velocity(vVelocity[0], vVelocity[1], vVelocity[2]); } } @@ -2676,11 +2713,11 @@ openal_channel::set_3d */ void openal_channel::set_3d() { - qalSourcei(source, AL_SOURCE_RELATIVE, true); + qalSourcei(source, AL_SOURCE_RELATIVE, false); alDieIfError(); qalSourcei(source, AL_LOOPING, false); alDieIfError(); - qalSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + qalSourcef(source, AL_ROLLOFF_FACTOR, 0.019f); alDieIfError(); qalSourcef(source, AL_GAIN, S_GetBaseVolume()); alDieIfError(); @@ -3249,7 +3286,7 @@ void Music_Update() currentsong = -1; } - if (!music_current_mood) { + if (music_current_mood == mood_none) { if (MUSIC_Playing()) { MUSIC_StopAllSongs(); } @@ -3601,7 +3638,8 @@ qboolean MUSIC_PlaySong(const char *alias) MUSIC_StopChannel(channel_to_play_on); } - if (!S_OPENAL_LoadMP3(FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), song->path), song_channel)) { + //if (!S_OPENAL_LoadMP3(FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), song->path), song_channel)) { + if (!S_OPENAL_LoadMP3(song->path, song_channel)) { Com_DPrintf("Could not start music file '%s'!", song->path); return false; } @@ -3913,7 +3951,6 @@ int S_CurrentMoviePosition() return 0; } - /* ================= S_AL_Format @@ -3924,19 +3961,18 @@ static ALuint S_OPENAL_Format(int width, int channels) ALuint format = AL_FORMAT_MONO16; // Work out format - if (width == 1) - { - if (channels == 1) + if (width == 1) { + if (channels == 1) { format = AL_FORMAT_MONO8; - else if (channels == 2) + } else if (channels == 2) { format = AL_FORMAT_STEREO8; - } - else if (width == 2) - { - if (channels == 1) + } + } else if (width == 2) { + if (channels == 1) { format = AL_FORMAT_MONO16; - else if (channels == 2) + } else if (channels == 2) { format = AL_FORMAT_STEREO16; + } } return format; @@ -3947,10 +3983,11 @@ static ALuint S_OPENAL_Format(int width, int channels) S_OPENAL_LoadMP3_Codec ============== */ -static bool S_OPENAL_LoadMP3_Codec(const char* _path, openal_channel* chan) { - void* data; +static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan) +{ + void *data; snd_info_t info; - ALuint format; + ALuint format; // Try to load data = S_CodecLoad(_path, &info); @@ -3965,14 +4002,12 @@ static bool S_OPENAL_LoadMP3_Codec(const char* _path, openal_channel* chan) { alDieIfError(); // Fill the buffer - if (info.size == 0) - { + if (info.size == 0) { // We have no data to buffer, so buffer silence - byte dummyData[2] = { 0 }; + byte dummyData[2] = {0}; - qalBufferData(chan->buffer, AL_FORMAT_MONO16, (void*)dummyData, 2, 22050); - } - else { + qalBufferData(chan->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050); + } else { qalBufferData(chan->buffer, format, data, info.size, info.rate); } From cb9e69238c81f149d0de12149fc1fe7e9cc27732 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 17 Jan 2024 23:15:38 +0100 Subject: [PATCH 0034/2040] Initialize buffer to 0 (integer) --- code/client/snd_mem_new.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_mem_new.c b/code/client/snd_mem_new.c index 8317fc54..13dc44a2 100644 --- a/code/client/snd_mem_new.c +++ b/code/client/snd_mem_new.c @@ -431,7 +431,7 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo char tempName[MAX_RES_NAME + 1]; int realKhz; - sfx->buffer = NULL; + sfx->buffer = 0; if (fileName[0] == '*') { return qfalse; From f1e2a45520e2b7feeaabc9c3675d689828b96938 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:05:57 +0100 Subject: [PATCH 0035/2040] Don't crash if the length is 0 --- code/client/snd_dma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index dd0fbfca..ac0a29f5 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -848,7 +848,11 @@ void S_Base_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_ } if ( !sfx->soundLength ) { - Com_Error( ERR_DROP, "%s has length 0", sfx->soundName ); + // Fixed in OPM + // Why should it crash??? + //Com_Error( ERR_DROP, "%s has length 0", sfx->soundName ); + Com_Printf( "%s has length 0", sfx->soundName ); + return; } VectorCopy( origin, loopSounds[entityNum].origin ); VectorCopy( velocity, loopSounds[entityNum].velocity ); From 9255c5259da8c205c35b4f95c633a5ef661c3683 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:23:41 +0100 Subject: [PATCH 0036/2040] Fixed spawnpoint issues --- code/fgame/g_client.cpp | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/code/fgame/g_client.cpp b/code/fgame/g_client.cpp index c11b7f24..a1020954 100644 --- a/code/fgame/g_client.cpp +++ b/code/fgame/g_client.cpp @@ -578,6 +578,10 @@ Chooses a player start, deathmatch start, etc PlayerStart *SelectSpawnPoint(Player *player) { PlayerStart *spot = NULL; + PlayerStart *spawnpoint; + const char *classID; + int i; + int nFound; switch (g_gametype->integer) { case GT_SINGLE_PLAYER: @@ -602,15 +606,38 @@ PlayerStart *SelectSpawnPoint(Player *player) // find a single player start spot if (!spot) { - while ((spot = (PlayerStart *)G_FindArchivedClass(spot, "info_player_start")) != NULL) { - if (level.spawnpoint.icmp(spot->TargetName()) == 0) { - break; + for (i = 1; i <= level.m_SimpleArchivedEntities.NumObjects(); i++) { + SimpleArchivedEntity *arc = level.m_SimpleArchivedEntities.ObjectAt(i); + + classID = arc->classinfo()->classID; + if (!Q_stricmp(classID, "info_player_start")) { + spawnpoint = static_cast(arc); + if (!str::icmp(level.spawnpoint, spawnpoint->TargetName())) { + spot = spawnpoint; + break; + } } } if (!spot && !level.spawnpoint.length()) { - // there wasn't a spawnpoint without a target, so use any - spot = (PlayerStart *)G_FindArchivedClass(NULL, "info_player_start"); + nFound = 0; + + for (i = 1; i <= level.m_SimpleArchivedEntities.NumObjects(); i++) { + SimpleArchivedEntity *arc = level.m_SimpleArchivedEntities.ObjectAt(i); + + classID = arc->classinfo()->classID; + if (!Q_stricmp(classID, "info_player_start")) { + int randVal; + + spawnpoint = static_cast(arc); + nFound++; + + randVal = rand(); + if (randVal == randVal / nFound * nFound) { + spot = spawnpoint; + } + } + } } if (!spot) { @@ -786,7 +813,7 @@ void G_ClientUserinfoChanged(gentity_t *ent, const char *u) Q_strncpyz(client->pers.userinfo, u, sizeof(client->pers.userinfo)); } -void G_BotConnect(int clientNum, const char* userinfo) +void G_BotConnect(int clientNum, const char *userinfo) { gclient_t *client; gentity_t *ent; From 55582a85abee387b054ecac13a5307bf8ab25f62 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:39:04 +0100 Subject: [PATCH 0037/2040] Fixed entityNum callback --- code/client/snd_openal_new.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 666cfce2..0337eb56 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1166,14 +1166,14 @@ static void S_OPENAL_Start2DSound( "Couldn't play %s sound '%s' for entity %i on channel %s\n", (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "2Dstreamed" : "2D", pSfx->name, - iEntNum & ~S_FLAG_DO_CALLBACK, + iRealEntNum, S_ChannelNumToName(iEntChannel) ); return; } if (iEntNum & S_FLAG_DO_CALLBACK) { - callbackServer(iEntNum, iFreeChannel, pSfx->name); + callbackServer(iRealEntNum, iFreeChannel, pSfx->name); } pChannel = openal.channel[iFreeChannel]; @@ -1207,7 +1207,7 @@ static void S_OPENAL_Start2DSound( pChannel->pSfx = pSfx; pChannel->iEntNum = iRealEntNum; pChannel->iEntChannel = iEntChannel; - if (iEntNum == ENTITYNUM_NONE) { + if (iRealEntNum == ENTITYNUM_NONE) { VectorClear(pChannel->vOrigin); pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = 0; From d9fb37581261048e38a1873324cbcc86336aacd2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Jan 2024 20:46:15 +0100 Subject: [PATCH 0038/2040] Fixed collision issues due to steps --- code/fgame/bg_slidemove.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/code/fgame/bg_slidemove.cpp b/code/fgame/bg_slidemove.cpp index 59e79211..bbdfee39 100644 --- a/code/fgame/bg_slidemove.cpp +++ b/code/fgame/bg_slidemove.cpp @@ -49,7 +49,6 @@ qboolean PM_SlideMove( qboolean gravity ) float d; int numplanes; vec3_t planes[ MAX_CLIP_PLANES ]; - vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; trace_t trace; @@ -61,13 +60,11 @@ qboolean PM_SlideMove( qboolean gravity ) numbumps = 4; - VectorCopy( pm->ps->velocity, primal_velocity ); + VectorCopy( pm->ps->velocity, endVelocity ); if( gravity ) { - VectorCopy( pm->ps->velocity, endVelocity ); endVelocity[ 2 ] -= pm->ps->gravity * pml.frametime; pm->ps->velocity[ 2 ] = ( pm->ps->velocity[ 2 ] + endVelocity[ 2 ] ) * 0.5; - primal_velocity[ 2 ] = endVelocity[ 2 ]; if( pml.groundPlane ) { // slide along the ground plane PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, @@ -113,7 +110,7 @@ qboolean PM_SlideMove( qboolean gravity ) break; // moved the entire distance } - if( ( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) && ( trace.plane.normal[ 2 ] > 0 ) ) + if( ( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) && ( trace.plane.normal[ 2 ] > 0 ) && DotProduct(trace.plane.normal, pm->ps->velocity) <= 0 ) { // treat steep walls as vertical trace.plane.normal[ 2 ] = 0; @@ -301,6 +298,13 @@ void PM_StepSlideMove( qboolean gravity ) down[ 2 ] -= STEPSIZE; pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, qtrue, qfalse ); + if (trace.startsolid) { + // Fixed in OPM + VectorCopy(nostep_o, pm->ps->origin); + VectorCopy(nostep_v, pm->ps->velocity); + return; + } + if( !trace.allsolid ) { if( bWasOnGoodGround && trace.fraction < 1.0 && trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) From 748934edcd35e3bde7506f676a1aabbdffaab81a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Jan 2024 23:30:38 +0100 Subject: [PATCH 0039/2040] Fixed incorrect box in brush testing --- code/qcommon/cm_trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/cm_trace.c b/code/qcommon/cm_trace.c index 9fbc5f34..85b5f4fe 100644 --- a/code/qcommon/cm_trace.c +++ b/code/qcommon/cm_trace.c @@ -183,7 +183,7 @@ void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) { t = DotProduct( plane->normal, sphere.offset ); // adjust the plane distance apropriately for radius - dist = t + plane->dist + sphere.radius; + dist = fabs(t) + plane->dist + sphere.radius; d1 = DotProduct( tw->start, plane->normal ) - dist; // if completely in front of face, no intersection From bff58ae6159d4db10a001d0c2024d68c8eee0b2d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Jan 2024 23:30:48 +0100 Subject: [PATCH 0040/2040] Removed trace.startsolid check --- code/fgame/bg_slidemove.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/code/fgame/bg_slidemove.cpp b/code/fgame/bg_slidemove.cpp index bbdfee39..a90e2a46 100644 --- a/code/fgame/bg_slidemove.cpp +++ b/code/fgame/bg_slidemove.cpp @@ -298,13 +298,6 @@ void PM_StepSlideMove( qboolean gravity ) down[ 2 ] -= STEPSIZE; pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, qtrue, qfalse ); - if (trace.startsolid) { - // Fixed in OPM - VectorCopy(nostep_o, pm->ps->origin); - VectorCopy(nostep_v, pm->ps->velocity); - return; - } - if( !trace.allsolid ) { if( bWasOnGoodGround && trace.fraction < 1.0 && trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) From ac02afaae622d81bd7a2445bfa94aee143a25890 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Jan 2024 23:48:49 +0100 Subject: [PATCH 0041/2040] Don't spam the console with OpenAL errors --- code/client/snd_openal_new.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 0337eb56..8361df5a 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -126,7 +126,9 @@ static void __alDieIfError(const char *file, int line) { ALint alErr = qalGetError(); if (alErr) { - Com_DPrintf("OpenAL error, %s, line %i: [%s].\n", file, line, qalGetString(alErr)); + if (s_show_sounds->integer) { + Com_DPrintf("OpenAL error, %s, line %i: [%s].\n", file, line, qalGetString(alErr)); + } } } From cc048f50991f325cf6c48f036e11368ce1d0d761 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Jan 2024 23:50:15 +0100 Subject: [PATCH 0042/2040] Fixed some sounds being improperly replaced --- code/client/snd_dma_new.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index 816e6043..8458bd18 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -261,6 +261,7 @@ sfx_t *S_FindName(const char *name, int sequenceNumber) Com_Error(ERR_FATAL, "S_FindName: out of sfx_t"); } + sfx = &s_knownSfx[s_numSfx]; s_numSfx++; } From dd378db4d08e0e42558bfca95cb8028f82b572c2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jan 2024 00:08:27 +0100 Subject: [PATCH 0043/2040] Avoid the use of fabs() for dot product --- code/qcommon/cm_trace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/qcommon/cm_trace.c b/code/qcommon/cm_trace.c index 85b5f4fe..10460b29 100644 --- a/code/qcommon/cm_trace.c +++ b/code/qcommon/cm_trace.c @@ -181,9 +181,13 @@ void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) { // find the closest point on the capsule to the plane t = DotProduct( plane->normal, sphere.offset ); + if( t < 0 ) + { + t = -t; + } // adjust the plane distance apropriately for radius - dist = fabs(t) + plane->dist + sphere.radius; + dist = t + plane->dist + sphere.radius; d1 = DotProduct( tw->start, plane->normal ) - dist; // if completely in front of face, no intersection From b8e8aead93c19e7f2cd0e0d3c693ee1a5c4e52cd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:19:15 +0100 Subject: [PATCH 0044/2040] Fixed issues with multiple consecutive dollars This fixes the issue with scripts, like `m6l1c` that accidentally use double dollars for targetnames, like `$$player` --- code/parser/lex_source.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/parser/lex_source.txt b/code/parser/lex_source.txt index 6f3bb3d2..e61c6654 100644 --- a/code/parser/lex_source.txt +++ b/code/parser/lex_source.txt @@ -286,7 +286,7 @@ varname [a-zA-Z0-9_\"]+ "&=" { YYLEX( TOKEN_AND_EQUALS ); } "^=" { YYLEX( TOKEN_EXCL_OR_EQUALS ); } "|=" { YYLEX( TOKEN_OR_EQUALS ); } -"$" { BEGIN( VARIABLES ); YYLEX( TOKEN_DOLLAR ); } +[$]+ { BEGIN( VARIABLES ); YYLEX( TOKEN_DOLLAR ); } "!" { YYLEX( TOKEN_NOT ); } "~" { YYLEX( TOKEN_COMPLEMENT ); } From b6b35079efb9735a3e2b489d01b819ae364b14e4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:53:13 +0100 Subject: [PATCH 0045/2040] Fixed crouch height bounding box --- code/fgame/player.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 5b524fa0..87df5a5f 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -3949,24 +3949,25 @@ void Player::ClientMove(usercmd_t *ucmd) client->ps.pm_flags |= PMF_NO_PREDICTION; client->ps.pm_flags |= PMF_NO_MOVE; } - - /* - if (maxs.z == 60.0f) { - client->ps.pm_flags |= PMF_DUCKED; - } else if (maxs.z == 54.0f) { - client->ps.pm_flags |= PMF_DUCKED | PMF_VIEW_PRONE; - } else if (maxs.z == 20.0f) { - client->ps.pm_flags |= PMF_VIEW_PRONE; - } else if (maxs.z == 53.0f) { - client->ps.pm_flags |= PMF_VIEW_DUCK_RUN; - } else if (viewheight == 52) { - client->ps.pm_flags |= PMF_VIEW_JUMP_START; - } - */ - if (maxs.z == 54.0f || maxs.z == 60.0f) { - client->ps.pm_flags |= PMF_DUCKED; - } else if (viewheight == 52) { - client->ps.pm_flags |= PMF_VIEW_JUMP_START; + + if (g_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + if (maxs.z == 54.0f || maxs.z == 60.0f) { + client->ps.pm_flags |= PMF_DUCKED; + } else if (viewheight == JUMP_START_VIEWHEIGHT) { + client->ps.pm_flags |= PMF_VIEW_JUMP_START; + } + } else { + if (maxs.z == 60.0f) { + client->ps.pm_flags |= PMF_DUCKED; + } else if (maxs.z == 54.0f) { + client->ps.pm_flags |= PMF_DUCKED | PMF_VIEW_PRONE; + } else if (maxs.z == 20.0f) { + client->ps.pm_flags |= PMF_VIEW_PRONE; + } else if (maxs.z == 53.0f) { + client->ps.pm_flags |= PMF_VIEW_DUCK_RUN; + } else if (viewheight == JUMP_START_VIEWHEIGHT) { + client->ps.pm_flags |= PMF_VIEW_JUMP_START; + } } switch (movecontrol) { From ef4b79b1f54b1c889d9d2265c7df4e617236d658 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:53:25 +0100 Subject: [PATCH 0046/2040] Fixed pm_flags being wrong on Allied Assault --- code/qcommon/bg_compat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/qcommon/bg_compat.cpp b/code/qcommon/bg_compat.cpp index e30396d3..d53cd2e2 100644 --- a/code/qcommon/bg_compat.cpp +++ b/code/qcommon/bg_compat.cpp @@ -54,7 +54,7 @@ static uint32_t CPT_NormalizePlayerStateFlags_ver_6(uint32_t flags) { // Convert AA PlayerMove flags to SH/BT flags normalizedFlags |= flags & (1 << 0); - for (size_t i = 2; i < 32; ++i) + for (size_t i = 1; i < 32; ++i) { if (flags & (1 << (i + 2))) { normalizedFlags |= (1 << i); @@ -70,7 +70,7 @@ static uint32_t CPT_DenormalizePlayerStateFlags_ver_6(uint32_t flags) { // Convert AA PlayerMove flags to SH/BT flags normalizedFlags |= flags & (1 << 0); - for (size_t i = 2; i < 32; ++i) + for (size_t i = 1; i < 32; ++i) { if (flags & (1 << i)) { normalizedFlags |= (1 << (i + 2)); From 840501c8dd9f9ddedad907e7f3e33162d2d7c8b2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:04:41 +0100 Subject: [PATCH 0047/2040] Fixed waffenss skin name --- code/client/cl_ui.cpp | 1 + code/client/cl_uiplayermodelpicker.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 56e01306..3b2e6769 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -3333,6 +3333,7 @@ void UI_GetPlayerModel_f(void) Cvar_Set("ui_dm_playergermanmodel_set", pszUIPlayerModel); if (!strncmp(pszUIPlayerModel, "german_waffen_", 14)) { + Q_strncpyz(donotshowssindeorfr, "german_waffenss_", sizeof(donotshowssindeorfr)); Q_strcat(donotshowssindeorfr, sizeof(donotshowssindeorfr), pszUIPlayerModel + 14); Cvar_Set("ui_disp_playergermanmodel", va("models/player/%s.tik", donotshowssindeorfr)); } else { diff --git a/code/client/cl_uiplayermodelpicker.cpp b/code/client/cl_uiplayermodelpicker.cpp index 1ef4e1e5..e7af68a1 100644 --- a/code/client/cl_uiplayermodelpicker.cpp +++ b/code/client/cl_uiplayermodelpicker.cpp @@ -295,7 +295,7 @@ void PlayerModelPickerClass::FileSelected(Event *ev) fullname = PM_DisplaynameToFilename(name); if (!Q_stricmpn(fullname, "german_waffen_", 14)) { - Q_strncpyz(donotshowssindeorfr, "german_waffen_", sizeof(donotshowssindeorfr)); + Q_strncpyz(donotshowssindeorfr, "german_waffenss_", sizeof(donotshowssindeorfr)); Q_strcat(donotshowssindeorfr, sizeof(donotshowssindeorfr), fullname.c_str() + 14); } else { Q_strncpyz(donotshowssindeorfr, fullname, sizeof(donotshowssindeorfr)); From 9ab28dc7da8f6f1db31090678475e236776ca78f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 23 Jan 2024 22:42:27 +0100 Subject: [PATCH 0048/2040] Fixed objective maps appearing twice --- code/client/cl_uimpmappicker.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/code/client/cl_uimpmappicker.cpp b/code/client/cl_uimpmappicker.cpp index 577f9b48..453dbfca 100644 --- a/code/client/cl_uimpmappicker.cpp +++ b/code/client/cl_uimpmappicker.cpp @@ -180,12 +180,14 @@ void MpMapPickerClass::SetupFiles(void) FS_FreeFileList(filenames); } - if (currentDirectory.length()) { - if (currentDirectory == "maps/-/") { - SetupSecondaryFiles(currentDirectory, bTugOfWar, bObjective, bLiberation); - } else { - SetupSecondaryFiles("maps/obj/", bTugOfWar, bObjective, bLiberation); - SetupSecondaryFiles("maps/lib/", bTugOfWar, bObjective, bLiberation); + if (com_target_game->integer > target_game_e::TG_MOH) { + if (currentDirectory.length()) { + if (currentDirectory == "maps/-/") { + SetupSecondaryFiles(currentDirectory, bTugOfWar, bObjective, bLiberation); + } else { + SetupSecondaryFiles("maps/obj/", bTugOfWar, bObjective, bLiberation); + SetupSecondaryFiles("maps/lib/", bTugOfWar, bObjective, bLiberation); + } } } @@ -278,9 +280,9 @@ void MpMapPickerClass::FileSelected(Event *ev) uii.Snd_PlaySound("sound/menu/apply.wav"); - UIListCtrlItem* item = listbox->GetItem(listbox->getCurrentItem()); - str name = item->getListItemString(0); - str directory = item->getListItemString(1); + UIListCtrlItem *item = listbox->GetItem(listbox->getCurrentItem()); + str name = item->getListItemString(0); + str directory = item->getListItemString(1); FileSelected(directory, name, directory + name); } @@ -305,9 +307,9 @@ void MpMapPickerClass::FileChosen(Event *ev) uii.Snd_PlaySound("sound/menu/apply.wav"); - UIListCtrlItem* item = listbox->GetItem(listbox->getCurrentItem()); - str name = item->getListItemString(0); - str directory = item->getListItemString(1); + UIListCtrlItem *item = listbox->GetItem(listbox->getCurrentItem()); + str name = item->getListItemString(0); + str directory = item->getListItemString(1); FileSelected(directory, name, directory + name); } From 92ee1d9caf8f71d5d5fdbcb47add9fc7c783722b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:19:22 +0100 Subject: [PATCH 0049/2040] Reset location print after sending it --- code/server/sv_snapshot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index b319f97e..1abafffe 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -222,6 +222,7 @@ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) { MSG_WriteShort( msg, client->XOffset ); MSG_WriteShort( msg, client->YOffset ); MSG_WriteScrambledString( msg, client->stringToPrint ); + client->locprint = qfalse; } else { MSG_WriteSVC( msg, svc_centerprint ); From 97a0bd90ec8b72ca4de4f8a8ab6937c9bc2cd26b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:37:43 +0100 Subject: [PATCH 0050/2040] Set default values for `sv_invulnerabletime` and `sv_team_spawn_interval` depending on the target protocol --- code/fgame/gamecvars.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/code/fgame/gamecvars.cpp b/code/fgame/gamecvars.cpp index f0fd97d2..e93ce97b 100644 --- a/code/fgame/gamecvars.cpp +++ b/code/fgame/gamecvars.cpp @@ -258,7 +258,7 @@ cvar_t *g_no_seasick; cvar_t *g_aistats; -cvar_t* g_obituarylocation; +cvar_t *g_obituarylocation; cvar_t *sv_scriptfiles; @@ -332,7 +332,7 @@ void CVAR_Init(void) sv_waterspeed = gi.Cvar_Get("sv_waterspeed", "400", 0); sv_cheats = gi.Cvar_Get("cheats", "0", CVAR_USERINFO | CVAR_SERVERINFO | CVAR_LATCH); - sv_fps = gi.Cvar_Get("sv_fps", "20", CVAR_SAVEGAME); + sv_fps = gi.Cvar_Get("sv_fps", "20", CVAR_SAVEGAME); sv_cinematic = gi.Cvar_Get("sv_cinematic", "0", CVAR_ROM); sv_maplist = gi.Cvar_Get("sv_maplist", "", CVAR_ARCHIVE | CVAR_SERVERINFO); @@ -348,8 +348,8 @@ void CVAR_Init(void) sv_sprinttime_dm = gi.Cvar_Get("sv_sprinttime_dm", "5.0", 0); sv_sprintmult_dm = gi.Cvar_Get("sv_sprintmult_dm", "1.20", 0); - if (g_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { - sv_sprinton = gi.Cvar_Get("sv_sprinton", "1", 0); + if (g_target_game >= target_game_e::TG_MOHTA) { + sv_sprinton = gi.Cvar_Get("sv_sprinton", "1", 0); } else { // mohaa doesn't have sprint support sv_sprinton = gi.Cvar_Get("sv_sprinton", "0", 0); @@ -359,8 +359,13 @@ void CVAR_Init(void) gi.cvar_set("sv_runspeed", "250"); } - sv_invulnerabletime = gi.Cvar_Get("sv_invulnerabletime", "3.0", CVAR_ARCHIVE | CVAR_SERVERINFO); - sv_team_spawn_interval = gi.Cvar_Get("sv_team_spawn_interval", "15", CVAR_ARCHIVE | CVAR_SERVERINFO); + if (g_target_game >= target_game_e::TG_MOHTA) { + sv_invulnerabletime = gi.Cvar_Get("sv_invulnerabletime", "3.0", CVAR_ARCHIVE | CVAR_SERVERINFO); + sv_team_spawn_interval = gi.Cvar_Get("sv_team_spawn_interval", "15", CVAR_ARCHIVE | CVAR_SERVERINFO); + } else { + sv_invulnerabletime = gi.Cvar_Get("sv_invulnerabletime", "0", CVAR_ARCHIVE | CVAR_SERVERINFO); + sv_team_spawn_interval = gi.Cvar_Get("sv_team_spawn_interval", "0", CVAR_ARCHIVE | CVAR_SERVERINFO); + } g_showmem = gi.Cvar_Get("g_showmem", "0", 0); g_timeents = gi.Cvar_Get("g_timeents", "0", 0); @@ -461,7 +466,7 @@ void CVAR_Init(void) gi.cvar_set("deathmatch", "1"); } - if (g_protocol >= PROTOCOL_MOHTA_MIN) { + if (g_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { if (gi.Cvar_Get("com_target_game", "", 0)->integer == target_game_e::TG_MOHTT) { // Set the server type to mohaab gi.cvar_set("g_servertype", va("%d", target_game_e::TG_MOHTT)); @@ -591,11 +596,11 @@ void CVAR_Init(void) g_rifles_for_sweepers = gi.Cvar_Get("g_rifles_for_sweepers", "0", 0); g_no_seasick = gi.Cvar_Get("g_no_seasick", "0", 0); - if (g_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { - g_obituarylocation = gi.Cvar_Get("g_obituarylocation", "0", 0); + if (g_target_game >= target_game_e::TG_MOHTA) { + g_obituarylocation = gi.Cvar_Get("g_obituarylocation", "0", 0); } else { // Defaults to 1 on vanilla mohaa - g_obituarylocation = gi.Cvar_Get("g_obituarylocation", "1", 0); + g_obituarylocation = gi.Cvar_Get("g_obituarylocation", "1", 0); } sv_scriptfiles = gi.Cvar_Get("sv_scriptfiles", "0", 0); From 5a447405927cf8383f25c2773cb2f90f99d0d278 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:51:46 +0100 Subject: [PATCH 0051/2040] Fixed invalid event name causing crashes --- code/qcommon/listener.cpp | 70 ++++++++++++++++++++++++++------------- code/qcommon/listener.h | 16 +++++---- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/code/qcommon/listener.cpp b/code/qcommon/listener.cpp index 4f6f4152..d2c1b38e 100644 --- a/code/qcommon/listener.cpp +++ b/code/qcommon/listener.cpp @@ -396,7 +396,7 @@ int HashCode(Event *const& key) template<> int HashCode(const command_t& key) { - const char* p; + const char *p; int hash = 0; for (p = key.command; *p; p++) { @@ -1322,7 +1322,7 @@ void Event::PendingEvents(const char *mask) EVENT_Printf("%d pending events as of %.2f\n", num, EVENT_time); } -bool Event::Exists(const char* command) +bool Event::Exists(const char *command) { return FindEventNum(command) != 0; } @@ -1641,6 +1641,10 @@ Event::Event() data = NULL; dataSize = 0; maxDataSize = 0; + +#ifdef _DEBUG + name = NULL; +#endif } /* @@ -1676,6 +1680,10 @@ Event::Event( maxDataSize = 0; data = NULL; eventnum = 0; + +#ifdef _DEBUG + name = NULL; +#endif } /* @@ -1737,10 +1745,18 @@ Event::Event(Event&& ev) maxDataSize = ev.maxDataSize; data = ev.data; +#ifdef _DEBUG + name = ev.name; +#endif + ev.data = NULL; ev.dataSize = 0; ev.maxDataSize = 0; ev.eventnum = 0; + +#ifdef _DEBUG + ev.name = NULL; +#endif } /* @@ -1881,11 +1897,19 @@ Event& Event::operator=(Event&& ev) maxDataSize = ev.maxDataSize; data = ev.data; +#ifdef _DEBUG + name = ev.name; +#endif + ev.data = NULL; ev.dataSize = 0; ev.maxDataSize = 0; ev.eventnum = 0; +#ifdef _DEBUG + ev.name = NULL; +#endif + return *this; } @@ -2049,10 +2073,10 @@ void Event::AddVector(const Vector& vector) SetValue ======================= */ -void Event::CopyValues(const ScriptVariable* values, size_t count) +void Event::CopyValues(const ScriptVariable *values, size_t count) { assert(count <= maxDataSize); - + for (size_t i = 0; i < count; i++) { data[i] = values[i]; } @@ -2227,16 +2251,16 @@ GetValue */ ScriptVariable& Event::GetValue(void) { - ScriptVariable* tmp; - int i; + ScriptVariable *tmp; + int i; if (fromScript) { // an event method will emit the return value // to the first index of the array // so there is no reallocation if (!data) { - data = new ScriptVariable[1]; - dataSize = 1; + data = new ScriptVariable[1]; + dataSize = 1; maxDataSize = 1; } return data[0]; @@ -3066,7 +3090,7 @@ BroadcastEvent */ bool Listener::BroadcastEvent(const_str name, Event& event) { - ConList* listeners; + ConList *listeners; if (!m_NotifyList) { return false; @@ -3090,10 +3114,10 @@ Broadcast an event to the notify list */ bool Listener::BroadcastEvent(Event& event, ConList *listeners) { - Listener* listener; - int num = listeners->NumObjects(); - int i; - bool found; + Listener *listener; + int num = listeners->NumObjects(); + int i; + bool found; if (!num) { return false; @@ -3151,7 +3175,7 @@ CancelWaiting */ void Listener::CancelWaiting(const_str name) { - ConList* list; + ConList *list; if (!m_WaitForList) { return; @@ -3442,7 +3466,7 @@ void Listener::Unregister(const_str name) } for (int i = stoppedListeners.NumObjects(); i > 0; i--) { - Listener* listener = stoppedListeners.ObjectAt(i); + Listener *listener = stoppedListeners.ObjectAt(i); if (listener && !DisableListenerNotify) { listener->StoppedWaitFor(name, false); @@ -3530,7 +3554,7 @@ UnregisterSource */ bool Listener::UnregisterSource(const_str name, Listener *listener) { - ConList* list; + ConList *list; if (!m_NotifyList) { return false; @@ -3568,7 +3592,7 @@ UnregisterTarget */ bool Listener::UnregisterTarget(const_str name, Listener *listener) { - ConList* list; + ConList *list; if (!m_WaitForList) { return false; @@ -4036,7 +4060,7 @@ ExecuteScriptInternal */ void Listener::ExecuteScriptInternal(Event *ev, ScriptVariable& returnValue) { - ScriptThread* thread = CreateScriptInternal(ev->GetValue(1)); + ScriptThread *thread = CreateScriptInternal(ev->GetValue(1)); thread->ScriptExecute(&ev->data[1], ev->dataSize - 1, returnValue); } @@ -4048,7 +4072,7 @@ ExecuteThreadInternal */ void Listener::ExecuteThreadInternal(Event *ev, ScriptVariable& returnValue) { - ScriptThread* thread = CreateThreadInternal(ev->GetValue(1)); + ScriptThread *thread = CreateThreadInternal(ev->GetValue(1)); thread->ScriptExecute(&ev->data[1], ev->dataSize - 1, returnValue); } @@ -4061,7 +4085,7 @@ WaitExecuteScriptInternal void Listener::WaitExecuteScriptInternal(Event *ev, ScriptVariable& returnValue) { ScriptThread *currentThread = Director.CurrentScriptThread(); - ScriptThread *thread = CreateScriptInternal(ev->GetValue(1)); + ScriptThread *thread = CreateScriptInternal(ev->GetValue(1)); thread->GetScriptClass()->Register(0, currentThread); @@ -4076,7 +4100,7 @@ WaitExecuteThreadInternal void Listener::WaitExecuteThreadInternal(Event *ev, ScriptVariable& returnValue) { ScriptThread *currentThread = Director.CurrentScriptThread(); - ScriptThread *thread = CreateThreadInternal(ev->GetValue(1)); + ScriptThread *thread = CreateThreadInternal(ev->GetValue(1)); thread->Register(0, currentThread); @@ -4131,11 +4155,11 @@ ScriptThread *Listener::CreateThreadInternal(const ScriptVariable& label) { GameScript *scr; ScriptThread *thread = NULL; - ScriptClass* scriptClass; + ScriptClass *scriptClass; if (label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING) { scriptClass = Director.CurrentScriptClass(); - scr = scriptClass->GetScript(); + scr = scriptClass->GetScript(); if (label.GetType() == VARIABLE_CONSTSTRING) { thread = Director.CreateScriptThread(scr, this, label.constStringValue()); diff --git a/code/qcommon/listener.h b/code/qcommon/listener.h index 66d3d77e..ef3b8c12 100644 --- a/code/qcommon/listener.h +++ b/code/qcommon/listener.h @@ -90,7 +90,7 @@ class EventQueueNode; // are parsed. #define EV_REMOVE -9.0f // remove any unused entities before spawnargs are parsed -#define EV_LINKBEAMS -9.0f // for finding out the endpoints of beams +#define EV_LINKBEAMS -9.0f // for finding out the endpoints of beams #define EV_VEHICLE -9.0f #define EV_PRIORITY_SPAWNARG -8.0f // for priority spawn args passed in by the bsp file #define EV_SETUP_ROPEPIECE -8.0f @@ -310,7 +310,7 @@ public: virtual void ErrorInternal(Listener *l, str text) const; - static bool Exists(const char* command); + static bool Exists(const char *command); static unsigned int FindEventNum(const char *s); static unsigned int FindNormalEventNum(const_str s); static unsigned int FindNormalEventNum(str s); @@ -378,7 +378,7 @@ public: void AddTokens(int argc, const char **argv); void AddValue(const ScriptVariable& value); void AddVector(const Vector& vector); - void CopyValues(const ScriptVariable* values, size_t count); + void CopyValues(const ScriptVariable *values, size_t count); void Clear(void); @@ -438,13 +438,17 @@ public: EventQueueNode *next; #ifdef _DEBUG - str name; + const char *name; #endif EventQueueNode() { prev = this; next = this; + +#ifdef _DEBUG + name = NULL; +#endif } Listener *GetSourceObject(void) { return m_sourceobject; } @@ -514,9 +518,9 @@ public: qboolean PostponeAllEvents(float time); qboolean PostponeEvent(Event& ev, float time); - bool ProcessEvent(const Event &ev); + bool ProcessEvent(const Event& ev); bool ProcessEvent(Event *ev); - bool ProcessEvent(Event &ev); + bool ProcessEvent(Event& ev); ScriptVariable& ProcessEventReturn(Event *ev); void ProcessContainerEvent(const Container& conev); From adaeaea59685571046d1f2145b99176e8c7cb53b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jan 2024 19:48:34 +0100 Subject: [PATCH 0052/2040] Fixed other code that makes the game crash when length is 0 --- code/client/snd_dma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index ac0a29f5..584f3c7a 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -785,7 +785,11 @@ void S_Base_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t ve } if ( !sfx->soundLength ) { - Com_Error( ERR_DROP, "%s has length 0", sfx->soundName ); + // Fixed in OPM + // Why should it crash??? + //Com_Error( ERR_DROP, "%s has length 0", sfx->soundName ); + Com_Printf( "%s has length 0", sfx->soundName ); + return; } VectorCopy( origin, loopSounds[entityNum].origin ); From dd768ec9ef54792c80879163bdd35e42b222489a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:54:44 +0100 Subject: [PATCH 0053/2040] Formatted VehicleSoundEntity source files --- code/fgame/VehicleSoundEntity.cpp | 201 +++++++++++++----------------- code/fgame/VehicleSoundEntity.h | 48 ++++--- 2 files changed, 106 insertions(+), 143 deletions(-) diff --git a/code/fgame/VehicleSoundEntity.cpp b/code/fgame/VehicleSoundEntity.cpp index cc3f2c5a..1305fdfc 100644 --- a/code/fgame/VehicleSoundEntity.cpp +++ b/code/fgame/VehicleSoundEntity.cpp @@ -26,159 +26,128 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "vehicle.h" Event EV_VehicleSoundEntity_PostSpawn - ( - "vehiclesoundentity_post", - EV_DEFAULT, - NULL, - NULL, - "PostSpawn of a Vehicle Sound Entity" - ); +( + "vehiclesoundentity_post", + EV_DEFAULT, + NULL, + NULL, + "PostSpawn of a Vehicle Sound Entity" +); Event EV_VehicleSoundEntity_UpdateTraces - ( - "vehiclesoudnentity_updatetraces", - EV_DEFAULT, - NULL, - NULL, - "Updates the traces of a Vehicle Sound Entity" - ); +( + "vehiclesoudnentity_updatetraces", + EV_DEFAULT, + NULL, + NULL, + "Updates the traces of a Vehicle Sound Entity" +); -CLASS_DECLARATION( Entity, VehicleSoundEntity, NULL ) -{ - { &EV_VehicleSoundEntity_PostSpawn, &VehicleSoundEntity::EventPostSpawn }, - { &EV_VehicleSoundEntity_UpdateTraces, &VehicleSoundEntity::EventUpdateTraces }, - { NULL, NULL } +CLASS_DECLARATION(Entity, VehicleSoundEntity, NULL) { + {&EV_VehicleSoundEntity_PostSpawn, &VehicleSoundEntity::EventPostSpawn }, + {&EV_VehicleSoundEntity_UpdateTraces, &VehicleSoundEntity::EventUpdateTraces}, + {NULL, NULL } }; VehicleSoundEntity::VehicleSoundEntity() { - if( LoadingSavegame ) - { - return; - } + if (LoadingSavegame) { + return; + } - gi.Error( ERR_DROP, "VehicleSoundEntity Created with no parameters!\n" ); + gi.Error(ERR_DROP, "VehicleSoundEntity Created with no parameters!\n"); } -VehicleSoundEntity::VehicleSoundEntity( Vehicle *owner ) +VehicleSoundEntity::VehicleSoundEntity(Vehicle *owner) { - m_pVehicle = owner; - m_bDoSoundStuff = false; - m_iTraceSurfaceFlags = 0; + m_pVehicle = owner; + m_bDoSoundStuff = false; + m_iTraceSurfaceFlags = 0; - PostEvent( EV_VehicleSoundEntity_PostSpawn, EV_POSTSPAWN ); + PostEvent(EV_VehicleSoundEntity_PostSpawn, EV_POSTSPAWN); } -void VehicleSoundEntity::Start - ( - void - ) +void VehicleSoundEntity::Start(void) { - m_bDoSoundStuff = true; + m_bDoSoundStuff = true; } -void VehicleSoundEntity::Stop - ( - void - ) +void VehicleSoundEntity::Stop(void) { - m_bDoSoundStuff = false; + m_bDoSoundStuff = false; } -void VehicleSoundEntity::Think - ( - void - ) +void VehicleSoundEntity::Think(void) { - DoSoundStuff(); + DoSoundStuff(); } -void VehicleSoundEntity::EventPostSpawn - ( - Event *ev - ) +void VehicleSoundEntity::EventPostSpawn(Event *ev) { - setModel( "models/vehicles/vehiclesoundentity.tik" ); + setModel("models/vehicles/vehiclesoundentity.tik"); - PostEvent( EV_VehicleSoundEntity_UpdateTraces, 1.0f ); - flags |= FL_THINK; + PostEvent(EV_VehicleSoundEntity_UpdateTraces, 1.0f); + flags |= FL_THINK; } -void VehicleSoundEntity::EventUpdateTraces - ( - Event *ev - ) +void VehicleSoundEntity::EventUpdateTraces(Event *ev) { - if( m_bDoSoundStuff ) - { - m_pVehicle->SetSlotsNonSolid(); + if (m_bDoSoundStuff) { + m_pVehicle->SetSlotsNonSolid(); - trace_t trace = G_Trace( - origin, - vec3_origin, - vec3_origin, - Vector( origin[ 0 ], origin[ 1 ], origin[ 2 ] - 256.0f ), - m_pVehicle->edict, - MASK_SOUND, - qfalse, - "VehicleSoundEntity::DoSoundStuff" - ); + trace_t trace = G_Trace( + origin, + vec3_origin, + vec3_origin, + Vector(origin[0], origin[1], origin[2] - 256.0f), + m_pVehicle->edict, + MASK_SOUND, + qfalse, + "VehicleSoundEntity::DoSoundStuff" + ); - if( trace.fraction >= 1.0f ) - m_iTraceSurfaceFlags = 0; - else - m_iTraceSurfaceFlags = trace.surfaceFlags; + if (trace.fraction >= 1.0f) { + m_iTraceSurfaceFlags = 0; + } else { + m_iTraceSurfaceFlags = trace.surfaceFlags; + } - m_pVehicle->SetSlotsSolid(); - } + m_pVehicle->SetSlotsSolid(); + } - PostEvent( EV_VehicleSoundEntity_UpdateTraces, 1.0f ); + PostEvent(EV_VehicleSoundEntity_UpdateTraces, 1.0f); } -void VehicleSoundEntity::DoSoundStuff - ( - void - ) +void VehicleSoundEntity::DoSoundStuff(void) { - float pitch; + float pitch; - if( !m_bDoSoundStuff ) - { - StopLoopSound(); - return; - } + if (!m_bDoSoundStuff) { + StopLoopSound(); + return; + } - pitch = ( velocity.length() - m_pVehicle->m_fSoundMinSpeed ) / ( m_pVehicle->m_fSoundMaxSpeed - m_pVehicle->m_fSoundMinSpeed ); - if( pitch > 1.0f ) { - pitch = 1.0f; - } else if( pitch < 0.0f ) { - pitch = 0.0f; - } + pitch = (velocity.length() - m_pVehicle->m_fSoundMinSpeed) + / (m_pVehicle->m_fSoundMaxSpeed - m_pVehicle->m_fSoundMinSpeed); + if (pitch > 1.0f) { + pitch = 1.0f; + } else if (pitch < 0.0f) { + pitch = 0.0f; + } - pitch *= m_pVehicle->m_fSoundMinPitch + ( m_pVehicle->m_fSoundMaxPitch - m_pVehicle->m_fSoundMinPitch ); + pitch *= m_pVehicle->m_fSoundMinPitch + (m_pVehicle->m_fSoundMaxPitch - m_pVehicle->m_fSoundMinPitch); - if( m_iTraceSurfaceFlags & SURF_DIRT ) - { - LoopSound( m_pVehicle->m_sSoundSet + "treat_snd_dirt", -1.0f, -1.0f, -1.0f, pitch ); - } - else if( m_iTraceSurfaceFlags & SURF_GRASS ) - { - LoopSound( m_pVehicle->m_sSoundSet + "treat_snd_grass", -1.0f, -1.0f, -1.0f, pitch ); - } - else if( m_iTraceSurfaceFlags & SURF_WOOD ) - { - LoopSound( m_pVehicle->m_sSoundSet + "treat_snd_wood", -1.0f, -1.0f, -1.0f, pitch ); - } - else if( m_iTraceSurfaceFlags & SURF_MUD ) - { - LoopSound( m_pVehicle->m_sSoundSet + "treat_snd_mud", -1.0f, -1.0f, -1.0f, pitch ); - } - else if( m_iTraceSurfaceFlags & ( SURF_GRAVEL | SURF_ROCK ) ) - { - LoopSound( m_pVehicle->m_sSoundSet + "treat_snd_stone", -1.0f, -1.0f, -1.0f, pitch ); - } - else - { - StopLoopSound(); - } + if (m_iTraceSurfaceFlags & SURF_DIRT) { + LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_dirt", -1.0f, -1.0f, -1.0f, pitch); + } else if (m_iTraceSurfaceFlags & SURF_GRASS) { + LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_grass", -1.0f, -1.0f, -1.0f, pitch); + } else if (m_iTraceSurfaceFlags & SURF_WOOD) { + LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_wood", -1.0f, -1.0f, -1.0f, pitch); + } else if (m_iTraceSurfaceFlags & SURF_MUD) { + LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_mud", -1.0f, -1.0f, -1.0f, pitch); + } else if (m_iTraceSurfaceFlags & (SURF_GRAVEL | SURF_ROCK)) { + LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_stone", -1.0f, -1.0f, -1.0f, pitch); + } else { + StopLoopSound(); + } } diff --git a/code/fgame/VehicleSoundEntity.h b/code/fgame/VehicleSoundEntity.h index fa41dc65..2b5c93d5 100644 --- a/code/fgame/VehicleSoundEntity.h +++ b/code/fgame/VehicleSoundEntity.h @@ -21,47 +21,41 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // VehicleSoundEntity.h : Sound helper for vehicles -#ifndef __VEHICLESOUNDENTITY_H__ -#define __VEHICLESOUNDENTITY_H__ +#pragma once #include "entity.h" class Vehicle; -class VehicleSoundEntity : public Entity { +class VehicleSoundEntity : public Entity +{ private: - SafePtr m_pVehicle; - bool m_bDoSoundStuff; - int m_iTraceSurfaceFlags; + SafePtr m_pVehicle; + bool m_bDoSoundStuff; + int m_iTraceSurfaceFlags; public: - CLASS_PROTOTYPE( VehicleSoundEntity ); + CLASS_PROTOTYPE(VehicleSoundEntity); - VehicleSoundEntity(); - VehicleSoundEntity( Vehicle *owner ); + VehicleSoundEntity(); + VehicleSoundEntity(Vehicle *owner); - void Start( void ); - void Stop( void ); - void Think( void ) override; - void Archive( Archiver& arc ) override; + void Start(void); + void Stop(void); + void Think(void) override; + void Archive(Archiver& arc) override; private: - void EventPostSpawn( Event *ev ); - void EventUpdateTraces( Event *ev ); - void DoSoundStuff( void ); + void EventPostSpawn(Event *ev); + void EventUpdateTraces(Event *ev); + void DoSoundStuff(void); }; -inline -void VehicleSoundEntity::Archive - ( - Archiver& arc - ) +inline void VehicleSoundEntity::Archive(Archiver& arc) { - Entity::Archive( arc ); + Entity::Archive(arc); - arc.ArchiveSafePointer( &m_pVehicle ); - arc.ArchiveBool( &m_bDoSoundStuff ); - arc.ArchiveInteger( &m_iTraceSurfaceFlags ); + arc.ArchiveSafePointer(&m_pVehicle); + arc.ArchiveBool(&m_bDoSoundStuff); + arc.ArchiveInteger(&m_iTraceSurfaceFlags); } - -#endif // __VEHICLECOLLISIONENTITY_H__ \ No newline at end of file From 2c441ee541e9880d69956acc623f2c5d5fd94a3d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:55:03 +0100 Subject: [PATCH 0054/2040] Fixed vehicle sound entity using bad sound prefix --- code/fgame/VehicleSoundEntity.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/fgame/VehicleSoundEntity.cpp b/code/fgame/VehicleSoundEntity.cpp index 1305fdfc..284b4094 100644 --- a/code/fgame/VehicleSoundEntity.cpp +++ b/code/fgame/VehicleSoundEntity.cpp @@ -138,15 +138,15 @@ void VehicleSoundEntity::DoSoundStuff(void) pitch *= m_pVehicle->m_fSoundMinPitch + (m_pVehicle->m_fSoundMaxPitch - m_pVehicle->m_fSoundMinPitch); if (m_iTraceSurfaceFlags & SURF_DIRT) { - LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_dirt", -1.0f, -1.0f, -1.0f, pitch); + LoopSound(m_pVehicle->m_sSoundSet + "tread_snd_dirt", -1.0f, -1.0f, -1.0f, pitch); } else if (m_iTraceSurfaceFlags & SURF_GRASS) { - LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_grass", -1.0f, -1.0f, -1.0f, pitch); + LoopSound(m_pVehicle->m_sSoundSet + "tread_snd_grass", -1.0f, -1.0f, -1.0f, pitch); } else if (m_iTraceSurfaceFlags & SURF_WOOD) { - LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_wood", -1.0f, -1.0f, -1.0f, pitch); + LoopSound(m_pVehicle->m_sSoundSet + "tread_snd_wood", -1.0f, -1.0f, -1.0f, pitch); } else if (m_iTraceSurfaceFlags & SURF_MUD) { - LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_mud", -1.0f, -1.0f, -1.0f, pitch); - } else if (m_iTraceSurfaceFlags & (SURF_GRAVEL | SURF_ROCK)) { - LoopSound(m_pVehicle->m_sSoundSet + "treat_snd_stone", -1.0f, -1.0f, -1.0f, pitch); + LoopSound(m_pVehicle->m_sSoundSet + "tread_snd_mud", -1.0f, -1.0f, -1.0f, pitch); + } else if (m_iTraceSurfaceFlags & (SURF_GRAVEL | SURF_ROCK) || m_iTraceSurfaceFlags == 0) { + LoopSound(m_pVehicle->m_sSoundSet + "tread_snd_stone", -1.0f, -1.0f, -1.0f, pitch); } else { StopLoopSound(); } From e209290073dbc7c3c226aace65bbffe83f5d16c7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:55:21 +0100 Subject: [PATCH 0055/2040] Fixed cSpline using wrong positions --- code/fgame/spline.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/fgame/spline.h b/code/fgame/spline.h index aa6ab59b..34be2d74 100644 --- a/code/fgame/spline.h +++ b/code/fgame/spline.h @@ -85,7 +85,7 @@ int cSpline::Add(float *fAdd, int flags) int ii; int insertIndex; - if (m_iPoints + 1 > 512) { + if (m_iPoints + 1 > cPoints) { return -1; } @@ -115,8 +115,8 @@ void cSpline::UniformAdd(float *pos) int i; int ii; - for (i = m_iPoints; i > 0; i--) { - for (ii = 0; ii <= cGrids; ii++) { + for (i = 0; i < m_iPoints; i++) { + for (ii = 0; ii < cGrids; ii++) { m_vPoints[i][ii] += pos[ii]; } } @@ -221,11 +221,11 @@ float *cSpline::GetByNode(float x, int *flags) } } else { if (flags) { - *flags = m_iPointFlags[rp - 1]; + *flags = m_iPointFlags[m_iPoints - 1]; } for (i = 0; i < cGrids; i++) { - r[i] = m_vPoints[rp - 1][i]; + r[i] = m_vPoints[m_iPoints - 1][i]; } } @@ -240,7 +240,7 @@ int cSpline::Append(cSpline *pNew) float fIndexAdd; int i; int ii; - int iFlags; + int iFlags = 0; if (!pNew || pNew->m_iPoints == 0) { return -1; From 946a7a406c2aca889268404bcf430f676e3eee1f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jan 2024 20:45:56 +0100 Subject: [PATCH 0056/2040] Fixed client not quitting when dedicated is set to 1 --- code/qcommon/common.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index cd18527d..75c4971d 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -2161,6 +2161,11 @@ void Com_Frame( void ) { if ( !com_dedicated->integer ) { SV_Shutdown( "dedicated set to 0" ); CL_FlushMemory(); + } else { + CL_Shutdown("dedicated set to 1", qtrue, qtrue); + Sys_CloseMutex(); + Sys_ShowConsole(0, 0); + NET_Init(); } } From 23a866f6f8df3304c84eb8e0da29c936b5c93615 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jan 2024 20:53:17 +0100 Subject: [PATCH 0057/2040] Implemented R_GetInlineModelBounds --- code/renderer/tr_world.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_world.c b/code/renderer/tr_world.c index 7253c812..68b6bf36 100644 --- a/code/renderer/tr_world.c +++ b/code/renderer/tr_world.c @@ -426,7 +426,11 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { void R_GetInlineModelBounds(int iIndex, vec3_t vMins, vec3_t vMaxs) { - // FIXME: unimplemented + bmodel_t* bmodel; + + bmodel = &tr.world->bmodels[iIndex]; + VectorCopy(bmodel->bounds[0], vMins); + VectorCopy(bmodel->bounds[1], vMaxs); } From 9b7f192dce9587f3018b5feb197bfd1b10821549 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jan 2024 21:14:13 +0100 Subject: [PATCH 0058/2040] Corrected marks not working on entities like doors --- code/cgame/cg_marks.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/code/cgame/cg_marks.c b/code/cgame/cg_marks.c index 4c413d1a..33934aa6 100644 --- a/code/cgame/cg_marks.c +++ b/code/cgame/cg_marks.c @@ -191,7 +191,7 @@ int CG_GetMarkFragments( } iNewPoints = 0; - for (j = 0, pFragment = pCurrFragment; j < iNewPoints; j++, pFragment++) { + for (j = 0, pFragment = pCurrFragment; j < iNewFragments; j++, pFragment++) { pFragment->firstPoint += iCurrPoints; pFragment->iIndex = -pEnt->number; iNewPoints += pFragment->numPoints; @@ -219,10 +219,11 @@ static qboolean CG_GetMarkInlineModelOrientation(int iIndex) { } pCEnt = &cg_entities[-iIndex]; - if (pCEnt->currentValid && pCEnt->currentState.modelindex < cgs.inlineDrawModel[ENTITYNUM_NONE]) + if (pCEnt->currentValid && pCEnt->currentState.modelindex < cgs.numInlineModels) { VectorCopy(pCEnt->lerpAngles, cg_vEntAngles); VectorCopy(pCEnt->lerpOrigin, cg_vEntOrigin); + cg_bLastEntValid = qtrue; if (cg_vEntAngles[0] || cg_vEntAngles[1] || cg_vEntAngles[2]) { AngleVectorsLeft(cg_vEntAngles, cg_fEntAxis[0], cg_fEntAxis[1], cg_fEntAxis[2]); @@ -937,15 +938,15 @@ void CG_AddMarks(void) } if (pMark->markPolys->iIndex < 0) { - if (CG_FrustumCullSphere(pMark->pos, pMark->radius)) { - continue; - } - } else { vec3_t vWorldPos; CG_FragmentPosToWorldPos(pMark->pos, vWorldPos); if (CG_FrustumCullSphere(vWorldPos, pMark->radius)) { continue; } + } else { + if (CG_FrustumCullSphere(pMark->pos, pMark->radius)) { + continue; + } } pMark->lastVisTime = cg.time; From ceea855c6f87588c4f46641fa64aa8483f99fb19 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jan 2024 21:26:11 +0100 Subject: [PATCH 0059/2040] Also play Widget motion if there is a fade sequence --- code/uilib/uiwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/uilib/uiwidget.cpp b/code/uilib/uiwidget.cpp index 8a8ac499..1f7afce2 100644 --- a/code/uilib/uiwidget.cpp +++ b/code/uilib/uiwidget.cpp @@ -2423,7 +2423,7 @@ void UIWidget::Display if( !m_enabledCvar.length() && !IsVisible() ) return; - if (m_direction || m_fadetime > 0.0) { + if (m_direction || m_fadetime || m_fadeSequenceState != fadesequence_t::SEQUENCE_NONE) { Motion(); } From 8d188073b46a1018c8f1e49f0aa8a31e6ef900af Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jan 2024 21:26:37 +0100 Subject: [PATCH 0060/2040] When pushing a menu, the max motion time must be taken from the head menu --- code/uilib/uimenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/uilib/uimenu.cpp b/code/uilib/uimenu.cpp index ecc9e316..063b368b 100644 --- a/code/uilib/uimenu.cpp +++ b/code/uilib/uimenu.cpp @@ -697,7 +697,7 @@ bool MenuManager::PushMenu if( head ) { - maxouttime = m->GetMaxMotionTime(); + maxouttime = head->GetMaxMotionTime(); head->ProcessEvent( Event( "hidemenu" ) ); } From eb70b30e7a78cab38c7a19241690c9532fef55df Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 19:40:32 +0100 Subject: [PATCH 0061/2040] Fixed an issue with the lexer (space before thhe dot) --- code/parser/lex_source.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/parser/lex_source.txt b/code/parser/lex_source.txt index e61c6654..bf8c3094 100644 --- a/code/parser/lex_source.txt +++ b/code/parser/lex_source.txt @@ -205,7 +205,7 @@ varname [a-zA-Z0-9_\"]+ "//"[^\r\n]* { if( prev_yylex != TOKEN_EOL ) YYLEX( TOKEN_EOL ); } "size" { BEGIN(INITIAL); YYLEX(TOKEN_SIZE); } -"." { YYLEX(TOKEN_PERIOD); } +[ ]*"." { YYLEX(TOKEN_PERIOD); } \"{string}\" { BEGIN(INITIAL); TextEscapeValue(yytext + 1, strlen( yytext ) - 2 ); YYLEX(TOKEN_STRING); } {varname} { TextValue(yytext, strlen(yytext)); From 0a634c633b8b0088c0152146e372817aa9ea5071 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 19:41:31 +0100 Subject: [PATCH 0062/2040] Fixed crash when loading MP3 in OpenAL --- code/client/snd_openal_new.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 8361df5a..2a1ca925 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2834,7 +2834,8 @@ bool openal_channel::set_sfx(sfx_t *pSfx) qalGenBuffers(1, &pSfx->buffer); alDieIfError(); - if (!_alutLoadMP3_LOKI(pSfx->buffer, pSfx->data, pSfx->length)) { + //if (!_alutLoadMP3_LOKI(pSfx->buffer, pSfx->data, pSfx->length)) { + if (!S_OPENAL_LoadMP3_Codec(pSfx->name, this)) { qalDeleteBuffers(1, &pSfx->buffer); alDieIfError(); From 665c35d089332ff874bc28a1a63aace8e5d8ffba Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:18:09 +0100 Subject: [PATCH 0063/2040] Added TIKI array max values --- code/qcommon/tiki.h | 47 +++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/code/qcommon/tiki.h b/code/qcommon/tiki.h index c1b07304..9e288c3c 100644 --- a/code/qcommon/tiki.h +++ b/code/qcommon/tiki.h @@ -33,6 +33,19 @@ class Archiver; # include "../qcommon/str.h" #endif +#define MAX_TIKI_LOAD_ANIMS 4095 +#define MAX_TIKI_LOAD_SKEL_INDEX 12 +#define MAX_TIKI_LOAD_SERVER_INIT_COMMANDS 160 +#define MAX_TIKI_LOAD_CLIENT_INIT_COMMANDS 180 +#define MAX_TIKI_LOAD_HEADMODELS_LENGTH 4096 +#define MAX_TIKI_LOAD_HEADSKINS_LENGTH 4096 +#define MAX_TIKI_LOAD_MODEL_BUFFER 8192 + +#define MAX_TIKI_LOAD_FRAME_SERVER_COMMANDS 32 +#define MAX_TIKI_LOAD_FRAME_CLIENT_COMMANDS 128 + +#define MAX_TIKI_LOAD_SHADERS 4 + typedef struct AliasList_s AliasList_t; typedef struct AliasListNode_s AliasListNode_t; typedef struct msg_s msg_t; @@ -42,7 +55,7 @@ typedef struct { } tikiTriangle_t; typedef struct { - float st[2]; + vec2_t st; } tikiSt_t; typedef struct { @@ -51,8 +64,8 @@ typedef struct { } tikiXyzNormal_t; typedef struct { - float origin[3]; - float axis[3][3]; + vec3_t origin; + vec3_t axis[3]; } tikiTagData_t; typedef struct { @@ -81,7 +94,7 @@ typedef struct { int frame_num; int num_args; char **args; - char location[256]; + char location[MAX_QPATH]; } dloadframecmd_t; typedef struct { @@ -90,8 +103,8 @@ typedef struct { } dloadinitcmd_t; typedef struct { - char name[32]; - char shader[4][64]; + char name[MAX_NAME_LENGTH]; + char shader[MAX_TIKI_LOAD_SHADERS][MAX_RES_NAME]; int numskins; int flags; float damage_multiplier; @@ -99,15 +112,15 @@ typedef struct { typedef struct { char *alias; - char name[128]; - char location[256]; + char name[MAX_QPATH]; + char location[MAX_QPATH]; float weight; float blendtime; int flags; int num_client_cmds; int num_server_cmds; - dloadframecmd_t *loadservercmds[32]; - dloadframecmd_t *loadclientcmds[128]; + dloadframecmd_t *loadservercmds[MAX_TIKI_LOAD_FRAME_SERVER_COMMANDS]; + dloadframecmd_t *loadclientcmds[MAX_TIKI_LOAD_FRAME_CLIENT_COMMANDS]; } dloadanim_t; typedef struct dloaddef_s dloaddef_t; @@ -120,21 +133,21 @@ typedef struct dloaddef_s { const char *path; class TikiScript tikiFile; - dloadanim_t *loadanims[4095]; - dloadinitcmd_t *loadserverinitcmds[160]; - dloadinitcmd_t *loadclientinitcmds[160]; + dloadanim_t *loadanims[MAX_TIKI_LOAD_ANIMS]; + dloadinitcmd_t *loadserverinitcmds[MAX_TIKI_LOAD_SERVER_INIT_COMMANDS]; + dloadinitcmd_t *loadclientinitcmds[MAX_TIKI_LOAD_CLIENT_INIT_COMMANDS]; - int skelIndex_ld[12]; + int skelIndex_ld[MAX_TIKI_LOAD_SKEL_INDEX]; int numanims; int numserverinitcmds; int numclientinitcmds; - char headmodels[4096]; - char headskins[4096]; + char headmodels[MAX_TIKI_LOAD_HEADMODELS_LENGTH]; + char headskins[MAX_TIKI_LOAD_HEADSKINS_LENGTH]; qboolean bIsCharacter; struct msg_s *modelBuf; - unsigned char modelData[8192]; + unsigned char modelData[MAX_TIKI_LOAD_MODEL_BUFFER]; qboolean bInIncludesSection; } dloaddef_t; From 4a66a41f910fa4e30792a471d4ae0bcf080aa045 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:19:14 +0100 Subject: [PATCH 0064/2040] Added idle skel and number of skeletons --- code/qcommon/tiki.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/qcommon/tiki.h b/code/qcommon/tiki.h index 9e288c3c..194e9b13 100644 --- a/code/qcommon/tiki.h +++ b/code/qcommon/tiki.h @@ -36,7 +36,7 @@ class Archiver; #define MAX_TIKI_LOAD_ANIMS 4095 #define MAX_TIKI_LOAD_SKEL_INDEX 12 #define MAX_TIKI_LOAD_SERVER_INIT_COMMANDS 160 -#define MAX_TIKI_LOAD_CLIENT_INIT_COMMANDS 180 +#define MAX_TIKI_LOAD_CLIENT_INIT_COMMANDS 180 // 2.30: Increased from 160 to 180 #define MAX_TIKI_LOAD_HEADMODELS_LENGTH 4096 #define MAX_TIKI_LOAD_HEADSKINS_LENGTH 4096 #define MAX_TIKI_LOAD_MODEL_BUFFER 8192 @@ -150,6 +150,13 @@ typedef struct dloaddef_s { unsigned char modelData[MAX_TIKI_LOAD_MODEL_BUFFER]; qboolean bInIncludesSection; + + // Added in 2.0 + //==== + char idleSkel[MAX_QPATH]; + int numskels; + qboolean hasSkel; + //==== } dloaddef_t; #endif From cb9ac23b23dc1f5e056fc92a66512a6c9b92341e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:23:05 +0100 Subject: [PATCH 0065/2040] Added TIKI_AllocAnim --- code/tiki/tiki_parse.cpp | 16 ++++++++++++++++ code/tiki/tiki_parse.h | 19 ++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index e11b2ad1..106fbd21 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -353,6 +353,22 @@ qboolean TIKI_ParseIncludes(dloaddef_t *ld) return false; } +dloadanim_t *TIKI_AllocAnim(dloaddef_t *ld) +{ + dloadanim_t *panim; + + panim = static_cast(TIKI_AllocateLoadData(sizeof(dloadanim_t))); + panim->weight = 1.f; + panim->location[0] = 0; + panim->num_client_cmds = 0; + panim->num_server_cmds = 0; + panim->flags = 0; + panim->blendtime = 0.2f; + ld->loadanims[ld->numanims++] = panim; + + return panim; +} + /* =============== TIKI_ParseAnimations diff --git a/code/tiki/tiki_parse.h b/code/tiki/tiki_parse.h index b3829ca0..5babdef7 100644 --- a/code/tiki/tiki_parse.h +++ b/code/tiki/tiki_parse.h @@ -26,15 +26,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA extern "C" { #endif - const char *TIKI_FileExtension(const char *in); - void TIKI_ParseFrameCommands(dloaddef_t *ld, dloadframecmd_t **cmdlist, int maxcmds, int *numcmds); - void TIKI_ParseAnimationCommands(dloaddef_t *ld, dloadanim_t *anim); - void TIKI_ParseAnimationFlags(dloaddef_t *ld, dloadanim_t *anim); - void TIKI_ParseAnimationsFail(dloaddef_t *ld); - qboolean TIKI_ParseIncludes(dloaddef_t *ld); - void TIKI_ParseAnimations(dloaddef_t *ld); - int TIKI_ParseSurfaceFlag(const char *token); - void TIKI_InitSetup(dloaddef_t *ld); + const char *TIKI_FileExtension(const char *in); + void TIKI_ParseFrameCommands(dloaddef_t *ld, dloadframecmd_t **cmdlist, int maxcmds, int *numcmds); + void TIKI_ParseAnimationCommands(dloaddef_t *ld, dloadanim_t *anim); + void TIKI_ParseAnimationFlags(dloaddef_t *ld, dloadanim_t *anim); + void TIKI_ParseAnimationsFail(dloaddef_t *ld); + qboolean TIKI_ParseIncludes(dloaddef_t *ld); + void TIKI_ParseAnimations(dloaddef_t *ld); + int TIKI_ParseSurfaceFlag(const char *token); + void TIKI_InitSetup(dloaddef_t *ld); + dloadanim_t *TIKI_AllocAnim(dloaddef_t *ld); #ifdef __cplusplus qboolean TIKI_LoadSetupCaseHeader( From 7eca455795caf0980f14b7a03a59ffdb251774b2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:24:04 +0100 Subject: [PATCH 0066/2040] Set the idle skelmodel and increase the number of skels --- code/tiki/tiki_parse.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index 106fbd21..c5ca72d3 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -555,6 +555,9 @@ static void WriteSkelmodel(dloaddef_t *ld, const char *name) { MSG_WriteByte(ld->modelBuf, 3); MSG_WriteString(ld->modelBuf, name); + + Q_strncpyz(ld->idleSkel, name, sizeof(ld->idleSkel)); + ld->numskels++; } /* From c4a9a87929fbf0baee1a480567dde64d8ff10949 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:24:17 +0100 Subject: [PATCH 0067/2040] Added TIKI_AddDefaultIdleAnim --- code/tiki/tiki_files.cpp | 47 ++++++++++++++++++++++++++++++++++++++++ code/tiki/tiki_files.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 71a50f0d..43ef4db8 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -93,6 +93,52 @@ void *TIKI_AllocateLoadData(size_t length) return TIKI_allocator.Alloc(length); } +/* +=============== +TIKI_AliasExists +=============== +*/ +qboolean TIKI_AliasExists(dloaddef_t* ld, const char* name) { + int i; + + for (i = 0; i < ld->numanims; i++) { + if (!Q_stricmp(ld->loadanims[i]->alias, name)) { + return true; + } + } + + return false; +} + +/* +=============== +TIKI_AddDefaultIdleAnim +=============== +*/ +void TIKI_AddDefaultIdleAnim(dloaddef_t* ld) { + const char* ext; + dloadanim_t* panim; + + if (ld->numskels != 1) { + return; + } + + ext = strstr(ld->idleSkel, "."); + if (!ext) { + return; + } + + if (TIKI_AliasExists(ld, "idle")) { + return; + } + + panim = TIKI_AllocAnim(ld); + panim->alias = TIKI_CopyString("idle"); + Q_strncpyz(panim->name, ld->idleSkel, ext - ld->idleSkel); + panim->name[ext - ld->idleSkel] = 0; + Q_strcat(panim->name, sizeof(panim->name), ".skc"); +} + /* =============== TIKI_CopyString @@ -190,6 +236,7 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) TIKI_Error("TIKI_LoadTIKIfile: Include section in %s did not terminate\n", loaddef.tikiFile.Filename()); } + TIKI_AddDefaultIdleAnim(&loaddef); if (loaddef.numanims) { sprintf(tempName, "a%s", path); UI_LoadResource(tempName); diff --git a/code/tiki/tiki_files.h b/code/tiki/tiki_files.h index 7126f80a..518d0f88 100644 --- a/code/tiki/tiki_files.h +++ b/code/tiki/tiki_files.h @@ -41,6 +41,8 @@ extern "C" { void TIKI_FreeStorage(dloaddef_t *ld); void *TIKI_AllocateLoadData(size_t length); + qboolean TIKI_AliasExists(dloaddef_t* ld, const char* name); + void TIKI_AddDefaultIdleAnim(dloaddef_t* ld); char *TIKI_CopyString(const char *s); dtikianim_t *TIKI_LoadTikiAnim(const char *path); From 3f8aeac7e67747c4b5b2847fb0e6889d5ba2d538 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:27:58 +0100 Subject: [PATCH 0068/2040] Exported WriteSkelmodel --- code/tiki/tiki_parse.cpp | 2 +- code/tiki/tiki_parse.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index c5ca72d3..1fe94eed 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -551,7 +551,7 @@ static void WriteLodBias(dloaddef_t *ld, float lod_bias) WriteSkelmodel =============== */ -static void WriteSkelmodel(dloaddef_t *ld, const char *name) +void WriteSkelmodel(dloaddef_t *ld, const char *name) { MSG_WriteByte(ld->modelBuf, 3); MSG_WriteString(ld->modelBuf, name); diff --git a/code/tiki/tiki_parse.h b/code/tiki/tiki_parse.h index 5babdef7..1db2634f 100644 --- a/code/tiki/tiki_parse.h +++ b/code/tiki/tiki_parse.h @@ -76,3 +76,5 @@ extern "C" { #ifdef __cplusplus } #endif + +void WriteSkelmodel(dloaddef_t* ld, const char* name); From 7518d7b41818fa22fd7ad090d5ea38d4fe44472a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:41:17 +0100 Subject: [PATCH 0069/2040] Reworked FS_CanonicalFilename --- code/qcommon/files.cpp | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/code/qcommon/files.cpp b/code/qcommon/files.cpp index bbf734f5..595c6a1a 100644 --- a/code/qcommon/files.cpp +++ b/code/qcommon/files.cpp @@ -4374,23 +4374,41 @@ FS_CanonicalFilename */ void FS_CanonicalFilename(char* filename) { - char* p = filename; + char* source; + char* dest; - while (*p) + dest = filename; + + for(source = filename; *source; source++) { - if (p[0] == '/' && p[1] == '/') - { - char* p2 = p + 1; + switch (*source) { + case '\t': + case ' ': + break; + case '\n': + case '\r': + *filename = 0; + break; + case '/': + case '\\': + if (dest == filename) { + *filename = 0; + return; + } - while (*p2) - { - p2[0] = p2[1]; - p2++; - } - } - - p++; + if (*(dest - 1) != '/') { + *dest = '/'; + dest++; + } + break; + default: + *dest = tolower(*source); + dest++; + break; + } } + + *dest = 0; } void FS_FileTime(const char* filename, char* date, char* size) { From bca71ade85ac651bf2d408d308c115574107666f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:16:47 +0100 Subject: [PATCH 0070/2040] Added automatic addition of idle animation when there is none (from 2.30 code) --- code/tiki/tiki_files.cpp | 78 +++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 43ef4db8..b9d2816e 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -98,7 +98,8 @@ void *TIKI_AllocateLoadData(size_t length) TIKI_AliasExists =============== */ -qboolean TIKI_AliasExists(dloaddef_t* ld, const char* name) { +qboolean TIKI_AliasExists(dloaddef_t *ld, const char *name) +{ int i; for (i = 0; i < ld->numanims; i++) { @@ -115,9 +116,10 @@ qboolean TIKI_AliasExists(dloaddef_t* ld, const char* name) { TIKI_AddDefaultIdleAnim =============== */ -void TIKI_AddDefaultIdleAnim(dloaddef_t* ld) { - const char* ext; - dloadanim_t* panim; +void TIKI_AddDefaultIdleAnim(dloaddef_t *ld) +{ + const char *ext; + dloadanim_t *panim; if (ld->numskels != 1) { return; @@ -132,9 +134,9 @@ void TIKI_AddDefaultIdleAnim(dloaddef_t* ld) { return; } - panim = TIKI_AllocAnim(ld); + panim = TIKI_AllocAnim(ld); panim->alias = TIKI_CopyString("idle"); - Q_strncpyz(panim->name, ld->idleSkel, ext - ld->idleSkel); + Q_strncpyz(panim->name, ld->idleSkel, ext - ld->idleSkel + 1); panim->name[ext - ld->idleSkel] = 0; Q_strcat(panim->name, sizeof(panim->name), ".skc"); } @@ -167,12 +169,18 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) msg_t modelBuf; str s; char tempName[257]; + const char *ext; memset(&loaddef, 0, sizeof(dloaddef_t)); loaddef.modelBuf = &modelBuf; TIKI_InitSetup(&loaddef); + loaddef.path = path; + loaddef.numanims = 0; + loaddef.numserverinitcmds = 0; + loaddef.numclientinitcmds = 0; + if (loaddef.tikiFile.LoadFile(path, qfalse)) { loaddef.path = path; @@ -235,37 +243,49 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) if (loaddef.bInIncludesSection) { TIKI_Error("TIKI_LoadTIKIfile: Include section in %s did not terminate\n", loaddef.tikiFile.Filename()); } + } else { + loaddef.tikiFile.Close(); - TIKI_AddDefaultIdleAnim(&loaddef); - if (loaddef.numanims) { - sprintf(tempName, "a%s", path); + ext = strstr(path, "."); + if (!ext) { + return false; + } + + Q_strncpyz(tempName, path, ext - path + 1); + tempName[ext - path] = 0; + Q_strcat(tempName, sizeof(tempName), ".skd"); + WriteSkelmodel(&loaddef, tempName); + + loaddef.hasSkel = true; + } + + TIKI_AddDefaultIdleAnim(&loaddef); + if (loaddef.numanims) { + sprintf(tempName, "a%s", path); + UI_LoadResource(tempName); + + tiki = TIKI_FillTIKIStructureSkel(&loaddef); + if (tiki) { + sprintf(tempName, "b%s", path); + UI_LoadResource(tempName); + sprintf(tempName, "c%s", path); UI_LoadResource(tempName); - tiki = TIKI_FillTIKIStructureSkel(&loaddef); - if (tiki) { - sprintf(tempName, "b%s", path); - UI_LoadResource(tempName); - sprintf(tempName, "c%s", path); - UI_LoadResource(tempName); - - VectorSubtract(tiki->maxs, tiki->mins, tempVec); - if (VectorLength(tempVec) > 100000.0f) { - VectorSet(tiki->mins, -4.0f, -4.0f, -4.0f); - VectorSet(tiki->maxs, 4.0f, 4.0f, 4.0f); - } - - TIKI_FreeStorage(&loaddef); - sprintf(tempName, "d%s", path); - UI_LoadResource(tempName); - } else { - TIKI_FreeStorage(&loaddef); + VectorSubtract(tiki->maxs, tiki->mins, tempVec); + if (VectorLength(tempVec) > 100000.0f) { + VectorSet(tiki->mins, -4.0f, -4.0f, -4.0f); + VectorSet(tiki->maxs, 4.0f, 4.0f, 4.0f); } + + TIKI_FreeStorage(&loaddef); + sprintf(tempName, "d%s", path); + UI_LoadResource(tempName); } else { - TIKI_Error("TIKI_LoadTIKIfile: No valid animations found in %s.\n", loaddef.tikiFile.Filename()); TIKI_FreeStorage(&loaddef); } } else { - loaddef.tikiFile.Close(); + TIKI_Error("TIKI_LoadTIKIfile: No valid animations found in %s.\n", loaddef.tikiFile.Filename()); + TIKI_FreeStorage(&loaddef); } return tiki; From d8505eff2be173d798f8ad647ce718aa4d114b58 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:17:00 +0100 Subject: [PATCH 0071/2040] Fixed label parameters being incorrectly case-sensitive --- code/script/scriptcompiler.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index 49b80eea..26726266 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -910,14 +910,18 @@ void ScriptCompiler::EmitOpcode(int opcode, unsigned int sourcePos) void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) { + str name_lowered; + if (lhs.node[0].type != ENUM_field) { CompileError(sourcePos, "bad parameter lvalue: %d (expecting field)", lhs.node[0].type); } sval_u listener_val = lhs.node[1]; const char *name = lhs.node[2].stringValue; + name_lowered = name; + name_lowered.tolower(); - int eventnum = Event::FindSetterEventNum(name); + int eventnum = Event::FindSetterEventNum(name_lowered); if (listener_val.node[0].type != ENUM_listener || (eventnum && BuiltinWriteVariable(sourcePos, listener_val.node[1].byteValue, eventnum))) { @@ -926,7 +930,7 @@ void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) EmitOpcode(OP_STORE_PARAM, sourcePos); EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].byteValue, sourcePos); - unsigned int index = Director.AddString(name); + unsigned int index = Director.AddString(name_lowered); EmitOpcodeValue(index, sizeof(unsigned int)); } } From 24dbc1ce4efa882424c13de82e0de8dab986bc59 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:29:56 +0100 Subject: [PATCH 0072/2040] Use C vectors --- code/fgame/scriptthread.cpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index f4b4a4ca..f8dde9ad 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -3523,31 +3523,46 @@ void ScriptThread::Vector_CrossProduct(Event *ev) void ScriptThread::Vector_ToAngles(Event *ev) { - ev->AddVector(ev->GetVector(1).toAngles()); + Vector v1; + Vector v3; + + v1 = ev->GetVector(1); + vectoangles(v1, v3); + + ev->AddVector(v3); } void ScriptThread::Angles_ToForward(Event *ev) { - Vector fwd; + Vector v1; + Vector v3; - ev->GetVector(1).AngleVectors(&fwd); - ev->AddVector(fwd); + v1 = ev->GetVector(1); + + AngleVectors(v1, v3, NULL, NULL); + ev->AddVector(v3); } void ScriptThread::Angles_ToLeft(Event *ev) { - Vector left; + Vector v1; + Vector v3; - ev->GetVector(1).AngleVectors(NULL, &left); - ev->AddVector(left); + v1 = ev->GetVector(1); + + AngleVectors(v1, NULL, v3, NULL); + ev->AddVector(v3); } void ScriptThread::Angles_ToUp(Event *ev) { - Vector up; + Vector v1; + Vector v3; - ev->GetVector(1).AngleVectors(NULL, NULL, &up); - ev->AddVector(up); + v1 = ev->GetVector(1); + + AngleVectors(v1, NULL, NULL, v3); + ev->AddVector(v3); } void ScriptThread::Angles_PointAt(Event *ev) From f83839e01bf7532e9b4c658949fb63e920ab01f6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:32:43 +0100 Subject: [PATCH 0073/2040] Fixed crash with WhatIs command if the entity doesn't have a model --- code/fgame/player_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player_util.cpp b/code/fgame/player_util.cpp index aaf043e4..a04510d2 100644 --- a/code/fgame/player_util.cpp +++ b/code/fgame/player_util.cpp @@ -94,7 +94,7 @@ void Player::WhatIs(Event *ev) const char *animname; animname = NULL; - if (gi.modeltiki(ent->model)) { + if (ent->edict->tiki) { animname = gi.Anim_NameForNum(ent->edict->tiki, ent->edict->s.frameInfo[0].index); } From 42c0605abf8f007cd1d670fb3be53f63e9d2c57e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:33:59 +0100 Subject: [PATCH 0074/2040] Fixed game message printing possible random characters if the string is empty --- code/client/cl_ui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 3b2e6769..e5c6f22d 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -1289,7 +1289,9 @@ void UI_PrintConsole(const char *msg) break; } - pszString++; + if (*pszString != 0) { + pszString++; + } // // print to the deathmatch console From 45f50cfe2528d6d06c96d1933eb93e365223d1b5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:53:02 +0100 Subject: [PATCH 0075/2040] Fixed array variable being case-sensitive --- code/script/scriptcompiler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index 26726266..807fc1dc 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -956,6 +956,7 @@ int ScriptCompiler::EmitParameterList(sval_t event_parameter_list) void ScriptCompiler::EmitRef(sval_t val, unsigned int sourcePos) { unsigned int index; + str name_lowered; if (val.node[0].type != ENUM_field) { if (val.node[0].type == ENUM_array_expr) { @@ -968,7 +969,9 @@ void ScriptCompiler::EmitRef(sval_t val, unsigned int sourcePos) return; } - index = Director.AddString(val.node[2].stringValue); + name_lowered = val.node[2].stringValue; + name_lowered.tolower(); + index = Director.AddString(name_lowered); EmitValue(val.node[1]); EmitOpcode(OP_STORE_FIELD_REF, sourcePos); From 5f3ee10bc017860d0055b7ad7bfff03f49cb128e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jan 2024 00:01:39 +0100 Subject: [PATCH 0076/2040] Fixed Linux compilation error because of stupid CL accepting anything --- code/tiki/tiki_files.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index b9d2816e..4f36dc6c 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -248,7 +248,7 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) ext = strstr(path, "."); if (!ext) { - return false; + return NULL; } Q_strncpyz(tempName, path, ext - path + 1); From 808916029e1dbd81db3f5417f627c2169ef7e315 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jan 2024 00:03:51 +0100 Subject: [PATCH 0077/2040] Formatted scriptthread source file --- code/fgame/scriptthread.cpp | 47 +++++++++++++++++-------------------- code/fgame/scriptthread.h | 40 +++++++++++++++---------------- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index f8dde9ad..468126f3 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -430,7 +430,8 @@ Event EV_ScriptThread_KillEnt ); Event EV_ScriptThread_IsAlive ( - "IsAlive", EV_DEFAULT, + "IsAlive", + EV_DEFAULT, "e", "ent", "Returns true if the specified entity exists and has health > 0.", @@ -707,7 +708,8 @@ Event EV_ScriptThread_Vector_Normalize ); Event EV_ScriptThread_Vector_Add ( - "vector_add", EV_DEFAULT, + "vector_add", + EV_DEFAULT, "vv", "vector1 vector2", "Returns vector1 + vector2.", @@ -724,7 +726,8 @@ Event EV_ScriptThread_Vector_Subtract ); Event EV_ScriptThread_Vector_Scale ( - "vector_scale", EV_DEFAULT, + "vector_scale", + EV_DEFAULT, "vf", "vector1 scale_factor", "Returns vector1 * scale_factor.", @@ -732,7 +735,8 @@ Event EV_ScriptThread_Vector_Scale ); Event EV_ScriptThread_Vector_DotProduct ( - "vector_dot", EV_DEFAULT, + "vector_dot", + EV_DEFAULT, "vv", "vector1 vector2", "Returns vector1 * vector2.", @@ -2273,7 +2277,7 @@ ScriptThread::ScriptThread(ScriptClass *scriptClass, unsigned char *pCodePos) ScriptThread::~ScriptThread() { - ScriptVM* vm; + ScriptVM *vm; if (g_scripttrace->integer && CanScriptTracePrint()) { gi.DPrintf2("---Destructor THREAD: %p\n", this); @@ -2285,7 +2289,7 @@ ScriptThread::~ScriptThread() throw ScriptException("Attempting to delete a dead thread."); } - vm = m_ScriptVM; + vm = m_ScriptVM; m_ScriptVM = NULL; if (vm->ThreadState() == THREAD_WAITING) { vm->m_ThreadState = THREAD_RUNNING; @@ -2366,7 +2370,7 @@ void ScriptThread::ScriptExecuteInternal(ScriptVariable *data, int dataSize) SafePtr currentThread; SafePtr previousThread; - currentThread = Director.CurrentThread(); + currentThread = Director.CurrentThread(); previousThread = this; Director.m_PreviousThread = Director.CurrentThread(); @@ -2489,7 +2493,7 @@ void ScriptThread::Pause() void ScriptThread::Getcvar(Event *ev) { str varName = ev->GetString(1); - str s = gi.Cvar_Get(varName.c_str(), "", 0)->string; + str s = gi.Cvar_Get(varName.c_str(), "", 0)->string; if (strstr(s.c_str(), ".")) { for (int i = s.length() - 1; i >= 0; i--) { @@ -2906,7 +2910,8 @@ void ScriptThread::TriggerEvent(Event *ev) void ScriptThread::RegisterAliasAndCache(Event *ev) { //assert(!"ScriptThread::RegisterAliasAndCache needs to be implemented like ClientGameCommandManager::AliasCache"); - gi.DPrintf("ScriptThread::RegisterAliasAndCache needs to be implemented like ClientGameCommandManager::AliasCache\n"); + gi.DPrintf("ScriptThread::RegisterAliasAndCache needs to be implemented like ClientGameCommandManager::AliasCache\n" + ); } void ScriptThread::CacheResourceEvent(Event *ev) @@ -3591,7 +3596,7 @@ void ScriptThread::Angles_PointAt(Event *ev) void ScriptThread::EventIsAlive(Event *ev) { - Entity* ent; + Entity *ent; if (!ev->IsEntityAt(1)) { ev->AddInteger(false); @@ -4289,27 +4294,20 @@ void ScriptThread::SetCurrentObjective(int iObjective, int iTeam) gi.setConfigstring(CS_CURRENT_OBJECTIVE, va("%i", iObjective)); if (iObjective == -1) { - level.m_vObjectiveLocation = vec_zero; + level.m_vObjectiveLocation = vec_zero; level.m_vAlliedObjectiveLocation = vec_zero; - level.m_vAxisObjectiveLocation = vec_zero; + level.m_vAxisObjectiveLocation = vec_zero; } else { const char *s = gi.getConfigstring(CS_OBJECTIVES + iObjective); const char *loc = Info_ValueForKey(s, "loc"); - Vector v; + Vector v; - sscanf( - loc, - "%f %f %f", - &v[0], - &v[1], - &v[2] - ); + sscanf(loc, "%f %f %f", &v[0], &v[1], &v[2]); // // Since 2.0, allow objective location per team // - switch (iTeam) - { + switch (iTeam) { case TEAM_NONE: default: level.m_vObjectiveLocation = v; @@ -4390,14 +4388,13 @@ void ScriptThread::EventSetScoreboardToggle(Event *ev) void ScriptThread::EventSetCurrentObjective(Event *ev) { int iObjective = ev->GetInteger(1); - int iTeam = 0; + int iTeam = 0; if (iObjective > MAX_OBJECTIVES) { ScriptError("Index Out Of Range"); } - if (ev->NumArgs() >= 2) - { + if (ev->NumArgs() >= 2) { const_str teamStr = ev->GetConstString(2); if (teamStr == STRING_ALLIES) { iTeam = TEAM_ALLIES; diff --git a/code/fgame/scriptthread.h b/code/fgame/scriptthread.h index d46f3b1c..1c39e70b 100644 --- a/code/fgame/scriptthread.h +++ b/code/fgame/scriptthread.h @@ -131,14 +131,14 @@ protected: void GetRandomFloat(Event *ev); void GetRandomInt(Event *ev); - void GetAbs(Event* ev); + void GetAbs(Event *ev); ////////// // Added in 2.30 - void EventCos(Event* ev); - void EventSin(Event* ev); - void EventTan(Event* ev); - void EventATan(Event* ev); - void EventSqrt(Event* ev); + void EventCos(Event *ev); + void EventSin(Event *ev); + void EventTan(Event *ev); + void EventATan(Event *ev); + void EventSqrt(Event *ev); ////////// void GetSelf(Event *ev); void Vector_Length(Event *ev); @@ -192,13 +192,13 @@ public: ScriptThread(ScriptClass *scriptClass, unsigned char *pCodePos); virtual ~ScriptThread(); - void Execute(Event &ev); + void Execute(Event& ev); void Execute(Event *ev); void Execute(); void Execute(ScriptVariable *data, int dataSize); void Wait(float time); void Pause(void); - void ScriptExecute(ScriptVariable *data, int dataSize, ScriptVariable &returnValue); + void ScriptExecute(ScriptVariable *data, int dataSize, ScriptVariable& returnValue); void ScriptExecuteInternal(ScriptVariable *data = NULL, int dataSize = 0); void EventThrow(Event *ev); void StartWaiting(); @@ -225,22 +225,22 @@ public: // static void AddObjective(int index, int status, str text, Vector location); static void SetCurrentObjective(int iObjective, int iTeam); - void SendObjective(); - void SendObjectives(); - void ClearObjectives(); - void EventAddObjective(Event *ev); - void EventSetScoreboardToggle(Event *ev); // Added in 2.30 - void EventSetCurrentObjective(Event *ev); - void EventClearObjectives(Event *ev); - void SetObjectiveLocation(Vector vLocation); - void SetObjectiveLocation(Event *ev); - void ClearObjectiveLocation(void); - void ClearObjectiveLocation(Event *ev); + void SendObjective(); + void SendObjectives(); + void ClearObjectives(); + void EventAddObjective(Event *ev); + void EventSetScoreboardToggle(Event *ev); // Added in 2.30 + void EventSetCurrentObjective(Event *ev); + void EventClearObjectives(Event *ev); + void SetObjectiveLocation(Vector vLocation); + void SetObjectiveLocation(Event *ev); + void ClearObjectiveLocation(void); + void ClearObjectiveLocation(Event *ev); void EventDrawHud(Event *ev); virtual void Archive(Archiver& arc) override; - void ArchiveInternal(Archiver &arc); + void ArchiveInternal(Archiver& arc); // // Openmohaa addition From bf27caa61e6f51eb56425a6b562b96362d685b58 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:55:48 +0100 Subject: [PATCH 0078/2040] Fixed vehicle lacking gravity --- code/fgame/vehicle.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 1c20db88..e9dc3752 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -4516,6 +4516,8 @@ void Vehicle::MoveVehicle(void) } if (bDoGravity) { + velocity[2] -= sv_gravity->value * level.frametime; + tr = G_Trace( origin, mins, From 92f7c3633f786c6bd2f2e8c1a871f4d55d158af0 Mon Sep 17 00:00:00 2001 From: DraGoN <51184732+ysdragon@users.noreply.github.com> Date: Tue, 30 Jan 2024 22:54:13 +0000 Subject: [PATCH 0079/2040] Fixed compilation using Clang 16+ --- code/server/sv_ccmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 5913d2c5..9c6c479a 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1593,7 +1593,7 @@ void SV_AddOperatorCommands(void) { Cmd_AddCommand("say", SV_ConSay_f); Cmd_AddCommand("tell", SV_ConTell_f); Cmd_AddCommand("sayto", SV_ConSayto_f); - Cmd_SetCommandCompletionFunc("sayto", SV_CompletePlayerName); + Cmd_SetCommandCompletionFunc("sayto", (completionFunc_t)SV_CompletePlayerName); } Cmd_AddCommand("rehashbans", SV_RehashBans_f); From 368f94ce3bd8a9fda9ceff1ba82a9cd50176c624 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 2 Feb 2024 19:23:09 +0100 Subject: [PATCH 0080/2040] Fixed spline improperly returning the number of points when appending --- code/fgame/spline.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/fgame/spline.h b/code/fgame/spline.h index 34be2d74..83ef4520 100644 --- a/code/fgame/spline.h +++ b/code/fgame/spline.h @@ -247,6 +247,9 @@ int cSpline::Append(cSpline *pNew) } if (m_iPoints) { + int points; + + points = m_iPoints; fIndexAdd = *GetByNode(m_iPoints, NULL); for (i = 0; i < pNew->m_iPoints; i++) { @@ -260,7 +263,7 @@ int cSpline::Append(cSpline *pNew) Add(o_fTmp, iFlags); } - return m_iPoints; + return points; } else { for (i = 0; i < pNew->m_iPoints; i++) { i_fTmp = pNew->GetByNode(i, &iFlags); From 4388b7b187a81f1b6150f8f59bbd50026fd33f2c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 2 Feb 2024 19:26:11 +0100 Subject: [PATCH 0081/2040] AI_ThinkActive() must be used if the owner is an Actor --- code/fgame/weapturret.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index 9b8a7229..6f0d806a 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -1267,10 +1267,12 @@ void TurretGun::AI_ThinkActive() void TurretGun::Think(void) { - if (owner || (!m_bHadOwner && aim_target)) { + if (!owner && (m_bHadOwner || !aim_target)) { + ThinkIdle(); + } else if (owner && owner->IsSubclassOfPlayer()) { P_ThinkActive(); } else { - ThinkIdle(); + AI_ThinkActive(); } } From ca2c2fb8feb9e6c63750546346e601ee83639c50 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 2 Feb 2024 23:05:18 +0100 Subject: [PATCH 0082/2040] Use floating-point operation in CalculateBoxPoints() --- code/fgame/movegrid.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/fgame/movegrid.cpp b/code/fgame/movegrid.cpp index ee755b89..7adfdae5 100644 --- a/code/fgame/movegrid.cpp +++ b/code/fgame/movegrid.cpp @@ -82,7 +82,7 @@ void cMoveGrid::CalculateBoxPoints(void) for (z = 0; z < m_iZRes; z++) { gridpoint_t *gridPoint = GetGridPoint(x, y, z); - gridPoint->origin = Vector(xdelta - rx, ydelta - ry, zdelta + rz / 2); + gridPoint->origin = Vector(xdelta - rx, ydelta - ry, zdelta + rz / 2.f); zdelta += rz; } zdelta = 0; @@ -107,18 +107,18 @@ void cMoveGrid::CalculateBoxPoints(void) if (rx >= ry) { Vector vec; - vec = Vector(-ry / 2, -ry / 2, -rz / 2); + vec = Vector(-ry / 2.f, -ry / 2.f, -rz / 2.f); vec.copyTo(gridPoint->vm.mins); - vec = Vector(ry / 2, ry / 2, rz / 2); + vec = Vector(ry / 2.f, ry / 2.f, rz / 2.f); vec.copyTo(gridPoint->vm.maxs); } else { Vector vec; - vec = Vector(-rx / 2, -rx / 2, -rz / 2); + vec = Vector(-rx / 2.f, -rx / 2.f, -rz / 2.f); vec.copyTo(gridPoint->vm.mins); - vec = Vector(rx / 2, rx / 2, rz / 2); + vec = Vector(rx / 2.f, rx / 2.f, rz / 2.f); vec.copyTo(gridPoint->vm.maxs); } } From 534176423e3ad2d4ee72f03db60ac71a91aab3bd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 2 Feb 2024 23:05:55 +0100 Subject: [PATCH 0083/2040] Fixed trace error with `Vehicle Hit(MV2)` --- code/fgame/vehicle.cpp | 6 +----- code/fgame/vehicle.h | 8 ++++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index e9dc3752..3ceb667d 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -4411,14 +4411,10 @@ void Vehicle::MoveVehicle(void) "Vehicle::MoveVehicle" ); - if (tr.fraction != 1.0f || tr.plane.normal[2] < 0.7f || tr.allsolid) { + if ((tr.fraction != 1.0f && tr.plane.normal[2] < 0.7f) || tr.allsolid) { flMoveFrac = 0.0f; } - if (tr.fraction == 1.0f && !tr.allsolid && !tr.startsolid) { - break; - } - if (!tr.ent || !tr.ent->entity || tr.ent->entity == world) { break; } diff --git a/code/fgame/vehicle.h b/code/fgame/vehicle.h index d27ea5f5..143a7270 100644 --- a/code/fgame/vehicle.h +++ b/code/fgame/vehicle.h @@ -485,7 +485,7 @@ public: virtual qboolean ShowWeapon(void); Entity *Driver(void); virtual qboolean IsDrivable(void); - void Archive(Archiver &arc) override; + void Archive(Archiver& arc) override; str GetSoundSet(void); virtual float QuerySpeed(void); virtual int QueryFreePassengerSlot(void); @@ -503,7 +503,7 @@ public: virtual Entity *QueryPassengerSlotEntity(int slot); virtual Entity *QueryDriverSlotEntity(int slot); virtual Entity *QueryTurretSlotEntity(int slot); - bool FindExitPosition(Entity *pEnt, const Vector &vOrigin, const Vector *vAngles); // added in 2.0 + bool FindExitPosition(Entity *pEnt, const Vector& vOrigin, const Vector *vAngles); // added in 2.0 virtual void AttachPassengerSlot(int slot, Entity *ent, Vector vExitPosition); virtual void AttachDriverSlot(int slot, Entity *ent, Vector vExitPosition); virtual void AttachTurretSlot(int slot, Entity *ent, Vector vExitPosition, Vector *vExitAngles); @@ -519,7 +519,7 @@ public: qboolean isLocked(void); void Lock(void); void UnLock(void); - const str & getName() const; // added in 2.0 + const str& getName() const; // added in 2.0 VehicleCollisionEntity *GetCollisionEntity(void); // Added in 2.30 //==== @@ -592,7 +592,7 @@ public: virtual void CalculateOriginOffset() override; void UpdateSound() override; //void AttachDriverSlot(Event* ev) override; - void AttachDriverSlot(int slot, Entity* ent, Vector vExitPosition) override; + void AttachDriverSlot(int slot, Entity *ent, Vector vExitPosition) override; }; class VehicleHalfTrack : public DrivableVehicle From 570dddddd83e23d967831b8928fc93c3d89d7ebf Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 21:07:49 +0100 Subject: [PATCH 0084/2040] Formatted cm_terrain source files --- code/qcommon/cm_terrain.c | 2390 +++++++++++++++++-------------------- code/qcommon/cm_terrain.h | 50 +- 2 files changed, 1151 insertions(+), 1289 deletions(-) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 12002e2c..ede3d330 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -27,43 +27,33 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "cm_terrain.h" typedef struct varnodeIndex_s { - short unsigned int iTreeAndMask; - short unsigned int iNode; + short unsigned int iTreeAndMask; + short unsigned int iNode; } varnodeIndex_t; typedef struct worknode_s { - int i0; - int j0; - int i1; - int j1; - int i2; - int j2; + int i0; + int j0; + int i1; + int j1; + int i2; + int j2; } worknode_t; typedef struct pointtrace_s { - traceWork_t *tw; - terrainCollide_t *tc; - vec3_t vStart; - vec3_t vEnd; - int i; - int j; - float fSurfaceClipEpsilon; + traceWork_t *tw; + terrainCollide_t *tc; + vec3_t vStart; + vec3_t vEnd; + int i; + int j; + float fSurfaceClipEpsilon; } pointtrace_t; -varnodeIndex_t g_vni[ 2 ][ 8 ][ 8 ][ 2 ]; +varnodeIndex_t g_vni[2][8][8][2]; static pointtrace_t g_trace; -static int modeTable[] = -{ - 2, - 2, - 5, - 6, - 4, - 3, - 0, - 0 -}; +static int modeTable[] = {2, 2, 5, 6, 4, 3, 0, 0}; /* ================= @@ -71,16 +61,17 @@ CM_SignbitsForNormal ================= Copied over from cm_patch.c */ -static int CM_SignbitsForNormal( vec3_t normal ) { - int bits, j; +static int CM_SignbitsForNormal(vec3_t normal) +{ + int bits, j; - bits = 0; - for (j=0 ; j<3 ; j++) { - if ( normal[j] < 0 ) { - bits |= 1<> 1; - worknode[ i * 2 + 2 ].j2 = j2 >> 1; - worknode[ i * 2 + 2 + 1 ].i0 = worknode[ i + 1 ].i2; - worknode[ i * 2 + 2 + 1 ].j0 = worknode[ i + 1 ].j2; - worknode[ i * 2 + 2 + 1 ].i1 = worknode[ i + 1 ].i0; - worknode[ i * 2 + 2 + 1 ].j1 = worknode[ i + 1 ].j0; - worknode[ i * 2 + 2 + 1 ].i2 = i2 >> 1; - worknode[ i * 2 + 2 + 1 ].j2 = j2 >> 1; - } + for (i = 0; i <= 30; i++) { + i2 = worknode[i + 1].i0 + worknode[i + 1].i1; + j2 = worknode[i + 1].j0 + worknode[i + 1].j1; + worknode[i * 2 + 2].i0 = worknode[i + 1].i1; + worknode[i * 2 + 2].j0 = worknode[i + 1].j1; + worknode[i * 2 + 2].i1 = worknode[i + 1].i2; + worknode[i * 2 + 2].j1 = worknode[i + 1].j2; + worknode[i * 2 + 2].i2 = i2 >> 1; + worknode[i * 2 + 2].j2 = j2 >> 1; + worknode[i * 2 + 2 + 1].i0 = worknode[i + 1].i2; + worknode[i * 2 + 2 + 1].j0 = worknode[i + 1].j2; + worknode[i * 2 + 2 + 1].i1 = worknode[i + 1].i0; + worknode[i * 2 + 2 + 1].j1 = worknode[i + 1].j0; + worknode[i * 2 + 2 + 1].i2 = i2 >> 1; + worknode[i * 2 + 2 + 1].j2 = j2 >> 1; + } - for( i = 32; i < 64; i++ ) - { - i2 = ( worknode[ i ].i0 + worknode[ i ].i1 ) >> 1; - j2 = ( worknode[ i ].j0 + worknode[ i ].j1 ) >> 1; + for (i = 32; i < 64; i++) { + i2 = (worknode[i].i0 + worknode[i].i1) >> 1; + j2 = (worknode[i].j0 + worknode[i].j1) >> 1; - if( worknode[ i ].i0 == worknode[ i ].i1 ) - { - if( worknode[ i ].j0 <= worknode[ i ].j1 ) - { - vni = &g_vni[ iDiagonal ][ i2 ][ j2 ][ 1 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x2000; + if (worknode[i].i0 == worknode[i].i1) { + if (worknode[i].j0 <= worknode[i].j1) { + vni = &g_vni[iDiagonal][i2][j2][1]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x2000; - vni = &g_vni[ iDiagonal ][ i2 ][ j2 - 1 ][ 0 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x1000; - } - else - { - vni = &g_vni[ iDiagonal ][ i2 - 1 ][ j2 ][ 1 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x1000; + vni = &g_vni[iDiagonal][i2][j2 - 1][0]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x1000; + } else { + vni = &g_vni[iDiagonal][i2 - 1][j2][1]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x1000; - vni = &g_vni[ iDiagonal ][ i2 - 1 ][ j2 - 1 ][ 0 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x2000; - } - } - else - { - if( worknode[ i ].i0 <= worknode[ i ].i1 ) - { - vni = &g_vni[ iDiagonal ][ i2 ][ j2 - 1 ][ 0 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x2000; + vni = &g_vni[iDiagonal][i2 - 1][j2 - 1][0]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x2000; + } + } else { + if (worknode[i].i0 <= worknode[i].i1) { + vni = &g_vni[iDiagonal][i2][j2 - 1][0]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x2000; - vni = &g_vni[ iDiagonal ][ i2 - 1 ][ j2 - 1 ][ 0 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x1000; - } - else - { - vni = &g_vni[ iDiagonal ][ i2 ][ j2 ][ 1 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x1000; + vni = &g_vni[iDiagonal][i2 - 1][j2 - 1][0]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x1000; + } else { + vni = &g_vni[iDiagonal][i2][j2][1]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x1000; - vni = &g_vni[ iDiagonal ][ i2 - 1 ][ j2 ][ 1 ]; - vni->iNode = i - 1; - vni->iTreeAndMask = iTree | 0x2000; - } - } - - } + vni = &g_vni[iDiagonal][i2 - 1][j2][1]; + vni->iNode = i - 1; + vni->iTreeAndMask = iTree | 0x2000; + } + } + } } /* @@ -173,70 +152,71 @@ void CM_CalculateTerrainIndices( worknode_t *worknode, int iDiagonal, int iTree CM_PrepareGenerateTerrainCollide ==================== */ -void CM_PrepareGenerateTerrainCollide( void ) +void CM_PrepareGenerateTerrainCollide(void) { - worknode_t worknode[ 64 ]; + worknode_t worknode[64]; - memset( &g_vni, 0, sizeof( g_vni ) ); + memset(&g_vni, 0, sizeof(g_vni)); - worknode[ 1 ].i0 = 8; - worknode[ 1 ].j0 = 8; - worknode[ 1 ].i1 = 0; - worknode[ 1 ].j1 = 0; - worknode[ 1 ].i2 = 0; - worknode[ 1 ].j2 = 8; + worknode[1].i0 = 8; + worknode[1].j0 = 8; + worknode[1].i1 = 0; + worknode[1].j1 = 0; + worknode[1].i2 = 0; + worknode[1].j2 = 8; - CM_CalculateTerrainIndices( worknode, 0, 0 ); + CM_CalculateTerrainIndices(worknode, 0, 0); - worknode[ 1 ].i0 = 0; - worknode[ 1 ].j0 = 0; - worknode[ 1 ].i1 = 8; - worknode[ 1 ].j1 = 8; - worknode[ 1 ].i2 = 8; - worknode[ 1 ].j2 = 0; + worknode[1].i0 = 0; + worknode[1].j0 = 0; + worknode[1].i1 = 8; + worknode[1].j1 = 8; + worknode[1].i2 = 8; + worknode[1].j2 = 0; - CM_CalculateTerrainIndices( worknode, 0, 1 ); + CM_CalculateTerrainIndices(worknode, 0, 1); - worknode[ 1 ].i0 = 8; - worknode[ 1 ].j0 = 0; - worknode[ 1 ].i1 = 0; - worknode[ 1 ].j1 = 8; - worknode[ 1 ].i2 = 8; - worknode[ 1 ].j2 = 8; + worknode[1].i0 = 8; + worknode[1].j0 = 0; + worknode[1].i1 = 0; + worknode[1].j1 = 8; + worknode[1].i2 = 8; + worknode[1].j2 = 8; - CM_CalculateTerrainIndices( worknode, 1, 0 ); + CM_CalculateTerrainIndices(worknode, 1, 0); - worknode[ 1 ].i0 = 0; - worknode[ 1 ].j0 = 8; - worknode[ 1 ].i1 = 8; - worknode[ 1 ].j1 = 0; - worknode[ 1 ].i2 = 0; - worknode[ 1 ].j2 = 0; + worknode[1].i0 = 0; + worknode[1].j0 = 8; + worknode[1].i1 = 8; + worknode[1].j1 = 0; + worknode[1].i2 = 0; + worknode[1].j2 = 0; - CM_CalculateTerrainIndices( worknode, 1, 1 ); + CM_CalculateTerrainIndices(worknode, 1, 1); } -void CM_PickTerrainSquareMode( terrainCollideSquare_t *square, vec3_t vTest, int i, int j, cTerraPatch_t *patch ) { - int flags0, flags1; - varnodeIndex_t *vni; +void CM_PickTerrainSquareMode(terrainCollideSquare_t *square, vec3_t vTest, int i, int j, cTerraPatch_t *patch) +{ + int flags0, flags1; + varnodeIndex_t *vni; - vni = &g_vni[ ( patch->flags & 0x80 ) ? 1 : 0 ][ i ][ j ][ 0 ]; + vni = &g_vni[(patch->flags & 0x80) ? 1 : 0][i][j][0]; - flags0 = ( ( unsigned short )( patch->varTree[ vni->iTreeAndMask & 1 ][ vni->iNode ].flags & 0xFFFE & vni->iTreeAndMask ) != 0 ); - flags1 = ( ( unsigned short )( patch->varTree[ vni[ 1 ].iTreeAndMask & 1 ][ vni[ 1 ].iNode ].flags & 0xFFFE & vni[ 1 ].iTreeAndMask ) != 0 ); + flags0 = + ((unsigned short)(patch->varTree[vni->iTreeAndMask & 1][vni->iNode].flags & 0xFFFE & vni->iTreeAndMask) != 0); + flags1 = + ((unsigned short)(patch->varTree[vni[1].iTreeAndMask & 1][vni[1].iNode].flags & 0xFFFE & vni[1].iTreeAndMask) + != 0); - square->eMode = modeTable[ ( j + i ) & 1 | 2 * flags0 | 4 * flags1 ]; + square->eMode = modeTable[(j + i) & 1 | 2 * flags0 | 4 * flags1]; - if( square->eMode == 2 ) - { - if( DotProduct( vTest, square->plane[ 0 ] ) < square->plane[ 0 ][ 3 ] ) { - square->eMode = 1; - } - } - else if( square->eMode == 5 || square->eMode == 6 ) - { - VectorCopy( square->plane[ 1 ], square->plane[ 0 ] ); - } + if (square->eMode == 2) { + if (DotProduct(vTest, square->plane[0]) < square->plane[0][3]) { + square->eMode = 1; + } + } else if (square->eMode == 5 || square->eMode == 6) { + VectorCopy(square->plane[1], square->plane[0]); + } } /* @@ -244,107 +224,95 @@ void CM_PickTerrainSquareMode( terrainCollideSquare_t *square, vec3_t vTest, int CM_GenerateTerPatchCollide ==================== */ -void CM_GenerateTerrainCollide( cTerraPatch_t *patch, terrainCollide_t *tc ) { - int i; - int j; - int x0, y0, z0; - float fMaxHeight; - float heightmap[ 9 ][ 9 ]; - terrainCollideSquare_t *square; - vec3_t v1; - vec3_t v2; - vec3_t v3; - vec3_t v4; - - x0 = ( patch->x << 6 ); - y0 = ( patch->y << 6 ); - z0 = ( patch->iBaseHeight ); +void CM_GenerateTerrainCollide(cTerraPatch_t *patch, terrainCollide_t *tc) +{ + int i; + int j; + int x0, y0, z0; + float fMaxHeight; + float heightmap[9][9]; + terrainCollideSquare_t *square; + vec3_t v1; + vec3_t v2; + vec3_t v3; + vec3_t v4; - fMaxHeight = z0; + x0 = (patch->x << 6); + y0 = (patch->y << 6); + z0 = (patch->iBaseHeight); - for( j = 0; j < 9; j++ ) - { - for( i = 0; i < 9; i++ ) - { - heightmap[ i ][ j ] = ( float )( z0 + 2 * patch->heightmap[ j * 9 + i ] ); - } - } + fMaxHeight = z0; - for( j = 0; j < 8; j++ ) - { - for( i = 0; i < 8; i++ ) - { - v1[ 0 ] = ( ( i << 6 ) + x0 ); - v1[ 1 ] = ( ( j << 6 ) + y0 ); - v1[ 2 ] = heightmap[ i ][ j ]; + for (j = 0; j < 9; j++) { + for (i = 0; i < 9; i++) { + heightmap[i][j] = (float)(z0 + 2 * patch->heightmap[j * 9 + i]); + } + } - v2[ 0 ] = ( ( i << 6 ) + x0 ) + 64; - v2[ 1 ] = ( ( j << 6 ) + y0 ); - v2[ 2 ] = heightmap[ i + 1 ][ j ]; + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++) { + v1[0] = ((i << 6) + x0); + v1[1] = ((j << 6) + y0); + v1[2] = heightmap[i][j]; - v3[ 0 ] = ( ( i << 6 ) + x0 ) + 64; - v3[ 1 ] = ( ( j << 6 ) + y0 ) + 64; - v3[ 2 ] = heightmap[ i + 1 ][ j + 1 ]; + v2[0] = ((i << 6) + x0) + 64; + v2[1] = ((j << 6) + y0); + v2[2] = heightmap[i + 1][j]; - v4[ 0 ] = ( ( i << 6 ) + x0 ); - v4[ 1 ] = ( ( j << 6 ) + y0 ) + 64; - v4[ 2 ] = heightmap[ i ][ j + 1 ]; + v3[0] = ((i << 6) + x0) + 64; + v3[1] = ((j << 6) + y0) + 64; + v3[2] = heightmap[i + 1][j + 1]; - if( fMaxHeight < v1[ 2 ] ) { - fMaxHeight = v1[ 2 ]; - } + v4[0] = ((i << 6) + x0); + v4[1] = ((j << 6) + y0) + 64; + v4[2] = heightmap[i][j + 1]; - if( fMaxHeight < v2[ 2 ] ) { - fMaxHeight = v2[ 2 ]; - } + if (fMaxHeight < v1[2]) { + fMaxHeight = v1[2]; + } - if( fMaxHeight < v3[ 2 ] ) { - fMaxHeight = v3[ 2 ]; - } + if (fMaxHeight < v2[2]) { + fMaxHeight = v2[2]; + } - if( fMaxHeight < v4[ 2 ] ) { - fMaxHeight = v4[ 2 ]; - } + if (fMaxHeight < v3[2]) { + fMaxHeight = v3[2]; + } - square = &tc->squares[ i ][ j ]; + if (fMaxHeight < v4[2]) { + fMaxHeight = v4[2]; + } - if( ( i + j ) & 1 ) - { - if( patch->flags & 0x40 ) - { - CM_PlaneFromPoints( square->plane[ 0 ], v4, v2, v3 ); - CM_PlaneFromPoints( square->plane[ 1 ], v2, v4, v1 ); - } - else - { - CM_PlaneFromPoints( square->plane[ 0 ], v2, v4, v3 ); - CM_PlaneFromPoints( square->plane[ 1 ], v4, v2, v1 ); - } - CM_PickTerrainSquareMode( square, v1, i, j, patch ); - } - else - { - if( patch->flags & 0x40 ) - { - CM_PlaneFromPoints( square->plane[ 0 ], v1, v3, v4 ); - CM_PlaneFromPoints( square->plane[ 1 ], v3, v1, v2 ); - } - else - { - CM_PlaneFromPoints( square->plane[ 0 ], v3, v1, v4 ); - CM_PlaneFromPoints( square->plane[ 1 ], v1, v3, v2 ); - } - CM_PickTerrainSquareMode( square, v2, i, j, patch ); - } - } - } + square = &tc->squares[i][j]; - tc->vBounds[ 0 ][ 0 ] = x0; - tc->vBounds[ 0 ][ 1 ] = y0; - tc->vBounds[ 0 ][ 2 ] = z0; - tc->vBounds[ 1 ][ 0 ] = ( x0 + 512 ); - tc->vBounds[ 1 ][ 1 ] = ( y0 + 512 ); - tc->vBounds[ 1 ][ 2 ] = fMaxHeight; + if ((i + j) & 1) { + if (patch->flags & 0x40) { + CM_PlaneFromPoints(square->plane[0], v4, v2, v3); + CM_PlaneFromPoints(square->plane[1], v2, v4, v1); + } else { + CM_PlaneFromPoints(square->plane[0], v2, v4, v3); + CM_PlaneFromPoints(square->plane[1], v4, v2, v1); + } + CM_PickTerrainSquareMode(square, v1, i, j, patch); + } else { + if (patch->flags & 0x40) { + CM_PlaneFromPoints(square->plane[0], v1, v3, v4); + CM_PlaneFromPoints(square->plane[1], v3, v1, v2); + } else { + CM_PlaneFromPoints(square->plane[0], v3, v1, v4); + CM_PlaneFromPoints(square->plane[1], v1, v3, v2); + } + CM_PickTerrainSquareMode(square, v2, i, j, patch); + } + } + } + + tc->vBounds[0][0] = x0; + tc->vBounds[0][1] = y0; + tc->vBounds[0][2] = z0; + tc->vBounds[1][0] = (x0 + 512); + tc->vBounds[1][1] = (y0 + 512); + tc->vBounds[1][2] = fMaxHeight; } /* @@ -352,40 +320,39 @@ void CM_GenerateTerrainCollide( cTerraPatch_t *patch, terrainCollide_t *tc ) { CM_CheckTerrainPlane ==================== */ -float CM_CheckTerrainPlane( vec4_t plane ) +float CM_CheckTerrainPlane(vec4_t plane) { - float d1, d2; - float f; + float d1, d2; + float f; - d1 = DotProduct( g_trace.vStart, plane ) - plane[ 3 ]; - d2 = DotProduct( g_trace.vEnd, plane ) - plane[ 3 ]; + d1 = DotProduct(g_trace.vStart, plane) - plane[3]; + d2 = DotProduct(g_trace.vEnd, plane) - plane[3]; - // if completely in front of face, no intersection with the entire brush - if( d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) { - return 1; - } + // if completely in front of face, no intersection with the entire brush + if (d1 > 0 && (d2 >= SURFACE_CLIP_EPSILON || d2 >= d1)) { + return 1; + } - if( d1 <= 0 && d2 <= 0 ) - { - if( d1 >= -32 ) { - return 0; - } + if (d1 <= 0 && d2 <= 0) { + if (d1 >= -32) { + return 0; + } - if( d2 >= -32 ) { - return 0; - } - return 1; - } + if (d2 >= -32) { + return 0; + } + return 1; + } - if( d1 <= d2 ) { - return 1; - } + if (d1 <= d2) { + return 1; + } - f = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 ); - if( f < 0 ) { - f = 0; - } - return f; + f = (d1 - SURFACE_CLIP_EPSILON) / (d1 - d2); + if (f < 0) { + f = 0; + } + return f; } /* @@ -393,68 +360,64 @@ float CM_CheckTerrainPlane( vec4_t plane ) CM_CheckTerrainTriSpherePoint ==================== */ -float CM_CheckTerrainTriSpherePoint( vec3_t v ) +float CM_CheckTerrainTriSpherePoint(vec3_t v) { - vec3_t vDelta, vDir; - float fLenSq; - float fRadSq; - float fA, fB; - float fDiscr; - float fFrac; - float fSq; - float f; + vec3_t vDelta, vDir; + float fLenSq; + float fRadSq; + float fA, fB; + float fDiscr; + float fFrac; + float fSq; + float f; - VectorSubtract( g_trace.vStart, v, vDir ); + VectorSubtract(g_trace.vStart, v, vDir); - fRadSq = sphere.radius * sphere.radius; - fLenSq = VectorLengthSquared( vDir ); + fRadSq = sphere.radius * sphere.radius; + fLenSq = VectorLengthSquared(vDir); - if( fLenSq <= fRadSq ) { - g_trace.tw->trace.startsolid = qtrue; - g_trace.tw->trace.allsolid = qtrue; - return 0; - } + if (fLenSq <= fRadSq) { + g_trace.tw->trace.startsolid = qtrue; + g_trace.tw->trace.allsolid = qtrue; + return 0; + } - VectorSubtract( g_trace.vEnd, g_trace.vStart, vDelta ); + VectorSubtract(g_trace.vEnd, g_trace.vStart, vDelta); - fA = VectorLengthSquared( vDelta ); - fB = DotProduct( vDelta, vDir ); - fDiscr = fB * fB - ( fLenSq - fRadSq ) * fA; + fA = VectorLengthSquared(vDelta); + fB = DotProduct(vDelta, vDir); + fDiscr = fB * fB - (fLenSq - fRadSq) * fA; - if( fDiscr <= 0.0f ) { - return g_trace.tw->trace.fraction; - } + if (fDiscr <= 0.0f) { + return g_trace.tw->trace.fraction; + } - fSq = sqrt( fDiscr ); + fSq = sqrt(fDiscr); - if( fA > 0 ) - { - fFrac = ( -fB - fSq ) / fA - g_trace.fSurfaceClipEpsilon; + if (fA > 0) { + fFrac = (-fB - fSq) / fA - g_trace.fSurfaceClipEpsilon; - if( fFrac >= 0.0f && fFrac <= g_trace.tw->trace.fraction ) { - return fFrac; - } + if (fFrac >= 0.0f && fFrac <= g_trace.tw->trace.fraction) { + return fFrac; + } + fFrac = -fB + fSq; + } else { + fFrac = (-fB + fSq) / fA - g_trace.fSurfaceClipEpsilon; - fFrac = -fB + fSq; - } - else - { - fFrac = ( -fB + fSq ) / fA - g_trace.fSurfaceClipEpsilon; + if (fFrac >= 0.0f && fFrac <= g_trace.tw->trace.fraction) { + return fFrac; + } - if( fFrac >= 0.0f && fFrac <= g_trace.tw->trace.fraction ) { - return fFrac; - } + fFrac = -fB - fSq; + } - fFrac = -fB - fSq; - } + f = fFrac / fA - g_trace.fSurfaceClipEpsilon; + if (f < 0 || f > g_trace.tw->trace.fraction) { + f = g_trace.tw->trace.fraction; + } - f = fFrac / fA - g_trace.fSurfaceClipEpsilon; - if( f < 0 || f > g_trace.tw->trace.fraction ) { - f = g_trace.tw->trace.fraction; - } - - return f; + return f; } /* @@ -462,15 +425,15 @@ float CM_CheckTerrainTriSpherePoint( vec3_t v ) CM_CheckTerrainTriSphereCorner ==================== */ -float CM_CheckTerrainTriSphereCorner( vec4_t plane, float x0, float y0, int i, int j ) +float CM_CheckTerrainTriSphereCorner(vec4_t plane, float x0, float y0, int i, int j) { - vec3_t v; + vec3_t v; - v[ 0 ] = ( ( i << 6 ) + x0 ); - v[ 1 ] = ( ( j << 6 ) + y0 ); - v[ 2 ] = ( plane[ 3 ] - ( v[ 1 ] * plane[ 1 ] + v[ 0 ] * plane[ 0 ] ) ) / plane[ 2 ]; + v[0] = ((i << 6) + x0); + v[1] = ((j << 6) + y0); + v[2] = (plane[3] - (v[1] * plane[1] + v[0] * plane[0])) / plane[2]; - return CM_CheckTerrainTriSpherePoint( v ); + return CM_CheckTerrainTriSpherePoint(v); } /* @@ -478,92 +441,91 @@ float CM_CheckTerrainTriSphereCorner( vec4_t plane, float x0, float y0, int i, i CM_CheckTerrainTriSphereEdge ==================== */ -float CM_CheckTerrainTriSphereEdge( float *plane, float x0, float y0, int i0, int j0, int i1, int j1 ) +float CM_CheckTerrainTriSphereEdge(float *plane, float x0, float y0, int i0, int j0, int i1, int j1) { - vec3_t v0, v1; - float fScale; - float fRadSq; - float S, T; - vec3_t vDeltaStart; - vec3_t vDirEdge; - vec3_t vDirTrace; - float fSFromT_Const; - float fSFromT_Scale; - vec3_t vRFromT_Const; - vec3_t vRFromT_Scale; + vec3_t v0, v1; + float fScale; + float fRadSq; + float S, T; + vec3_t vDeltaStart; + vec3_t vDirEdge; + vec3_t vDirTrace; + float fSFromT_Const; + float fSFromT_Scale; + vec3_t vRFromT_Const; + vec3_t vRFromT_Scale; - // junk variable(s) as usual - float fLengthSq, fDot; - float fFrac, fFracClip; + // junk variable(s) as usual + float fLengthSq, fDot; + float fFrac, fFracClip; - fScale = 1.0 / plane[ 2 ]; + fScale = 1.0 / plane[2]; - v0[ 0 ] = ( i0 << 6 ) + x0; - v0[ 1 ] = ( j0 << 6 ) + y0; - v0[ 2 ] = ( plane[ 3 ] - ( v0[ 0 ] * plane[ 0 ] + v0[ 1 ] * plane[ 1 ] ) ) * fScale; + v0[0] = (i0 << 6) + x0; + v0[1] = (j0 << 6) + y0; + v0[2] = (plane[3] - (v0[0] * plane[0] + v0[1] * plane[1])) * fScale; - v1[ 0 ] = ( i1 << 6 ) + x0; - v1[ 1 ] = ( j1 << 6 ) + y0; - v1[ 2 ] = ( plane[ 3 ] - ( v1[ 0 ] * plane[ 0 ] + v1[ 1 ] * plane[ 1 ] ) ) * fScale; + v1[0] = (i1 << 6) + x0; + v1[1] = (j1 << 6) + y0; + v1[2] = (plane[3] - (v1[0] * plane[0] + v1[1] * plane[1])) * fScale; - VectorSubtract( g_trace.vStart, v0, vDirTrace ); - VectorSubtract( v1, v0, vDirEdge ); - VectorSubtract( g_trace.vEnd, g_trace.vStart, vDeltaStart ); + VectorSubtract(g_trace.vStart, v0, vDirTrace); + VectorSubtract(v1, v0, vDirEdge); + VectorSubtract(g_trace.vEnd, g_trace.vStart, vDeltaStart); - fScale = 1.0 / VectorLengthSquared( vDirEdge ); - S = DotProduct( vDirTrace, vDirEdge ) * fScale; - T = DotProduct( vDeltaStart, vDirEdge ) * fScale; + fScale = 1.0 / VectorLengthSquared(vDirEdge); + S = DotProduct(vDirTrace, vDirEdge) * fScale; + T = DotProduct(vDeltaStart, vDirEdge) * fScale; - VectorMA( vDirTrace, -S, vDirEdge, vRFromT_Const ); - VectorMA( vDeltaStart, -T, vDirEdge, vRFromT_Scale ); + VectorMA(vDirTrace, -S, vDirEdge, vRFromT_Const); + VectorMA(vDeltaStart, -T, vDirEdge, vRFromT_Scale); - fRadSq = sphere.radius * sphere.radius; - fLengthSq = VectorLengthSquared( vRFromT_Const ); + fRadSq = sphere.radius * sphere.radius; + fLengthSq = VectorLengthSquared(vRFromT_Const); - if( fLengthSq <= fRadSq ) - { - if( S < 0 || S > 1 ) { - return CM_CheckTerrainTriSpherePoint( v0 ); - } + if (fLengthSq <= fRadSq) { + if (S < 0 || S > 1) { + return CM_CheckTerrainTriSpherePoint(v0); + } - g_trace.tw->trace.startsolid = qtrue; - g_trace.tw->trace.allsolid = qtrue; - return 1; - } + g_trace.tw->trace.startsolid = qtrue; + g_trace.tw->trace.allsolid = qtrue; + return 1; + } - fDot = DotProduct( vRFromT_Scale, vRFromT_Const ); - fSFromT_Scale = VectorLengthSquared( vRFromT_Scale ); - fSFromT_Const = fDot * fDot - ( fLengthSq - fRadSq ) * fSFromT_Scale; + fDot = DotProduct(vRFromT_Scale, vRFromT_Const); + fSFromT_Scale = VectorLengthSquared(vRFromT_Scale); + fSFromT_Const = fDot * fDot - (fLengthSq - fRadSq) * fSFromT_Scale; - if( fSFromT_Const <= 0 ) { - return g_trace.tw->trace.fraction; - } + if (fSFromT_Const <= 0) { + return g_trace.tw->trace.fraction; + } - if( fSFromT_Scale > 0 ) { - fFrac = ( -fDot - sqrt( fSFromT_Const ) ) / fSFromT_Scale; - } else { - fFrac = ( -fDot + sqrt( fSFromT_Const ) ) / fSFromT_Scale; - } + if (fSFromT_Scale > 0) { + fFrac = (-fDot - sqrt(fSFromT_Const)) / fSFromT_Scale; + } else { + fFrac = (-fDot + sqrt(fSFromT_Const)) / fSFromT_Scale; + } - fFracClip = fFrac - g_trace.fSurfaceClipEpsilon; - if( fFrac <= 0 || fFracClip >= g_trace.tw->trace.fraction ) { - return g_trace.tw->trace.fraction; - } + fFracClip = fFrac - g_trace.fSurfaceClipEpsilon; + if (fFrac <= 0 || fFracClip >= g_trace.tw->trace.fraction) { + return g_trace.tw->trace.fraction; + } - fFrac = fFrac * T + S; + fFrac = fFrac * T + S; - if( fFrac < 0 ) { - return CM_CheckTerrainTriSpherePoint( v0 ); - } + if (fFrac < 0) { + return CM_CheckTerrainTriSpherePoint(v0); + } - if( fFrac > 1 ) { - return CM_CheckTerrainTriSpherePoint( v1 ); - } + if (fFrac > 1) { + return CM_CheckTerrainTriSpherePoint(v1); + } - if( fFracClip < 0 ) { - fFracClip = 0; - } - return fFracClip; + if (fFracClip < 0) { + fFracClip = 0; + } + return fFracClip; } /* @@ -571,200 +533,191 @@ float CM_CheckTerrainTriSphereEdge( float *plane, float x0, float y0, int i0, in CM_CheckTerrainTriSphere ==================== */ -float CM_CheckTerrainTriSphere( float x0, float y0, int iPlane ) +float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) { - float *plane; - float fMaxFraction; - float d1, d2; - float fSpherePlane; - int eMode; - qboolean bFitsX, bFitsY; - qboolean bFitsDiag; - int iX[ 3 ]; - int iY[ 3 ]; + float *plane; + float fMaxFraction; + float d1, d2; + float fSpherePlane; + int eMode; + qboolean bFitsX, bFitsY; + qboolean bFitsDiag; + int iX[3]; + int iY[3]; - plane = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ iPlane ]; - d1 = DotProduct( g_trace.vStart, plane ) - plane[ 3 ]; - d2 = DotProduct( g_trace.vEnd, plane ) - plane[ 3 ]; + plane = g_trace.tc->squares[g_trace.i][g_trace.j].plane[iPlane]; + d1 = DotProduct(g_trace.vStart, plane) - plane[3]; + d2 = DotProduct(g_trace.vEnd, plane) - plane[3]; - if( d1 > sphere.radius ) - { - if( d2 >= sphere.radius + SURFACE_CLIP_EPSILON ) { - return g_trace.tw->trace.fraction; - } + if (d1 > sphere.radius) { + if (d2 >= sphere.radius + SURFACE_CLIP_EPSILON) { + return g_trace.tw->trace.fraction; + } - if( d2 >= d1 ) { - return g_trace.tw->trace.fraction; - } - } + if (d2 >= d1) { + return g_trace.tw->trace.fraction; + } + } - if( d1 <= -sphere.radius && d2 <= -sphere.radius ) { - return g_trace.tw->trace.fraction; - } + if (d1 <= -sphere.radius && d2 <= -sphere.radius) { + return g_trace.tw->trace.fraction; + } - if( d1 <= d2 ) { - return g_trace.tw->trace.fraction; - } + if (d1 <= d2) { + return g_trace.tw->trace.fraction; + } - fMaxFraction = SURFACE_CLIP_EPSILON / ( d1 - d2 ); - g_trace.fSurfaceClipEpsilon = fMaxFraction; - fSpherePlane = ( d1 - sphere.radius ) / ( d1 - d2 ) - fMaxFraction; + fMaxFraction = SURFACE_CLIP_EPSILON / (d1 - d2); + g_trace.fSurfaceClipEpsilon = fMaxFraction; + fSpherePlane = (d1 - sphere.radius) / (d1 - d2) - fMaxFraction; - if( fSpherePlane < 0 ) { - fSpherePlane = 0; - } + if (fSpherePlane < 0) { + fSpherePlane = 0; + } - if( fSpherePlane >= g_trace.tw->trace.fraction ) { - return g_trace.tw->trace.fraction; - } + if (fSpherePlane >= g_trace.tw->trace.fraction) { + return g_trace.tw->trace.fraction; + } - d1 = ( g_trace.vEnd[ 0 ] - g_trace.vStart[ 0 ] ) * fSpherePlane + g_trace.vEnd[ 0 ] - sphere.radius * plane[ 0 ] - x0; - d2 = ( g_trace.vEnd[ 1 ] - g_trace.vStart[ 1 ] ) * fSpherePlane + g_trace.vEnd[ 1 ] - sphere.radius * plane[ 1 ] - y0; + d1 = (g_trace.vEnd[0] - g_trace.vStart[0]) * fSpherePlane + g_trace.vEnd[0] - sphere.radius * plane[0] - x0; + d2 = (g_trace.vEnd[1] - g_trace.vStart[1]) * fSpherePlane + g_trace.vEnd[1] - sphere.radius * plane[1] - y0; - eMode = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].eMode; + eMode = g_trace.tc->squares[g_trace.i][g_trace.j].eMode; - if( eMode == 1 || eMode == 2 ) - { - if( ( g_trace.i + g_trace.j ) & 1 ) { - eMode = iPlane ? 6 : 3; - } else { - eMode = iPlane ? 5 : 4; - } - } + if (eMode == 1 || eMode == 2) { + if ((g_trace.i + g_trace.j) & 1) { + eMode = iPlane ? 6 : 3; + } else { + eMode = iPlane ? 5 : 4; + } + } - switch( eMode ) - { - case 3: - if( d1 > 64 ) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if( d2 > 64 ) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + switch (eMode) { + case 3: + if (d1 > 64) { + bFitsX = qfalse; + } else { + bFitsX = qtrue; + } + if (d2 > 64) { + bFitsY = qfalse; + } else { + bFitsY = qtrue; + } - if( d1 < 64 - d2 ) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } - iX[ 0 ] = 1; - iX[ 1 ] = 1; - iX[ 2 ] = 1; - iY[ 0 ] = 0; - iY[ 1 ] = 1; - iY[ 2 ] = 0; - break; - case 4: - if( d1 < 0 ) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if( d2 > 64 ) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + if (d1 < 64 - d2) { + bFitsDiag = qfalse; + } else { + bFitsDiag = qtrue; + } + iX[0] = 1; + iX[1] = 1; + iX[2] = 1; + iY[0] = 0; + iY[1] = 1; + iY[2] = 0; + break; + case 4: + if (d1 < 0) { + bFitsX = qfalse; + } else { + bFitsX = qtrue; + } + if (d2 > 64) { + bFitsY = qfalse; + } else { + bFitsY = qtrue; + } - if( d1 > d2 ) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } - iX[ 0 ] = 0; - iX[ 1 ] = 1; - iX[ 2 ] = 1; - iY[ 0 ] = 1; - iY[ 1 ] = 0; - iY[ 2 ] = 0; - break; - case 5: - if( d1 > 64 ) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if( d2 < 0 ) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + if (d1 > d2) { + bFitsDiag = qfalse; + } else { + bFitsDiag = qtrue; + } + iX[0] = 0; + iX[1] = 1; + iX[2] = 1; + iY[0] = 1; + iY[1] = 0; + iY[2] = 0; + break; + case 5: + if (d1 > 64) { + bFitsX = qfalse; + } else { + bFitsX = qtrue; + } + if (d2 < 0) { + bFitsY = qfalse; + } else { + bFitsY = qtrue; + } - if( d1 < d2 ) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } - iX[ 0 ] = 1; - iX[ 1 ] = 0; - iX[ 2 ] = 0; - iY[ 0 ] = 0; - iY[ 1 ] = 1; - iY[ 2 ] = 1; - break; - case 6: - if( d1 < 0 ) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if( d2 < 0 ) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + if (d1 < d2) { + bFitsDiag = qfalse; + } else { + bFitsDiag = qtrue; + } + iX[0] = 1; + iX[1] = 0; + iX[2] = 0; + iY[0] = 0; + iY[1] = 1; + iY[2] = 1; + break; + case 6: + if (d1 < 0) { + bFitsX = qfalse; + } else { + bFitsX = qtrue; + } + if (d2 < 0) { + bFitsY = qfalse; + } else { + bFitsY = qtrue; + } - if( d1 > 64 - d2 ) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } - iX[ 0 ] = 0; - iX[ 1 ] = 0; - iX[ 2 ] = 0; - iY[ 0 ] = 1; - iY[ 1 ] = 0; - iY[ 2 ] = 1; - break; - default: - return 0; - } + if (d1 > 64 - d2) { + bFitsDiag = qfalse; + } else { + bFitsDiag = qtrue; + } + iX[0] = 0; + iX[1] = 0; + iX[2] = 0; + iY[0] = 1; + iY[1] = 0; + iY[2] = 1; + break; + default: + return 0; + } - if( bFitsX ) - { - if( bFitsY ) - { - if( bFitsDiag ) { - return fSpherePlane; - } else { - return CM_CheckTerrainTriSphereEdge( plane, x0, y0, iY[ 0 ], iX[ 1 ], iY[ 1 ], iY[ 2 ] ); - } - } else if( bFitsDiag ) { - return CM_CheckTerrainTriSphereEdge( plane, x0, y0, iX[ 0 ], iX[ 2 ], iY[ 0 ], iX[ 1 ] ); - } else { - return CM_CheckTerrainTriSphereCorner( plane, x0, y0, iY[ 0 ], iX[ 1 ] ); - } - } - else if( bFitsY ) - { - if( bFitsDiag ) { - return CM_CheckTerrainTriSphereEdge( plane, x0, y0, iX[ 0 ], iX[ 2 ], iY[ 1 ], iY[ 2 ] ); - } else { - return CM_CheckTerrainTriSphereCorner( plane, x0, y0, iY[ 1 ], iY[ 2 ] ); - } - } - else - { - if( bFitsDiag ) { - return CM_CheckTerrainTriSphereCorner( plane, x0, y0, iX[ 0 ], iX[ 2 ] ); - } else { - return g_trace.tw->trace.fraction; - } - } + if (bFitsX) { + if (bFitsY) { + if (bFitsDiag) { + return fSpherePlane; + } else { + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iY[0], iX[1], iY[1], iY[2]); + } + } else if (bFitsDiag) { + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iX[2], iY[0], iX[1]); + } else { + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iY[0], iX[1]); + } + } else if (bFitsY) { + if (bFitsDiag) { + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iX[2], iY[1], iY[2]); + } else { + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iY[1], iY[2]); + } + } else { + if (bFitsDiag) { + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[0], iX[2]); + } else { + return g_trace.tw->trace.fraction; + } + } } /* @@ -772,24 +725,23 @@ float CM_CheckTerrainTriSphere( float x0, float y0, int iPlane ) CM_ValidateTerrainCollidePointSquare ==================== */ -qboolean CM_ValidateTerrainCollidePointSquare( float frac ) +qboolean CM_ValidateTerrainCollidePointSquare(float frac) { - float f; + float f; - f = g_trace.vStart[ 0 ] + frac * ( g_trace.vEnd[ 0 ] - g_trace.vStart[ 0 ] ) - - ( ( g_trace.i << 6 ) + g_trace.tc->vBounds[ 0 ][ 0 ] ); + f = g_trace.vStart[0] + frac * (g_trace.vEnd[0] - g_trace.vStart[0]) + - ((g_trace.i << 6) + g_trace.tc->vBounds[0][0]); - if( f >= 0 && f <= 64 ) - { - f = g_trace.vStart[ 1 ] + frac * ( g_trace.vEnd[ 1 ] - g_trace.vStart[ 1 ] ) - - ( ( g_trace.j << 6 ) + g_trace.tc->vBounds[ 0 ][ 1 ] ); + if (f >= 0 && f <= 64) { + f = g_trace.vStart[1] + frac * (g_trace.vEnd[1] - g_trace.vStart[1]) + - ((g_trace.j << 6) + g_trace.tc->vBounds[0][1]); - if( f >= 0 && f <= 64 ) { - return qtrue; - } - } + if (f >= 0 && f <= 64) { + return qtrue; + } + } - return qfalse; + return qfalse; } /* @@ -797,49 +749,48 @@ qboolean CM_ValidateTerrainCollidePointSquare( float frac ) CM_ValidateTerrainCollidePointTri ==================== */ -qboolean CM_ValidateTerrainCollidePointTri( int eMode, float frac ) +qboolean CM_ValidateTerrainCollidePointTri(int eMode, float frac) { - float x0, y0; - float x, y; - float dx, dy; + float x0, y0; + float x, y; + float dx, dy; - x0 = ( g_trace.i << 6 ) + g_trace.tc->vBounds[ 0 ][ 0 ]; - dx = g_trace.vStart[ 0 ] + ( g_trace.vEnd[ 0 ] - g_trace.vStart[ 0 ] ) * frac; - x = x0 + 64; + x0 = (g_trace.i << 6) + g_trace.tc->vBounds[0][0]; + dx = g_trace.vStart[0] + (g_trace.vEnd[0] - g_trace.vStart[0]) * frac; + x = x0 + 64; - if( x0 > dx ) { - return qfalse; - } + if (x0 > dx) { + return qfalse; + } - if( x < dx ) { - return qfalse; - } + if (x < dx) { + return qfalse; + } - y0 = ( g_trace.j << 6 ) + g_trace.tc->vBounds[ 0 ][ 1 ]; - dy = g_trace.vStart[ 1 ] + ( g_trace.vEnd[ 1 ] - g_trace.vStart[ 1 ] ) * frac; - y = y0 + 64; + y0 = (g_trace.j << 6) + g_trace.tc->vBounds[0][1]; + dy = g_trace.vStart[1] + (g_trace.vEnd[1] - g_trace.vStart[1]) * frac; + y = y0 + 64; - if( y0 > dy ) { - return qfalse; - } + if (y0 > dy) { + return qfalse; + } - if( y < dy ) { - return qfalse; - } + if (y < dy) { + return qfalse; + } - switch( eMode ) - { - case 3: - return ( dx - x0 ) >= ( 64 - ( dy - y0 ) ); - case 4: - return ( dx - x0 ) <= ( dy - y0 ); - case 5: - return ( dx - x0 ) >= ( dy - y0 ); - case 6: - return ( dx - x0 ) <= ( 64 - ( dy - y0 ) ); - default: - return qtrue; - } + switch (eMode) { + case 3: + return (dx - x0) >= (64 - (dy - y0)); + case 4: + return (dx - x0) <= (dy - y0); + case 5: + return (dx - x0) >= (dy - y0); + case 6: + return (dx - x0) <= (64 - (dy - y0)); + default: + return qtrue; + } } /* @@ -847,63 +798,55 @@ qboolean CM_ValidateTerrainCollidePointTri( int eMode, float frac ) CM_TestTerrainCollideSquare ==================== */ -qboolean CM_TestTerrainCollideSquare( void ) +qboolean CM_TestTerrainCollideSquare(void) { - float *plane; - float frac0; - float enterFrac; - int eMode; + float *plane; + float frac0; + float enterFrac; + int eMode; - eMode = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].eMode; + eMode = g_trace.tc->squares[g_trace.i][g_trace.j].eMode; - if( !eMode ) { - return qfalse; - } + if (!eMode) { + return qfalse; + } - if( eMode >= 0 && eMode <= 2 ) - { - enterFrac = CM_CheckTerrainPlane( g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 0 ] ); + if (eMode >= 0 && eMode <= 2) { + enterFrac = CM_CheckTerrainPlane(g_trace.tc->squares[g_trace.i][g_trace.j].plane[0]); - plane = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 1 ]; - frac0 = CM_CheckTerrainPlane( plane ); + plane = g_trace.tc->squares[g_trace.i][g_trace.j].plane[1]; + frac0 = CM_CheckTerrainPlane(plane); - if( eMode == 2 ) - { - if( enterFrac > frac0 ) { - enterFrac = frac0; - } - } - else - { - if( enterFrac < frac0 ) { - enterFrac = frac0; - } - } + if (eMode == 2) { + if (enterFrac > frac0) { + enterFrac = frac0; + } + } else { + if (enterFrac < frac0) { + enterFrac = frac0; + } + } - if( enterFrac < g_trace.tw->trace.fraction && CM_ValidateTerrainCollidePointSquare( enterFrac ) ) - { - g_trace.tw->trace.fraction = enterFrac; - VectorCopy( plane, g_trace.tw->trace.plane.normal ); - g_trace.tw->trace.plane.dist = plane[ 3 ]; - return qtrue; - } - } - else - { - plane = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 0 ]; - enterFrac = CM_CheckTerrainPlane( plane ); + if (enterFrac < g_trace.tw->trace.fraction && CM_ValidateTerrainCollidePointSquare(enterFrac)) { + g_trace.tw->trace.fraction = enterFrac; + VectorCopy(plane, g_trace.tw->trace.plane.normal); + g_trace.tw->trace.plane.dist = plane[3]; + return qtrue; + } + } else { + plane = g_trace.tc->squares[g_trace.i][g_trace.j].plane[0]; + enterFrac = CM_CheckTerrainPlane(plane); - if( enterFrac < g_trace.tw->trace.fraction - && CM_ValidateTerrainCollidePointTri( g_trace.tc->squares[ g_trace.i ][ g_trace.j ].eMode, enterFrac ) ) - { - g_trace.tw->trace.fraction = enterFrac; - VectorCopy( plane, g_trace.tw->trace.plane.normal ); - g_trace.tw->trace.plane.dist = plane[ 3 ]; - return qtrue; - } - } + if (enterFrac < g_trace.tw->trace.fraction + && CM_ValidateTerrainCollidePointTri(g_trace.tc->squares[g_trace.i][g_trace.j].eMode, enterFrac)) { + g_trace.tw->trace.fraction = enterFrac; + VectorCopy(plane, g_trace.tw->trace.plane.normal); + g_trace.tw->trace.plane.dist = plane[3]; + return qtrue; + } + } - return qfalse; + return qfalse; } /* @@ -911,63 +854,54 @@ qboolean CM_TestTerrainCollideSquare( void ) CM_CheckStartInsideTerrain ==================== */ -static qboolean CM_CheckStartInsideTerrain( int i, int j, float fx, float fy ) +static qboolean CM_CheckStartInsideTerrain(int i, int j, float fx, float fy) { - float *plane; - float fDot; + float *plane; + float fDot; - if( i < 0 || i > 7 ) { - return qfalse; - } - if( j < 0 || j > 7 ) { - return qfalse; - } + if (i < 0 || i > 7) { + return qfalse; + } + if (j < 0 || j > 7) { + return qfalse; + } - if( !g_trace.tc->squares[ i ][ j ].eMode ) { - return qfalse; - } + if (!g_trace.tc->squares[i][j].eMode) { + return qfalse; + } - if( ( i + j ) & 1 ) - { - if( fx + fy >= 1 ) - { - if( g_trace.tc->squares[ i ][ j ].eMode == 6 ) { - return qfalse; - } - plane = g_trace.tc->squares[ i ][ j ].plane[ 0 ]; - } - else - { - if( g_trace.tc->squares[ i ][ j ].eMode == 3 ) { - return qfalse; - } - plane = g_trace.tc->squares[ i ][ j ].plane[ 1 ]; - } - } - else - { - if( fy >= fx ) - { - if( g_trace.tc->squares[ i ][ j ].eMode == 5 ) { - return qfalse; - } - plane = g_trace.tc->squares[ i ][ j ].plane[ 0 ]; - } - else - { - if( g_trace.tc->squares[ i ][ j ].eMode == 4 ) { - return qfalse; - } - plane = g_trace.tc->squares[ i ][ j ].plane[ 1 ]; - } - } + if ((i + j) & 1) { + if (fx + fy >= 1) { + if (g_trace.tc->squares[i][j].eMode == 6) { + return qfalse; + } + plane = g_trace.tc->squares[i][j].plane[0]; + } else { + if (g_trace.tc->squares[i][j].eMode == 3) { + return qfalse; + } + plane = g_trace.tc->squares[i][j].plane[1]; + } + } else { + if (fy >= fx) { + if (g_trace.tc->squares[i][j].eMode == 5) { + return qfalse; + } + plane = g_trace.tc->squares[i][j].plane[0]; + } else { + if (g_trace.tc->squares[i][j].eMode == 4) { + return qfalse; + } + plane = g_trace.tc->squares[i][j].plane[1]; + } + } - fDot = DotProduct( g_trace.vStart, plane ); - if( fDot <= plane[ 3 ] && fDot + 32.0f >= plane[ 3 ] ) { - return qtrue; - } + fDot = DotProduct(g_trace.vStart, plane); + if (fDot <= plane[3] && fDot + 32.0f >= plane[3]) { + return qtrue; + } - return qfalse; + return qfalse; } /* @@ -975,18 +909,18 @@ static qboolean CM_CheckStartInsideTerrain( int i, int j, float fx, float fy ) CM_PositionTestPointInTerrainCollide ==================== */ -qboolean CM_PositionTestPointInTerrainCollide( void ) +qboolean CM_PositionTestPointInTerrainCollide(void) { - int i0, j0; - float fx, fy; + int i0, j0; + float fx, fy; - fx = ( g_trace.vStart[ 0 ] - g_trace.tc->vBounds[ 0 ][ 0 ] ) * ( SURFACE_CLIP_EPSILON / 8 ); - fy = ( g_trace.vStart[ 1 ] - g_trace.tc->vBounds[ 0 ][ 1 ] ) * ( SURFACE_CLIP_EPSILON / 8 ); + fx = (g_trace.vStart[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8); + fy = (g_trace.vStart[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8); - i0 = ( int )floor( fx ); - j0 = ( int )floor( fy ); + i0 = (int)floor(fx); + j0 = (int)floor(fy); - return CM_CheckStartInsideTerrain( i0, j0, fx - i0, fy - j0 ); + return CM_CheckStartInsideTerrain(i0, j0, fx - i0, fy - j0); } /* @@ -994,185 +928,168 @@ qboolean CM_PositionTestPointInTerrainCollide( void ) CM_TracePointThroughTerrainCollide ==================== */ -void CM_TracePointThroughTerrainCollide( void ) +void CM_TracePointThroughTerrainCollide(void) { - int i0, j0, i1, j1; - int di, dj; - int d1, d2; - //int nTotal; - float fx, fy; - float dx, dy, dx2, dy2; + int i0, j0, i1, j1; + int di, dj; + int d1, d2; + //int nTotal; + float fx, fy; + float dx, dy, dx2, dy2; - fx = (g_trace.vStart[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8); - fy = (g_trace.vStart[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8); - i0 = (int64_t)floor(fx); - j0 = (int64_t)floor(fy); - i1 = (int64_t)floor((g_trace.vEnd[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8)); - j1 = (int64_t)floor((g_trace.vEnd[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8)); + fx = (g_trace.vStart[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8); + fy = (g_trace.vStart[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8); + i0 = (int64_t)floor(fx); + j0 = (int64_t)floor(fy); + i1 = (int64_t)floor((g_trace.vEnd[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8)); + j1 = (int64_t)floor((g_trace.vEnd[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8)); - const float dfx = fx - i0; - const float dfy = fy - j0; + const float dfx = fx - i0; + const float dfy = fy - j0; - if (CM_CheckStartInsideTerrain(i0, j0, dfx, dfy)) - { - g_trace.tw->trace.startsolid = qtrue; - g_trace.tw->trace.allsolid = qtrue; - g_trace.tw->trace.fraction = 0; - return; - } + if (CM_CheckStartInsideTerrain(i0, j0, dfx, dfy)) { + g_trace.tw->trace.startsolid = qtrue; + g_trace.tw->trace.allsolid = qtrue; + g_trace.tw->trace.fraction = 0; + return; + } - if (i0 == i1) - { - if (i0 < 0 || i0 > 7) { - return; - } + if (i0 == i1) { + if (i0 < 0 || i0 > 7) { + return; + } - if (j0 == j1) - { - if (j0 < 0 || j0 > 7) { - return; - } + if (j0 == j1) { + if (j0 < 0 || j0 > 7) { + return; + } - g_trace.i = i0; - g_trace.j = j0; - CM_TestTerrainCollideSquare(); - } - else if (j0 >= j1) - { - if (j0 > 7) - j0 = 7; - if (j1 < 0) - j1 = 0; + g_trace.i = i0; + g_trace.j = j0; + CM_TestTerrainCollideSquare(); + } else if (j0 >= j1) { + if (j0 > 7) { + j0 = 7; + } + if (j1 < 0) { + j1 = 0; + } - g_trace.i = i0; - for (g_trace.j = j0; g_trace.j >= j1; g_trace.j--) { - if (CM_TestTerrainCollideSquare()) { - return; - } - } - } - else - { - if (j0 < 0) - j0 = 0; - if (j1 > 7) - j1 = 7; + g_trace.i = i0; + for (g_trace.j = j0; g_trace.j >= j1; g_trace.j--) { + if (CM_TestTerrainCollideSquare()) { + return; + } + } + } else { + if (j0 < 0) { + j0 = 0; + } + if (j1 > 7) { + j1 = 7; + } - g_trace.i = i0; - for (g_trace.j = j0; g_trace.j <= j1; g_trace.j++) { - if (CM_TestTerrainCollideSquare()) { - return; - } - } - } - } - else if (j0 == j1) - { - if (j0 < 0 || j0 > 7) { - return; - } + g_trace.i = i0; + for (g_trace.j = j0; g_trace.j <= j1; g_trace.j++) { + if (CM_TestTerrainCollideSquare()) { + return; + } + } + } + } else if (j0 == j1) { + if (j0 < 0 || j0 > 7) { + return; + } - if (i0 >= i1) - { - if (i0 > 7) - i0 = 7; - if (i1 < 0) - i1 = 0; + if (i0 >= i1) { + if (i0 > 7) { + i0 = 7; + } + if (i1 < 0) { + i1 = 0; + } - g_trace.j = j0; - for (g_trace.i = i0; g_trace.i >= i1; g_trace.i--) { - if (CM_TestTerrainCollideSquare()) { - break; - } - } - } - else - { - if (i0 < 0) - i0 = 0; - if (i1 > 7) - i1 = 7; + g_trace.j = j0; + for (g_trace.i = i0; g_trace.i >= i1; g_trace.i--) { + if (CM_TestTerrainCollideSquare()) { + break; + } + } + } else { + if (i0 < 0) { + i0 = 0; + } + if (i1 > 7) { + i1 = 7; + } - g_trace.j = j0; - for (g_trace.i = i0; g_trace.i <= i1; g_trace.i++) { - if (CM_TestTerrainCollideSquare()) { - break; - } - } - } - } - else - { - dx = g_trace.vEnd[0] - g_trace.vStart[0]; - dy = g_trace.vEnd[1] - g_trace.vStart[1]; + g_trace.j = j0; + for (g_trace.i = i0; g_trace.i <= i1; g_trace.i++) { + if (CM_TestTerrainCollideSquare()) { + break; + } + } + } + } else { + dx = g_trace.vEnd[0] - g_trace.vStart[0]; + dy = g_trace.vEnd[1] - g_trace.vStart[1]; - // Fix - //== - // The original compares if delta float is zero - // not only it's slower, but it can be problematic if those floats are NaN - //== - if (i1 > i0) - { - // dx positive - d1 = 1; - di = i1 - i0; - dx2 = (i0 + 1 - fx) * dy; - } - else - { - d1 = -1; - di = i0 - i1; - dx = -dx; - dx2 = dfx * dy; - } + // Fix + //== + // The original compares if delta float is zero + // not only it's slower, but it can be problematic if those floats are NaN + //== + if (i1 > i0) { + // dx positive + d1 = 1; + di = i1 - i0; + dx2 = (i0 + 1 - fx) * dy; + } else { + d1 = -1; + di = i0 - i1; + dx = -dx; + dx2 = dfx * dy; + } - if (j1 > j0) - { - // dy positive - d2 = 1; - dj = di + j1 - j0 + 1; - dy2 = (j0 + 1 - fy) * dx; - } - else - { - d2 = -1; - dy = -dy; - dj = di + j0 - j1 + 1; - dy2 = dfy * dx; - dx2 = -dx2; - } + if (j1 > j0) { + // dy positive + d2 = 1; + dj = di + j1 - j0 + 1; + dy2 = (j0 + 1 - fy) * dx; + } else { + d2 = -1; + dy = -dy; + dj = di + j0 - j1 + 1; + dy2 = dfy * dx; + dx2 = -dx2; + } - g_trace.i = i0; - g_trace.j = j0; + g_trace.i = i0; + g_trace.j = j0; - while (1) - { - if (g_trace.i >= 0 && g_trace.i <= 7 && g_trace.j >= 0 && g_trace.j <= 7) - { - if (CM_TestTerrainCollideSquare()) { - return; - } - } + while (1) { + if (g_trace.i >= 0 && g_trace.i <= 7 && g_trace.j >= 0 && g_trace.j <= 7) { + if (CM_TestTerrainCollideSquare()) { + return; + } + } - dj--; - if (!dj) { - break; - } + dj--; + if (!dj) { + break; + } - if (dx2 < dy2) - { - dy2 -= dx2; - dx2 = dy; - g_trace.i += d1; - } - else - { - dx2 -= dy2; - dy2 = dx; - g_trace.j += d2; - } - } - } + if (dx2 < dy2) { + dy2 -= dx2; + dx2 = dy; + g_trace.i += d1; + } else { + dx2 -= dy2; + dy2 = dx; + g_trace.j += d2; + } + } + } } /* @@ -1180,87 +1097,88 @@ void CM_TracePointThroughTerrainCollide( void ) CM_TraceCylinderThroughTerrainCollide ==================== */ -void CM_TraceCylinderThroughTerrainCollide( traceWork_t *tw, const terrainCollide_t *tc ) +void CM_TraceCylinderThroughTerrainCollide(traceWork_t *tw, const terrainCollide_t *tc) { - int i0, j0, i1, j1; - float x0, y0; - float enterFrac; + int i0, j0, i1, j1; + float x0, y0; + float enterFrac; - i0 = ( int )( floor( tw->bounds[ 0 ][ 0 ] - tc->vBounds[ 0 ][ 0 ] ) * ( SURFACE_CLIP_EPSILON / 8 ) ); - i1 = ( int )( floor( tw->bounds[ 1 ][ 0 ] - tc->vBounds[ 0 ][ 0 ] ) * ( SURFACE_CLIP_EPSILON / 8 ) ); - j0 = ( int )( floor( tw->bounds[ 0 ][ 1 ] - tc->vBounds[ 0 ][ 1 ] ) * ( SURFACE_CLIP_EPSILON / 8 ) ); - j1 = ( int )( floor( tw->bounds[ 1 ][ 1 ] - tc->vBounds[ 0 ][ 1 ] ) * ( SURFACE_CLIP_EPSILON / 8 ) ); + i0 = (int)(floor(tw->bounds[0][0] - tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8)); + i1 = (int)(floor(tw->bounds[1][0] - tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8)); + j0 = (int)(floor(tw->bounds[0][1] - tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8)); + j1 = (int)(floor(tw->bounds[1][1] - tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8)); - if( i0 < 0 ) - i0 = 0; - if( j0 < 0 ) - j0 = 0; - if( i1 > 7 ) - i1 = 7; - if( j1 > 7 ) - j1 = 7; + if (i0 < 0) { + i0 = 0; + } + if (j0 < 0) { + j0 = 0; + } + if (i1 > 7) { + i1 = 7; + } + if (j1 > 7) { + j1 = 7; + } - y0 = ( j0 << 6 ) + tc->vBounds[ 0 ][ 1 ]; - for( g_trace.j = j0; g_trace.j <= j1; g_trace.j++ ) - { - x0 = ( i0 << 6 ) + tc->vBounds[ 0 ][ 0 ]; - for( g_trace.i = i0; g_trace.i <= i1; g_trace.i++ ) - { - switch( tc->squares[ g_trace.i ][ g_trace.j ].eMode ) - { - case 1: - case 2: - enterFrac = CM_CheckTerrainTriSphere( x0, y0, 0 ); - if( enterFrac < 0 ) - enterFrac = 0; - if( enterFrac < g_trace.tw->trace.fraction ) - { - g_trace.tw->trace.fraction = enterFrac; - VectorCopy( g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 0 ], g_trace.tw->trace.plane.normal ); - g_trace.tw->trace.plane.dist = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 0 ][ 3 ]; - } - enterFrac = CM_CheckTerrainTriSphere( x0, y0, 1 ); - if( enterFrac < 0 ) - enterFrac = 0; - if( enterFrac < g_trace.tw->trace.fraction ) - { - g_trace.tw->trace.fraction = enterFrac; - VectorCopy( g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 1 ], g_trace.tw->trace.plane.normal ); - g_trace.tw->trace.plane.dist = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 1 ][ 3 ]; - } - break; - case 3: - case 4: - enterFrac = CM_CheckTerrainTriSphere( x0, y0, 0 ); - if( enterFrac < 0 ) - enterFrac = 0; - if( enterFrac < g_trace.tw->trace.fraction ) - { - g_trace.tw->trace.fraction = enterFrac; - VectorCopy( g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 0 ], g_trace.tw->trace.plane.normal ); - g_trace.tw->trace.plane.dist = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 0 ][ 3 ]; - } - break; - case 5: - case 6: - enterFrac = CM_CheckTerrainTriSphere( x0, y0, 1 ); - if( enterFrac < 0 ) - enterFrac = 0; - if( enterFrac < g_trace.tw->trace.fraction ) - { - g_trace.tw->trace.fraction = enterFrac; - VectorCopy( g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 1 ], g_trace.tw->trace.plane.normal ); - g_trace.tw->trace.plane.dist = g_trace.tc->squares[ g_trace.i ][ g_trace.j ].plane[ 1 ][ 3 ]; - } - break; - default: - break; - } - x0 += 64; - } + y0 = (j0 << 6) + tc->vBounds[0][1]; + for (g_trace.j = j0; g_trace.j <= j1; g_trace.j++) { + x0 = (i0 << 6) + tc->vBounds[0][0]; + for (g_trace.i = i0; g_trace.i <= i1; g_trace.i++) { + switch (tc->squares[g_trace.i][g_trace.j].eMode) { + case 1: + case 2: + enterFrac = CM_CheckTerrainTriSphere(x0, y0, 0); + if (enterFrac < 0) { + enterFrac = 0; + } + if (enterFrac < g_trace.tw->trace.fraction) { + g_trace.tw->trace.fraction = enterFrac; + VectorCopy(g_trace.tc->squares[g_trace.i][g_trace.j].plane[0], g_trace.tw->trace.plane.normal); + g_trace.tw->trace.plane.dist = g_trace.tc->squares[g_trace.i][g_trace.j].plane[0][3]; + } + enterFrac = CM_CheckTerrainTriSphere(x0, y0, 1); + if (enterFrac < 0) { + enterFrac = 0; + } + if (enterFrac < g_trace.tw->trace.fraction) { + g_trace.tw->trace.fraction = enterFrac; + VectorCopy(g_trace.tc->squares[g_trace.i][g_trace.j].plane[1], g_trace.tw->trace.plane.normal); + g_trace.tw->trace.plane.dist = g_trace.tc->squares[g_trace.i][g_trace.j].plane[1][3]; + } + break; + case 3: + case 4: + enterFrac = CM_CheckTerrainTriSphere(x0, y0, 0); + if (enterFrac < 0) { + enterFrac = 0; + } + if (enterFrac < g_trace.tw->trace.fraction) { + g_trace.tw->trace.fraction = enterFrac; + VectorCopy(g_trace.tc->squares[g_trace.i][g_trace.j].plane[0], g_trace.tw->trace.plane.normal); + g_trace.tw->trace.plane.dist = g_trace.tc->squares[g_trace.i][g_trace.j].plane[0][3]; + } + break; + case 5: + case 6: + enterFrac = CM_CheckTerrainTriSphere(x0, y0, 1); + if (enterFrac < 0) { + enterFrac = 0; + } + if (enterFrac < g_trace.tw->trace.fraction) { + g_trace.tw->trace.fraction = enterFrac; + VectorCopy(g_trace.tc->squares[g_trace.i][g_trace.j].plane[1], g_trace.tw->trace.plane.normal); + g_trace.tw->trace.plane.dist = g_trace.tc->squares[g_trace.i][g_trace.j].plane[1][3]; + } + break; + default: + break; + } + x0 += 64; + } - y0 += 64; - } + y0 += 64; + } } /* @@ -1268,65 +1186,52 @@ void CM_TraceCylinderThroughTerrainCollide( traceWork_t *tw, const terrainCollid CM_TraceThroughTerrainCollide ==================== */ -void CM_TraceThroughTerrainCollide( traceWork_t *tw, terrainCollide_t *tc ) { - int i; +void CM_TraceThroughTerrainCollide(traceWork_t *tw, terrainCollide_t *tc) +{ + int i; - if( tw->bounds[ 0 ][ 0 ] >= tc->vBounds[ 1 ][ 0 ] || - tw->bounds[ 0 ][ 1 ] >= tc->vBounds[ 1 ][ 1 ] || - tw->bounds[ 0 ][ 2 ] >= tc->vBounds[ 1 ][ 2 ] || - tw->bounds[ 1 ][ 0 ] <= tc->vBounds[ 0 ][ 0 ] || - tw->bounds[ 1 ][ 1 ] <= tc->vBounds[ 0 ][ 1 ] || - tw->bounds[ 1 ][ 2 ] <= tc->vBounds[ 0 ][ 2 ] ) - { - return; - } + if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[0][1] >= tc->vBounds[1][1] + || tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][0] <= tc->vBounds[0][0] + || tw->bounds[1][1] <= tc->vBounds[0][1] || tw->bounds[1][2] <= tc->vBounds[0][2]) { + return; + } - g_trace.tw = tw; - g_trace.tc = tc; - VectorCopy( tw->start, g_trace.vStart ); - VectorCopy( tw->end, g_trace.vEnd ); + g_trace.tw = tw; + g_trace.tc = tc; + VectorCopy(tw->start, g_trace.vStart); + VectorCopy(tw->end, g_trace.vEnd); - if( sphere.use && cm_ter_usesphere->integer ) - { - VectorSubtract( tw->start, sphere.offset, g_trace.vStart ); - VectorSubtract( tw->end, sphere.offset, g_trace.vEnd ); - CM_TraceCylinderThroughTerrainCollide( tw, tc ); - } - else if( tw->isPoint ) - { - VectorCopy( tw->start, g_trace.vStart ); - VectorCopy( tw->end, g_trace.vEnd ); - CM_TracePointThroughTerrainCollide(); - } - else - { - if( tc->squares[ 0 ][ 0 ].plane[ 0 ][ 2 ] >= 0 ) - { - for( i = 0; i < 4; i++ ) - { - VectorAdd( tw->start, tw->offsets[ i ], g_trace.vStart ); - VectorAdd( tw->end, tw->offsets[ i ], g_trace.vEnd ); + if (sphere.use && cm_ter_usesphere->integer) { + VectorSubtract(tw->start, sphere.offset, g_trace.vStart); + VectorSubtract(tw->end, sphere.offset, g_trace.vEnd); + CM_TraceCylinderThroughTerrainCollide(tw, tc); + } else if (tw->isPoint) { + VectorCopy(tw->start, g_trace.vStart); + VectorCopy(tw->end, g_trace.vEnd); + CM_TracePointThroughTerrainCollide(); + } else { + if (tc->squares[0][0].plane[0][2] >= 0) { + for (i = 0; i < 4; i++) { + VectorAdd(tw->start, tw->offsets[i], g_trace.vStart); + VectorAdd(tw->end, tw->offsets[i], g_trace.vEnd); - CM_TracePointThroughTerrainCollide(); - if( tw->trace.allsolid ) { - return; - } - } - } - else - { - for( i = 4; i < 8; i++ ) - { - VectorAdd( tw->start, tw->offsets[ i ], g_trace.vStart ); - VectorAdd( tw->end, tw->offsets[ i ], g_trace.vEnd ); + CM_TracePointThroughTerrainCollide(); + if (tw->trace.allsolid) { + return; + } + } + } else { + for (i = 4; i < 8; i++) { + VectorAdd(tw->start, tw->offsets[i], g_trace.vStart); + VectorAdd(tw->end, tw->offsets[i], g_trace.vEnd); - CM_TracePointThroughTerrainCollide(); - if( tw->trace.allsolid ) { - return; - } - } - } - } + CM_TracePointThroughTerrainCollide(); + if (tw->trace.allsolid) { + return; + } + } + } + } } /* @@ -1334,66 +1239,53 @@ void CM_TraceThroughTerrainCollide( traceWork_t *tw, terrainCollide_t *tc ) { CM_PositionTestInTerrainCollide ==================== */ -qboolean CM_PositionTestInTerrainCollide( traceWork_t *tw, terrainCollide_t *tc ) { - int i; +qboolean CM_PositionTestInTerrainCollide(traceWork_t *tw, terrainCollide_t *tc) +{ + int i; - if( tw->bounds[ 0 ][ 0 ] >= tc->vBounds[ 1 ][ 0 ] || - tw->bounds[ 0 ][ 1 ] >= tc->vBounds[ 1 ][ 1 ] || - tw->bounds[ 0 ][ 2 ] >= tc->vBounds[ 1 ][ 2 ] || - tw->bounds[ 1 ][ 0 ] <= tc->vBounds[ 0 ][ 0 ] || - tw->bounds[ 1 ][ 1 ] <= tc->vBounds[ 0 ][ 1 ] || - tw->bounds[ 1 ][ 2 ] <= tc->vBounds[ 0 ][ 2 ] ) - { - return qfalse; - } + if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[0][1] >= tc->vBounds[1][1] + || tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][0] <= tc->vBounds[0][0] + || tw->bounds[1][1] <= tc->vBounds[0][1] || tw->bounds[1][2] <= tc->vBounds[0][2]) { + return qfalse; + } - g_trace.tw = tw; - g_trace.tc = tc; - VectorCopy( tw->start, g_trace.vStart ); - VectorCopy( tw->end, g_trace.vEnd ); + g_trace.tw = tw; + g_trace.tc = tc; + VectorCopy(tw->start, g_trace.vStart); + VectorCopy(tw->end, g_trace.vEnd); - if( sphere.use && cm_ter_usesphere->integer ) - { - VectorSubtract( tw->start, sphere.offset, g_trace.vStart ); - VectorSubtract( tw->end, sphere.offset, g_trace.vEnd ); - CM_TraceCylinderThroughTerrainCollide( tw, tc ); - return tw->trace.startsolid; - } - else if( tw->isPoint ) - { - VectorCopy( tw->start, g_trace.vStart ); - VectorCopy( tw->end, g_trace.vEnd ); - return CM_PositionTestPointInTerrainCollide(); - } - else - { - if( tc->squares[ 0 ][ 0 ].plane[ 0 ][ 2 ] >= 0 ) - { - for( i = 0; i < 4; i++ ) - { - VectorAdd( tw->start, tw->offsets[ i ], g_trace.vStart ); - VectorAdd( tw->end, tw->offsets[ i ], g_trace.vEnd ); + if (sphere.use && cm_ter_usesphere->integer) { + VectorSubtract(tw->start, sphere.offset, g_trace.vStart); + VectorSubtract(tw->end, sphere.offset, g_trace.vEnd); + CM_TraceCylinderThroughTerrainCollide(tw, tc); + return tw->trace.startsolid; + } else if (tw->isPoint) { + VectorCopy(tw->start, g_trace.vStart); + VectorCopy(tw->end, g_trace.vEnd); + return CM_PositionTestPointInTerrainCollide(); + } else { + if (tc->squares[0][0].plane[0][2] >= 0) { + for (i = 0; i < 4; i++) { + VectorAdd(tw->start, tw->offsets[i], g_trace.vStart); + VectorAdd(tw->end, tw->offsets[i], g_trace.vEnd); - if( CM_PositionTestPointInTerrainCollide() ) { - return qtrue; - } - } - } - else - { - for( i = 4; i < 8; i++ ) - { - VectorAdd( tw->start, tw->offsets[ i ], g_trace.vStart ); - VectorAdd( tw->end, tw->offsets[ i ], g_trace.vEnd ); + if (CM_PositionTestPointInTerrainCollide()) { + return qtrue; + } + } + } else { + for (i = 4; i < 8; i++) { + VectorAdd(tw->start, tw->offsets[i], g_trace.vStart); + VectorAdd(tw->end, tw->offsets[i], g_trace.vEnd); - if( CM_PositionTestPointInTerrainCollide() ) { - return qtrue; - } - } - } - } + if (CM_PositionTestPointInTerrainCollide()) { + return qtrue; + } + } + } + } - return qfalse; + return qfalse; } /* @@ -1401,173 +1293,157 @@ qboolean CM_PositionTestInTerrainCollide( traceWork_t *tw, terrainCollide_t *tc CM_SightTracePointThroughTerrainCollide ==================== */ -qboolean CM_SightTracePointThroughTerrainCollide( void ) +qboolean CM_SightTracePointThroughTerrainCollide(void) { - int i0, j0; - int i1, j1; - int di, dj; - float fx, fy; - float dx, dy, dx2, dy2; - float d1, d2; + int i0, j0; + int i1, j1; + int di, dj; + float fx, fy; + float dx, dy, dx2, dy2; + float d1, d2; - fx = ( g_trace.vStart[ 0 ] - g_trace.tc->vBounds[ 0 ][ 0 ] ) * ( SURFACE_CLIP_EPSILON / 8 ); - fy = ( g_trace.vStart[ 1 ] - g_trace.tc->vBounds[ 0 ][ 1 ] ) * ( SURFACE_CLIP_EPSILON / 8 ); - i0 = ( int )floor( fx ); - j0 = ( int )floor( fy ); - i1 = ( int )floor( ( g_trace.vEnd[ 0 ] - g_trace.tc->vBounds[ 0 ][ 0 ] ) * ( SURFACE_CLIP_EPSILON / 8 ) ); - j1 = ( int )floor( ( g_trace.vEnd[ 1 ] - g_trace.tc->vBounds[ 0 ][ 1 ] ) * ( SURFACE_CLIP_EPSILON / 8 ) ); + fx = (g_trace.vStart[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8); + fy = (g_trace.vStart[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8); + i0 = (int)floor(fx); + j0 = (int)floor(fy); + i1 = (int)floor((g_trace.vEnd[0] - g_trace.tc->vBounds[0][0]) * (SURFACE_CLIP_EPSILON / 8)); + j1 = (int)floor((g_trace.vEnd[1] - g_trace.tc->vBounds[0][1]) * (SURFACE_CLIP_EPSILON / 8)); - if( CM_CheckStartInsideTerrain( i0, j0, fx - i0, fy - j0 ) ) { - return qfalse; - } + if (CM_CheckStartInsideTerrain(i0, j0, fx - i0, fy - j0)) { + return qfalse; + } - if( i0 == i1 ) - { - if( i0 < 0 || i0 > 7 ) { - return qtrue; - } + if (i0 == i1) { + if (i0 < 0 || i0 > 7) { + return qtrue; + } - if( j0 == j1 ) - { - if( j0 < 0 || j0 > 7 ) { - return qtrue; - } + if (j0 == j1) { + if (j0 < 0 || j0 > 7) { + return qtrue; + } - g_trace.i = i0; - g_trace.j = j0; - return !CM_TestTerrainCollideSquare(); - } - else if( j0 >= j1 ) - { - if( j0 > 7 ) - j0 = 7; - if( j1 < 0 ) - j1 = 0; + g_trace.i = i0; + g_trace.j = j0; + return !CM_TestTerrainCollideSquare(); + } else if (j0 >= j1) { + if (j0 > 7) { + j0 = 7; + } + if (j1 < 0) { + j1 = 0; + } - g_trace.i = i0; - for( g_trace.j = j0; g_trace.j >= j1; g_trace.j-- ) { - if( CM_TestTerrainCollideSquare() ) { - return qfalse; - } - } - } - else - { - if( j0 < 0 ) - j0 = 0; - if( j1 > 7 ) - j1 = 7; + g_trace.i = i0; + for (g_trace.j = j0; g_trace.j >= j1; g_trace.j--) { + if (CM_TestTerrainCollideSquare()) { + return qfalse; + } + } + } else { + if (j0 < 0) { + j0 = 0; + } + if (j1 > 7) { + j1 = 7; + } - g_trace.i = i0; - for( g_trace.j = j0; g_trace.j <= j1; g_trace.j++ ) { - if( CM_TestTerrainCollideSquare() ) { - return qfalse; - } - } - } - } - else if( j0 == j1 ) - { - if( j0 < 0 || j0 > 7 ) { - return qtrue; - } + g_trace.i = i0; + for (g_trace.j = j0; g_trace.j <= j1; g_trace.j++) { + if (CM_TestTerrainCollideSquare()) { + return qfalse; + } + } + } + } else if (j0 == j1) { + if (j0 < 0 || j0 > 7) { + return qtrue; + } - if( i0 >= i1 ) - { - if( i0 > 7 ) - i0 = 7; - if( i1 < 0 ) - i1 = 0; + if (i0 >= i1) { + if (i0 > 7) { + i0 = 7; + } + if (i1 < 0) { + i1 = 0; + } - g_trace.j = j0; - for( g_trace.i = i0; g_trace.i >= i1; g_trace.i-- ) { - if( CM_TestTerrainCollideSquare() ) { - return qfalse; - } - } - } - else - { - if( i0 < 0 ) - i0 = 0; - if( i1 > 7 ) - i1 = 7; + g_trace.j = j0; + for (g_trace.i = i0; g_trace.i >= i1; g_trace.i--) { + if (CM_TestTerrainCollideSquare()) { + return qfalse; + } + } + } else { + if (i0 < 0) { + i0 = 0; + } + if (i1 > 7) { + i1 = 7; + } - g_trace.j = j0; - for( g_trace.i = i0; g_trace.i <= i1; g_trace.i++ ) { - if( CM_TestTerrainCollideSquare() ) { - return qfalse; - } - } - } - } - else - { - dx = g_trace.vEnd[ 0 ] - g_trace.vStart[ 0 ]; - dy = g_trace.vEnd[ 1 ] - g_trace.vStart[ 1 ]; + g_trace.j = j0; + for (g_trace.i = i0; g_trace.i <= i1; g_trace.i++) { + if (CM_TestTerrainCollideSquare()) { + return qfalse; + } + } + } + } else { + dx = g_trace.vEnd[0] - g_trace.vStart[0]; + dy = g_trace.vEnd[1] - g_trace.vStart[1]; - if( dx > 0 ) - { - d1 = 1; - di = i1 - i0; - dx2 = ( i0 + 1 - fx ) * dy; - } - else - { - d1 = -1; - di = i0 - i1; - dx = -dx; - dx2 = ( fx - i0 ) * dy; - } + if (dx > 0) { + d1 = 1; + di = i1 - i0; + dx2 = (i0 + 1 - fx) * dy; + } else { + d1 = -1; + di = i0 - i1; + dx = -dx; + dx2 = (fx - i0) * dy; + } - if( dy > 0 ) - { - d2 = 1; - dj = di + j1 - j0 + 1; - dy2 = ( j0 + 1 - fy ) * dx; - } - else - { - d2 = -1; - dy = -dy; - dj = di + j0 - j1 + 1; - dy2 = ( fy - j0 ) * dx; - dx2 = -dx2; - } + if (dy > 0) { + d2 = 1; + dj = di + j1 - j0 + 1; + dy2 = (j0 + 1 - fy) * dx; + } else { + d2 = -1; + dy = -dy; + dj = di + j0 - j1 + 1; + dy2 = (fy - j0) * dx; + dx2 = -dx2; + } - g_trace.i = i0; - g_trace.j = j0; + g_trace.i = i0; + g_trace.j = j0; - while( 1 ) - { - if( g_trace.i >= 0 && g_trace.i <= 7 && g_trace.j >= 0 && g_trace.j <= 7 ) - { - if( CM_TestTerrainCollideSquare() ) { - return qfalse; - } - } + while (1) { + if (g_trace.i >= 0 && g_trace.i <= 7 && g_trace.j >= 0 && g_trace.j <= 7) { + if (CM_TestTerrainCollideSquare()) { + return qfalse; + } + } - dj--; - if( !dj ) { - break; - } + dj--; + if (!dj) { + break; + } - if( dx2 < dy2 ) - { - dy2 -= dx2; - dx2 = dy; - g_trace.i += d1; - } - else - { - dx2 -= dy2; - dy2 = dx; - g_trace.j += d2; - } - } - } + if (dx2 < dy2) { + dy2 -= dx2; + dx2 = dy; + g_trace.i += d1; + } else { + dx2 -= dy2; + dy2 = dx; + g_trace.j += d2; + } + } + } - return qtrue; + return qtrue; } /* @@ -1575,60 +1451,48 @@ qboolean CM_SightTracePointThroughTerrainCollide( void ) CM_SightTraceThroughTerrainCollide ==================== */ -qboolean CM_SightTraceThroughTerrainCollide( traceWork_t *tw, terrainCollide_t *tc ) +qboolean CM_SightTraceThroughTerrainCollide(traceWork_t *tw, terrainCollide_t *tc) { - int i; + int i; - if( tw->bounds[ 0 ][ 0 ] >= tc->vBounds[ 1 ][ 0 ] || - tw->bounds[ 0 ][ 1 ] >= tc->vBounds[ 1 ][ 1 ] || - tw->bounds[ 0 ][ 2 ] >= tc->vBounds[ 1 ][ 2 ] || - tw->bounds[ 1 ][ 0 ] <= tc->vBounds[ 0 ][ 0 ] || - tw->bounds[ 1 ][ 1 ] <= tc->vBounds[ 0 ][ 1 ] || - tw->bounds[ 1 ][ 2 ] <= tc->vBounds[ 0 ][ 2 ] ) - { - return qtrue; - } + if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[0][1] >= tc->vBounds[1][1] + || tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][0] <= tc->vBounds[0][0] + || tw->bounds[1][1] <= tc->vBounds[0][1] || tw->bounds[1][2] <= tc->vBounds[0][2]) { + return qtrue; + } - g_trace.tw = tw; - g_trace.tc = tc; - VectorCopy( tw->start, g_trace.vStart ); - VectorCopy( tw->end, g_trace.vEnd ); + g_trace.tw = tw; + g_trace.tc = tc; + VectorCopy(tw->start, g_trace.vStart); + VectorCopy(tw->end, g_trace.vEnd); - if( tw->isPoint ) - { - VectorCopy( tw->start, g_trace.vStart ); - VectorCopy( tw->end, g_trace.vEnd ); - return CM_SightTracePointThroughTerrainCollide(); - } - else - { - if( tc->squares[ 0 ][ 0 ].plane[ 0 ][ 2 ] >= 0 ) - { - for( i = 0; i < 4; i++ ) - { - VectorAdd( tw->start, tw->offsets[ i ], g_trace.vStart ); - VectorAdd( tw->end, tw->offsets[ i ], g_trace.vEnd ); + if (tw->isPoint) { + VectorCopy(tw->start, g_trace.vStart); + VectorCopy(tw->end, g_trace.vEnd); + return CM_SightTracePointThroughTerrainCollide(); + } else { + if (tc->squares[0][0].plane[0][2] >= 0) { + for (i = 0; i < 4; i++) { + VectorAdd(tw->start, tw->offsets[i], g_trace.vStart); + VectorAdd(tw->end, tw->offsets[i], g_trace.vEnd); - if( !CM_SightTracePointThroughTerrainCollide() ) { - return qfalse; - } - } - } - else - { - for( i = 4; i < 8; i++ ) - { - VectorAdd( tw->start, tw->offsets[ i ], g_trace.vStart ); - VectorAdd( tw->end, tw->offsets[ i ], g_trace.vEnd ); + if (!CM_SightTracePointThroughTerrainCollide()) { + return qfalse; + } + } + } else { + for (i = 4; i < 8; i++) { + VectorAdd(tw->start, tw->offsets[i], g_trace.vStart); + VectorAdd(tw->end, tw->offsets[i], g_trace.vEnd); - if( !CM_SightTracePointThroughTerrainCollide() ) { - return qfalse; - } - } - } - } + if (!CM_SightTracePointThroughTerrainCollide()) { + return qfalse; + } + } + } + } - return qtrue; + return qtrue; } /* @@ -1636,7 +1500,7 @@ qboolean CM_SightTraceThroughTerrainCollide( traceWork_t *tw, terrainCollide_t * CM_TerrainSquareType ==================== */ -int CM_TerrainSquareType( int iTerrainPatch, int i, int j ) +int CM_TerrainSquareType(int iTerrainPatch, int i, int j) { - return cm.terrain[ iTerrainPatch ].tc.squares[ i ][ j ].eMode; + return cm.terrain[iTerrainPatch].tc.squares[i][j].eMode; } diff --git a/code/qcommon/cm_terrain.h b/code/qcommon/cm_terrain.h index 83fe5c15..7d2e7df0 100644 --- a/code/qcommon/cm_terrain.h +++ b/code/qcommon/cm_terrain.h @@ -28,45 +28,43 @@ void CM_TraceThroughTerPatchCollide(traceWork_t *tw, const struct terPatchCollid qboolean CM_PositionTestInTerPatchCollide(traceWork_t *tw, const struct terPatchCollide_s *tc); */ -#ifndef CM_TERRAIN_H -#define CM_TERRAIN_H +#pragma once #ifdef __cplusplus extern "C" { #endif -#define TER_QUADS_PER_ROW 8 -#define TER_TRIS_PER_PATCH (TER_QUADS_PER_ROW * TER_QUADS_PER_ROW * 2) -#define TER_PLANES_PER_TRI 5 +#define TER_QUADS_PER_ROW 8 +#define TER_TRIS_PER_PATCH (TER_QUADS_PER_ROW * TER_QUADS_PER_ROW * 2) +#define TER_PLANES_PER_TRI 5 -typedef struct terTriangle_s { - cplane_t planes[TER_PLANES_PER_TRI]; // 0 is the surface plane, 3 border planes follow and a cap to give it some finite volume -} terTriangle_t; + typedef struct terTriangle_s { + cplane_t planes + [TER_PLANES_PER_TRI]; // 0 is the surface plane, 3 border planes follow and a cap to give it some finite volume + } terTriangle_t; -typedef struct terPatchCollide_s { - vec3_t bounds[2]; + typedef struct terPatchCollide_s { + vec3_t bounds[2]; - baseshader_t *shader; + baseshader_t *shader; - terTriangle_t tris[TER_TRIS_PER_PATCH]; -} terPatchCollide_t; + terTriangle_t tris[TER_TRIS_PER_PATCH]; + } terPatchCollide_t; -typedef struct terrainCollideSquare_s { - vec4_t plane[ 2 ]; - int eMode; -} terrainCollideSquare_t; + typedef struct terrainCollideSquare_s { + vec4_t plane[2]; + int eMode; + } terrainCollideSquare_t; -typedef struct terrainCollide_s { - vec3_t vBounds[ 2 ]; - terrainCollideSquare_t squares[ 8 ][ 8 ]; -} terrainCollide_t; + typedef struct terrainCollide_s { + vec3_t vBounds[2]; + terrainCollideSquare_t squares[8][8]; + } terrainCollide_t; -void CM_PrepareGenerateTerrainCollide( void ); -void CM_GenerateTerrainCollide( cTerraPatch_t *patch, terrainCollide_t *tc ); -int CM_TerrainSquareType( int iTerrainPatch, int i, int j ); + void CM_PrepareGenerateTerrainCollide(void); + void CM_GenerateTerrainCollide(cTerraPatch_t *patch, terrainCollide_t *tc); + int CM_TerrainSquareType(int iTerrainPatch, int i, int j); #ifdef __cplusplus } #endif - -#endif // CM_TERRAIN_H From aa209e0aaf5c5ab8aa1e3e36b4d45bc52fdde264 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 21:09:26 +0100 Subject: [PATCH 0085/2040] Fixed plane distance not being copied correctly with terrain square mode 5 or 6 --- code/qcommon/cm_terrain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index ede3d330..2babe2aa 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -216,6 +216,7 @@ void CM_PickTerrainSquareMode(terrainCollideSquare_t *square, vec3_t vTest, int } } else if (square->eMode == 5 || square->eMode == 6) { VectorCopy(square->plane[1], square->plane[0]); + square->plane[0][3] = square->plane[1][3]; } } From e73be7ef5ca8a034c5284369bae357ae734f1c55 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 21:19:04 +0100 Subject: [PATCH 0086/2040] Smoke grenades don't exist in vanilla Allied Assault --- code/fgame/player.cpp | 44 ++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 87df5a5f..56b47b62 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -2586,17 +2586,21 @@ void Player::InitMaxAmmo(void) GiveAmmo("heavy", 0, 5); GiveAmmo("shotgun", 0, 50); - // - // Team tactics ammunition - // - GiveAmmo("landmine", 0, 5); + if (g_target_game >= target_game_e::TG_MOHTT) { + // + // Team tactics ammunition + // + GiveAmmo("landmine", 0, 5); + } - // - // Team assault ammunition - // - GiveAmmo("smokegrenade", 0, 5); - GiveAmmo("asmokegrenade", 0, 5); - GiveAmmo("riflegrenade", 0, 3); + if (g_target_game >= target_game_e::TG_MOHTA) { + // + // Team assault ammunition + // + GiveAmmo("smokegrenade", 0, 5); + GiveAmmo("asmokegrenade", 0, 5); + GiveAmmo("riflegrenade", 0, 3); + } } void Player::InitWeapons(void) @@ -8907,27 +8911,37 @@ void Player::EquipWeapons() switch (nationality) { case NA_BRITISH: giveItem("weapons/mills_grenade.tik"); - giveItem("weapons/M18_smoke_grenade.tik"); + if (g_target_game >= target_game_e::TG_MOHTA) { + giveItem("weapons/M18_smoke_grenade.tik"); + } giveItem("weapons/Webley_Revolver.tik"); break; case NA_RUSSIAN: giveItem("weapons/Russian_F1_grenade.tik"); - giveItem("weapons/RDG-1_Smoke_grenade.tik"); + if (g_target_game >= target_game_e::TG_MOHTA) { + giveItem("weapons/RDG-1_Smoke_grenade.tik"); + } giveItem("weapons/Nagant_revolver.tik"); break; case NA_GERMAN: giveItem("weapons/steilhandgranate.tik"); - giveItem("weapons/nebelhandgranate.tik"); + if (g_target_game >= target_game_e::TG_MOHTA) { + giveItem("weapons/nebelhandgranate.tik"); + } giveItem("weapons/p38.tik"); break; case NA_ITALIAN: giveItem("weapons/it_w_bomba.tik"); - giveItem("weapons/it_w_bombabreda.tik"); + if (g_target_game >= target_game_e::TG_MOHTA) { + giveItem("weapons/it_w_bombabreda.tik"); + } giveItem("weapons/it_w_beretta.tik"); break; default: giveItem("weapons/m2frag_grenade.tik"); - giveItem("weapons/M18_smoke_grenade.tik"); + if (g_target_game >= target_game_e::TG_MOHTA) { + giveItem("weapons/M18_smoke_grenade.tik"); + } giveItem("weapons/colt45.tik"); break; } From 0a31ab75587aa60881a583a873b54f780124e066 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 21:23:59 +0100 Subject: [PATCH 0087/2040] Use the correct view model animation for the kar98 mortar --- code/cgame/cg_viewmodelanim.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/cgame/cg_viewmodelanim.c b/code/cgame/cg_viewmodelanim.c index e53fe7ef..06fe1d94 100644 --- a/code/cgame/cg_viewmodelanim.c +++ b/code/cgame/cg_viewmodelanim.c @@ -308,6 +308,9 @@ int CG_GetVMAnimPrefixIndex() if (!Q_stricmp(szWeaponName, "Panzerschreck")) { return WPREFIX_PANZERSCHRECK; } + if (!Q_stricmp(szWeaponName, "Gewehrgranate")) { + return WPREFIX_KAR98_MORTAR; + } if (!Q_stricmp(szWeaponName, "Shotgun")) { return WPREFIX_SHOTGUN; } From e8109076f489badd3f28c25e8ccf18bae86d58da Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 23:03:41 +0100 Subject: [PATCH 0088/2040] Assign shaders to surfaces that don't have a shader assigned --- code/tiki/tiki_files.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 4f36dc6c..3d87867d 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -176,8 +176,8 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) TIKI_InitSetup(&loaddef); - loaddef.path = path; - loaddef.numanims = 0; + loaddef.path = path; + loaddef.numanims = 0; loaddef.numserverinitcmds = 0; loaddef.numclientinitcmds = 0; @@ -451,6 +451,33 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapnumSurfaces) { + skelmodel = TIKI_GetSkel(temp.tiki.mesh[i]); + + surf = skelmodel->pSurfaces; + + for (j = 0; j < skelmodel->numSurfaces; j++, surf = surf->pNext) { + tikiSurf = &tiki->surfaces[surfOffset + j]; + + if (tikiSurf->numskins) { + // Skip surfaces with skins + continue; + } + + Q_strncpyz(tikiSurf->name, surf->name, sizeof(tikiSurf->name)); + + if (strlen(surf->name) != 9 || !Q_strncmp(surf->name, "material", 8)) { + Q_strncpyz(tikiSurf->shader[0], surf->name, sizeof(tikiSurf->shader[0])); + } + + tikiSurf->numskins = 1; + } + } + if (!tiki->radius) { TIKI_CalcRadius(tiki); } From 56044dd8f8d5b04de648e6a7f9d8bda71da40e9c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 23:19:55 +0100 Subject: [PATCH 0089/2040] HideMouse doesn't take parameters --- code/fgame/scriptthread.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index 468126f3..be8438a9 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -3725,13 +3725,6 @@ void ScriptThread::EventHideMouse(Event *ev) { gentity_t *ent; int i; - str name; - - if (game.maxclients <= 0) { - return; - } - - name = ev->GetString(1); for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { if (!ent->inuse || !ent->client) { From 0ed92943de43161ff0f41651be5c01dc3b39d39f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Feb 2024 23:22:06 +0100 Subject: [PATCH 0090/2040] Fixed commands not being executed properly on a specific type of array of listeners --- code/script/scriptvm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/script/scriptvm.cpp b/code/script/scriptvm.cpp index ce0e0247..1f9e6cff 100644 --- a/code/script/scriptvm.cpp +++ b/code/script/scriptvm.cpp @@ -682,7 +682,7 @@ void ScriptVM::execCmdMethodCommon(op_parmNum_t param) array.CastConstArrayValue(); for (uintptr_t i = array.arraysize(); i > 0; i--) { - Listener *const listener = array[i]->listenerAt(i); + Listener *const listener = array.listenerAt(i); if (listener) { executeCommand(listener, param, eventNum); } From d50128505795d6099c4c4a3050a4e18865665773 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 15:47:48 +0100 Subject: [PATCH 0091/2040] Play pain animation only in 2.0 and above --- code/fgame/player.cpp | 250 +++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 124 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 56b47b62..0ed199f1 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -6161,145 +6161,147 @@ void Player::DamageFeedback(void) damage_blend += (damage_blood / realcount) * bcolor; } - // - // Since 2.0: Try to find and play pain animation - // - if (getMoveType() == MOVETYPE_PORTABLE_TURRET) { - // use mg42 pain animation - painAnim = "mg42_tripod_"; - } else { - Weapon *pWeap; - const char *itemName; - // try to find an animation + if (g_target_game >= target_game_e::TG_MOHTA) { + // + // Since 2.0: Try to find and play pain animation + // + if (getMoveType() == MOVETYPE_PORTABLE_TURRET) { + // use mg42 pain animation + painAnim = "mg42_tripod_"; + } else { + Weapon *pWeap; + const char *itemName; + // try to find an animation - pWeap = GetActiveWeapon(WEAPON_MAIN); - if (pWeap) { - int weapon_class; + pWeap = GetActiveWeapon(WEAPON_MAIN); + if (pWeap) { + int weapon_class; - weapon_class = pWeap->GetWeaponClass(); - if (weapon_class & WEAPON_CLASS_PISTOL) { - painAnim = "pistol_"; - } else if (weapon_class & WEAPON_CLASS_RIFLE) { - painAnim = "rifle_"; - } else if (weapon_class & WEAPON_CLASS_SMG) { - // get the animation name from the item name - itemName = pWeap->GetItemName(); + weapon_class = pWeap->GetWeaponClass(); + if (weapon_class & WEAPON_CLASS_PISTOL) { + painAnim = "pistol_"; + } else if (weapon_class & WEAPON_CLASS_RIFLE) { + painAnim = "rifle_"; + } else if (weapon_class & WEAPON_CLASS_SMG) { + // get the animation name from the item name + itemName = pWeap->GetItemName(); - if (!Q_stricmp(itemName, "MP40")) { - painAnim = "mp40_"; - } else if (!Q_stricmp(itemName, "Sten Mark II")) { - painAnim = "sten_"; + if (!Q_stricmp(itemName, "MP40")) { + painAnim = "mp40_"; + } else if (!Q_stricmp(itemName, "Sten Mark II")) { + painAnim = "sten_"; + } else { + painAnim = "smg_"; + } + } else if (weapon_class & WEAPON_CLASS_MG) { + itemName = pWeap->GetItemName(); + + if (!Q_stricmp(itemName, "StG 44")) { + painAnim = "mp44_"; + } else { + painAnim = "mg_"; + } + } else if (weapon_class & WEAPON_CLASS_GRENADE) { + itemName = pWeap->GetItemName(); + + // 2.30: use landmine animations + if (!Q_stricmp(itemName, "Minedetector")) { + painAnim = "minedetector_"; + } else if (!Q_stricmp(itemName, "Minensuchgerat")) { + painAnim = "minedetectoraxis_"; + } else if (!Q_stricmp(itemName, "LandmineAllies")) { + painAnim = "mine_"; + } else if (!Q_stricmp(itemName, "LandmineAxis")) { + painAnim = "mine_"; + } else if (!Q_stricmp(itemName, "LandmineAxis")) { + painAnim = "grenade_"; + } + } else if (weapon_class & WEAPON_CLASS_HEAVY) { + itemName = pWeap->GetItemName(); + + if (!Q_stricmp(itemName, "Shotgun")) { + painAnim = "shotgun_"; + } else { + // Defaults to bazooka + painAnim = "bazooka_"; + } } else { - painAnim = "smg_"; - } - } else if (weapon_class & WEAPON_CLASS_MG) { - itemName = pWeap->GetItemName(); + itemName = pWeap->GetItemName(); - if (!Q_stricmp(itemName, "StG 44")) { - painAnim = "mp44_"; - } else { - painAnim = "mg_"; - } - } else if (weapon_class & WEAPON_CLASS_GRENADE) { - itemName = pWeap->GetItemName(); - - // 2.30: use landmine animations - if (!Q_stricmp(itemName, "Minedetector")) { - painAnim = "minedetector_"; - } else if (!Q_stricmp(itemName, "Minensuchgerat")) { - painAnim = "minedetectoraxis_"; - } else if (!Q_stricmp(itemName, "LandmineAllies")) { - painAnim = "mine_"; - } else if (!Q_stricmp(itemName, "LandmineAxis")) { - painAnim = "mine_"; - } else if (!Q_stricmp(itemName, "LandmineAxis")) { - painAnim = "grenade_"; - } - } else if (weapon_class & WEAPON_CLASS_HEAVY) { - itemName = pWeap->GetItemName(); - - if (!Q_stricmp(itemName, "Shotgun")) { - painAnim = "shotgun_"; - } else { - // Defaults to bazooka - painAnim = "bazooka_"; + if (!Q_stricmp(itemName, "Packed MG42 Turret")) { + painAnim = "mg42_"; + } else { + // Default animation if not found + painAnim = "unarmed_"; + } } } else { - itemName = pWeap->GetItemName(); - - if (!Q_stricmp(itemName, "Packed MG42 Turret")) { - painAnim = "mg42_"; - } else { - // Default animation if not found - painAnim = "unarmed_"; - } + painAnim = "unarmed_"; } + + // use the animation based on the movement + if (m_iMovePosFlags & MPF_POSITION_CROUCHING) { + painAnim += "crouch_"; + } else { + painAnim += "stand_"; + } + } + + painAnim += "hit_"; + + if (pain_dir == PAIN_REAR || pain_location == HITLOC_TORSO_MID || HITLOC_TORSO_LOWER) { + painAnim += "back"; } else { - painAnim = "unarmed_"; + switch (pain_location) { + case HITLOC_HEAD: + case HITLOC_HELMET: + case HITLOC_NECK: + painAnim += "head"; + break; + case HITLOC_TORSO_UPPER: + case HITLOC_TORSO_MID: + painAnim += "uppertorso"; + break; + case HITLOC_TORSO_LOWER: + case HITLOC_PELVIS: + painAnim += "lowertorso"; + break; + case HITLOC_R_ARM_UPPER: + case HITLOC_R_ARM_LOWER: + case HITLOC_R_HAND: + painAnim += "rarm"; + break; + case HITLOC_L_ARM_UPPER: + case HITLOC_L_ARM_LOWER: + case HITLOC_L_HAND: + painAnim += "larm"; + break; + case HITLOC_R_LEG_UPPER: + case HITLOC_L_LEG_UPPER: + case HITLOC_R_LEG_LOWER: + case HITLOC_L_LEG_LOWER: + case HITLOC_R_FOOT: + case HITLOC_L_FOOT: + painAnim += "leg"; + break; + default: + painAnim += "uppertorso"; + break; + } } - // use the animation based on the movement - if (m_iMovePosFlags & MPF_POSITION_CROUCHING) { - painAnim += "crouch_"; + animnum = gi.Anim_NumForName(edict->tiki, painAnim.c_str()); + if (animnum == -1) { + gi.DPrintf("WARNING: Could not find player pain animation '%s'\n", painAnim.c_str()); } else { - painAnim += "stand_"; + NewAnim(animnum, EV_Player_AnimLoop_Pain, ANIMSLOT_PAIN); + RestartAnimSlot(ANIMSLOT_PAIN); + m_sPainAnim = painAnim; + m_fPainBlend = 1.f; + animdone_Pain = false; } } - painAnim += "hit_"; - - if (pain_dir == PAIN_REAR || pain_location == HITLOC_TORSO_MID || HITLOC_TORSO_LOWER) { - painAnim += "back"; - } else { - switch (pain_location) { - case HITLOC_HEAD: - case HITLOC_HELMET: - case HITLOC_NECK: - painAnim += "head"; - break; - case HITLOC_TORSO_UPPER: - case HITLOC_TORSO_MID: - painAnim += "uppertorso"; - break; - case HITLOC_TORSO_LOWER: - case HITLOC_PELVIS: - painAnim += "lowertorso"; - break; - case HITLOC_R_ARM_UPPER: - case HITLOC_R_ARM_LOWER: - case HITLOC_R_HAND: - painAnim += "rarm"; - break; - case HITLOC_L_ARM_UPPER: - case HITLOC_L_ARM_LOWER: - case HITLOC_L_HAND: - painAnim += "larm"; - break; - case HITLOC_R_LEG_UPPER: - case HITLOC_L_LEG_UPPER: - case HITLOC_R_LEG_LOWER: - case HITLOC_L_LEG_LOWER: - case HITLOC_R_FOOT: - case HITLOC_L_FOOT: - painAnim += "leg"; - break; - default: - painAnim += "uppertorso"; - break; - } - } - - animnum = gi.Anim_NumForName(edict->tiki, painAnim.c_str()); - if (animnum == -1) { - gi.DPrintf("WARNING: Could not find player pain animation '%s'\n", painAnim.c_str()); - } else { - NewAnim(animnum, EV_Player_AnimLoop_Pain, ANIMSLOT_PAIN); - RestartAnimSlot(ANIMSLOT_PAIN); - m_sPainAnim = painAnim; - m_fPainBlend = 1.f; - animdone_Pain = false; - } - // // clear totals // From 937f3993ec066a72360ed4f4027ac883a7f88f1e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:10:49 +0100 Subject: [PATCH 0092/2040] Removed unusable FX in 1.11 and below --- code/cgame/cg_specialfx.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/code/cgame/cg_specialfx.cpp b/code/cgame/cg_specialfx.cpp index 8f5abb61..d1b1c970 100644 --- a/code/cgame/cg_specialfx.cpp +++ b/code/cgame/cg_specialfx.cpp @@ -234,9 +234,15 @@ void ClientSpecialEffectsManager::LoadEffects() szEffectModel = "models/fx/bazookaexp_base.tik"; break; case SFX_EXP_HEAVYSHELL_BASE: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/heavyshellexp_base.tik"; break; case SFX_EXP_TANK_BASE: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/tankexp_base.tik"; break; case SFX_EXP_GREN_PAPER: @@ -285,30 +291,57 @@ void ClientSpecialEffectsManager::LoadEffects() szEffectModel = "models/fx/grenexp_carpet.tik"; break; case SFX_EXP_HEAVYSHELL_DIRT: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/heavyshellexp_dirt.tik"; break; case SFX_EXP_HEAVYSHELL_STONE: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/heavyshellexp_stone.tik"; break; case SFX_EXP_HEAVYSHELL_SNOW: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/heavyshellexp_snow.tik"; break; case SFX_EXP_TANK_DIRT: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/tankexp_dirt.tik"; break; case SFX_EXP_TANK_STONE: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/tankexp_stone.tik"; break; case SFX_EXP_TANK_SNOW: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/tankexp_snow.tik"; break; case SFX_EXP_BAZOOKA_DIRT: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/bazookaexp_dirt.tik"; break; case SFX_EXP_BAZOOKA_STONE: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/bazookaexp_stone.tik"; break; case SFX_EXP_BAZOOKA_SNOW: + if (cg_protocol < protocol_e::PROTOCOL_MOHTA_MIN) { + continue; + } szEffectModel = "models/fx/bazookaexp_snow.tik"; break; case SFX_WATER_RIPPLE_STILL: From 0290fa3351cd763f07b8806e0aafdfe97d60398f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:29:38 +0100 Subject: [PATCH 0093/2040] Set default animation on the attached model if the tag was not found --- code/fgame/entity.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index fe8f1d47..7cfe575b 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -4385,6 +4385,7 @@ void Entity::AttachModelEvent(Event *ev) } } else { warning("AttachModelEvent", "Tag %s not found", bone.c_str()); + obj->NewAnim("idle"); } } From 8cf3be3526da236f7f2abd0f03cb23b2a5a5ec91 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:30:22 +0100 Subject: [PATCH 0094/2040] If in thinks, don't delete the object immediately --- code/fgame/entity.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 7cfe575b..6f62e540 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -4380,7 +4380,12 @@ void Entity::AttachModelEvent(Event *ev) if (obj->attach(this->entnum, tagnum, true, offset)) { obj->NewAnim("idle"); } else { - delete obj; + warning("AttachModelEvent", "Could not attach model %s to tag \"%s\" on entnum #%d (targetname = %s)", modelname.c_str(), bone.c_str(), entnum, targetname.c_str()); + if (g_iInThinks) { + PostEvent(EV_Remove, 0); + } else { + delete obj; + } return; } } else { From d5908bd75ccdc663af3d44554a9110d8dbdabd27 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:30:31 +0100 Subject: [PATCH 0095/2040] Fixed frag grenade spelling in SP --- code/fgame/weapon.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index a4336227..935e303d 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -2954,6 +2954,7 @@ void Weapon::PickupWeapon(Event *ev) sen->GiveAmmo(sAmmoType, iGiveAmmo); + /* if (!g_gametype->integer && other->IsSubclassOfPlayer()) { if (!sAmmoType.icmp("agrenade")) { if (iGiveAmmo == 1) { @@ -2963,8 +2964,9 @@ void Weapon::PickupWeapon(Event *ev) } } } + */ - if (!sAmmoType.icmp("grenade")) { + if (!sAmmoType.icmp("grenade") || !sAmmoType.icmp("agrenade")) { if (iGiveAmmo == 1) { sMessage = gi.LV_ConvertString("Got 1 Grenade"); } else { @@ -2986,6 +2988,7 @@ void Weapon::PickupWeapon(Event *ev) sen->GiveAmmo(sAmmoType, iGiveAmmo); + /* if (!g_gametype->integer && other->IsSubclassOfPlayer()) { if (!sAmmoType.icmp("agrenade")) { if (iGiveAmmo == 1) { @@ -2995,8 +2998,9 @@ void Weapon::PickupWeapon(Event *ev) } } } + */ - if (!sAmmoType.icmp("grenade")) { + if (!sAmmoType.icmp("grenade") || !sAmmoType.icmp("agrenade")) { if (iGiveAmmo == 1) { sMessage = gi.LV_ConvertString("Got 1 Grenade"); } else { From ac40373c09c16f9c8c9d485a9519598370304ad3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:08:37 +0100 Subject: [PATCH 0096/2040] Use RemoveVehicleSoundEntities() to remove sound entities --- code/fgame/vehicle.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 3ceb667d..21f38dee 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -1194,11 +1194,7 @@ Vehicle::~Vehicle */ Vehicle::~Vehicle() { - for (int i = 0; i < MAX_CORNERS; i++) { - if (m_pVehicleSoundEntities[i]) { - m_pVehicleSoundEntities[i]->PostEvent(EV_Remove, EV_LINKDOORS); - } - } + RemoveVehicleSoundEntities(); if (m_pCollisionEntity) { m_pCollisionEntity->ProcessEvent(EV_Remove); From 2174f2ff85328337c46f6e434f2fab7420d70c7e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:09:08 +0100 Subject: [PATCH 0097/2040] For "delete" and "remove", use Listener::ScriptRemove --- code/fgame/entity.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 6f62e540..904cd28a 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -1645,8 +1645,8 @@ CLASS_DECLARATION(SimpleEntity, Entity, NULL) { {&EV_ConnectPaths, &Entity::EventConnectPaths }, {&EV_DisconnectPaths, &Entity::EventDisconnectPaths }, {&EV_Remove, &Entity::Remove }, - {&EV_Delete, &Entity::Remove }, - {&EV_ScriptRemove, &Entity::Remove }, + {&EV_Delete, &Listener::ScriptRemove }, + {&EV_ScriptRemove, &Listener::ScriptRemove }, {&EV_VolumeDamage, &Entity::EventVolumeDamage }, {&EV_GetNormalHealth, &Entity::EventGetNormalHealth }, {&EV_NormalDamage, &Entity::EventNormalDamage }, From 0fabdc8c4439495661f391163a8077b2c93d7fd0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:25:03 +0100 Subject: [PATCH 0098/2040] Added current objective index --- code/cgame/cg_local.h | 1 + code/cgame/cg_main.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 314bf2b9..caf1997e 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -340,6 +340,7 @@ extern "C" { float ObjectivesBaseAlpha; float ObjectivesDesiredAlpha; float ObjectivesCurrentAlpha; + int ObjectivesCurrentIndex; // misc crain_t rain; diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 70f4346b..0b342c61 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -351,6 +351,9 @@ void CG_ProcessConfigString(int num, qboolean modelOnly) } } return; + case CS_CURRENT_OBJECTIVE: + cg.ObjectivesCurrentIndex = atoi(str); + break; } if (num >= CS_OBJECTIVES && num < CS_OBJECTIVES + MAX_OBJECTIVES) { From fce0f7b357a9766c6557617a8b4a63b8bf9e6bee Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:36:34 +0100 Subject: [PATCH 0099/2040] Better rain handlijng --- code/cgame/cg_local.h | 1 + code/cgame/cg_main.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index caf1997e..500e259c 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -187,6 +187,7 @@ extern "C" { float min_dist; float width; char shader[MAX_RAIN_SHADERS][MAX_STRING_CHARS]; + char currentShader[MAX_STRING_CHARS]; int numshaders; } crain_t; diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 0b342c61..5c74c473 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -335,25 +335,25 @@ void CG_ProcessConfigString(int num, qboolean modelOnly) cg.rain.width = atof(str); return; case CS_RAIN_SHADER: - if (cg.rain.numshaders) { - for (i = 0; i < cg.rain.numshaders; i++) { - sprintf(cg.rain.shader[i], "%s%i", str, i); - } - } else { - strcpy(cg.rain.shader[0], str); + Q_strncpyz(cg.rain.currentShader, str, sizeof(cg.rain.currentShader)); + for (i = 0; i < cg.rain.numshaders; ++i) { + Com_sprintf(cg.rain.shader[i], sizeof(cg.rain.shader[i]), "%s%i", cg.rain.currentShader, i); + } + if (!cg.rain.numshaders) { + Q_strncpyz(cg.rain.shader[0], cg.rain.currentShader, sizeof(cg.rain.shader[0])); } return; case CS_RAIN_NUMSHADERS: cg.rain.numshaders = atoi(str); if (cg.rain.numshaders) { for (i = 0; i < cg.rain.numshaders; i++) { - sprintf(cg.rain.shader[i], "%s%i", str, i); + Com_sprintf(cg.rain.shader[i], sizeof(cg.rain.shader[i]), "%s%i", cg.rain.currentShader, i); } } return; case CS_CURRENT_OBJECTIVE: cg.ObjectivesCurrentIndex = atoi(str); - break; + return; } if (num >= CS_OBJECTIVES && num < CS_OBJECTIVES + MAX_OBJECTIVES) { From 13ec3435b43e675728760a26159a599cbc999491 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:36:56 +0100 Subject: [PATCH 0100/2040] Fixed rain num shaders --- code/fgame/level.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/level.cpp b/code/fgame/level.cpp index c98d4fa4..f2bff60c 100644 --- a/code/fgame/level.cpp +++ b/code/fgame/level.cpp @@ -695,8 +695,8 @@ CLASS_DECLARATION(Listener, Level, NULL) { {&EV_Level_Rain_Width_Get, &Level::EventRainWidthGet }, {&EV_Level_Rain_Shader_Set, &Level::EventRainShaderSet }, {&EV_Level_Rain_Shader_Get, &Level::EventRainShaderGet }, - {&EV_Level_Rain_NumShaders_Set, &Level::EventRainShaderSet }, - {&EV_Level_Rain_NumShaders_Get, &Level::EventRainShaderGet }, + {&EV_Level_Rain_NumShaders_Set, &Level::EventRainNumShadersSet }, + {&EV_Level_Rain_NumShaders_Get, &Level::EventRainNumShadersGet }, {&EV_Level_AddBadPlace, &Level::EventAddBadPlace }, {&EV_Level_RemoveBadPlace, &Level::EventRemoveBadPlace }, {&EV_Level_IgnoreClock, &Level::EventIgnoreClock }, From cf1dbf07c75095fc3675344967af0cd55b9efc95 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:46:05 +0100 Subject: [PATCH 0101/2040] Corrected MASK_CLICK tracemask (especially for patches surface) --- code/fgame/bg_public.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 079c74b7..890fa1d2 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -651,8 +651,7 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_FENCE | CONTENTS_VEHICLECLIP \ | CONTENTS_BODY | CONTENTS_TRIGGER) #define MASK_VEHICLE_TIRES (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_FENCE | CONTENTS_VEHICLECLIP | CONTENTS_TRIGGER) -#define MASK_CLICK \ - (CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_UNKNOWN3 | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX) +#define MASK_CLICK (CONTENTS_VEHICLECLIP | CONTENTS_WEAPONCLIP | CONTENTS_MONSTERCLIP | CONTENTS_PLAYERCLIP | CONTENTS_SOLID) #define MASK_CANSEE \ (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY) #define MASK_CANSEE_NOENTS (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) From 500c70016f944f76c342a7f4da396e9a0b593b5d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Feb 2024 20:13:23 +0100 Subject: [PATCH 0102/2040] Don't crossblend with new weapons --- code/cgame/cg_viewmodelanim.c | 65 ++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/code/cgame/cg_viewmodelanim.c b/code/cgame/cg_viewmodelanim.c index 06fe1d94..794fccd1 100644 --- a/code/cgame/cg_viewmodelanim.c +++ b/code/cgame/cg_viewmodelanim.c @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static const char *AnimPrefixList[] = { "", + "unarmed", "papers", "colt45", "p38", @@ -45,7 +46,6 @@ static const char *AnimPrefixList[] = { "bazooka", "panzerschreck", "shotgun", - "unarmed", // // Team Assault and Team Tactics weapons "mg42portable", @@ -82,6 +82,7 @@ static const char *AnimPrefixList[] = { enum animPrefix_e { WPREFIX_NONE, + WPREFIX_UNARMED, WPREFIX_PAPERS, WPREFIX_COLT45, WPREFIX_P38, @@ -99,7 +100,6 @@ enum animPrefix_e { WPREFIX_BAZOOKA, WPREFIX_PANZERSCHRECK, WPREFIX_SHOTGUN, - WPREFIX_UNARMED, // // Team Assault and Team Tactics weapons WPREFIX_MG42_PORTABLE, @@ -338,9 +338,11 @@ void CG_ViewModelAnimation(refEntity_t *pModel) char szAnimName[MAX_QPATH]; dtiki_t *pTiki; qboolean bAnimChanged; + qboolean bWeaponChanged; fCrossblendFrac = 0.0; - bAnimChanged = 0; + bAnimChanged = qfalse; + bWeaponChanged = qfalse; // Added in OPM pTiki = pModel->tiki; if (cgi.anim->g_iLastEquippedWeaponStat == cg.snap->ps.stats[STAT_EQUIPPED_WEAPON] @@ -351,7 +353,9 @@ void CG_ViewModelAnimation(refEntity_t *pModel) cgi.anim->g_iLastEquippedWeaponStat = cg.snap->ps.stats[STAT_EQUIPPED_WEAPON]; strcpy(cgi.anim->g_szLastActiveItem, CG_ConfigString(CS_WEAPONS + cg.snap->ps.activeItems[1])); cgi.anim->g_iLastAnimPrefixIndex = iAnimPrefixIndex; - bAnimChanged = qtrue; + + bAnimChanged = qtrue; + bWeaponChanged = qtrue; } if (cgi.anim->g_iLastVMAnim == -1) { @@ -425,20 +429,27 @@ void CG_ViewModelAnimation(refEntity_t *pModel) } sprintf(szAnimName, "%s_%s", AnimPrefixList[iAnimPrefixIndex], pszAnimSuffix); - fCrossblendTime = cgi.Anim_CrossblendTime(pTiki, cgi.anim->g_VMFrameInfo[cgi.anim->g_iCurrentVMAnimSlot].index); - fCrossblendAmount = cgi.anim->g_iCurrentVMDuration / 1000.0; + if (!bWeaponChanged) { + fCrossblendTime = + cgi.Anim_CrossblendTime(pTiki, cgi.anim->g_VMFrameInfo[cgi.anim->g_iCurrentVMAnimSlot].index); + fCrossblendAmount = cgi.anim->g_iCurrentVMDuration / 1000.0; - if (fCrossblendAmount < fCrossblendTime && fCrossblendAmount > 0.0) { - fCrossblendFrac = fCrossblendAmount / fCrossblendTime; - for (i = 0; i < MAX_FRAMEINFOS; ++i) { - if (cgi.anim->g_VMFrameInfo[i].weight) { - if (i == cgi.anim->g_iCurrentVMAnimSlot) { - cgi.anim->g_VMFrameInfo[i].weight = fCrossblendFrac; - } else { - cgi.anim->g_VMFrameInfo[i].weight *= (1.0 - fCrossblendFrac); + if (fCrossblendAmount < fCrossblendTime && fCrossblendAmount > 0.0) { + fCrossblendFrac = fCrossblendAmount / fCrossblendTime; + for (i = 0; i < MAX_FRAMEINFOS; ++i) { + if (cgi.anim->g_VMFrameInfo[i].weight) { + if (i == cgi.anim->g_iCurrentVMAnimSlot) { + cgi.anim->g_VMFrameInfo[i].weight = fCrossblendFrac; + } else { + cgi.anim->g_VMFrameInfo[i].weight *= (1.0 - fCrossblendFrac); + } } } } + } else { + fCrossblendTime = 0; + fCrossblendAmount = 0; + fCrossblendFrac = 0; } cgi.anim->g_iCurrentVMAnimSlot = (cgi.anim->g_iCurrentVMAnimSlot + 1) % MAX_FRAMEINFOS; @@ -453,17 +464,31 @@ void CG_ViewModelAnimation(refEntity_t *pModel) cgi.anim->g_VMFrameInfo[cgi.anim->g_iCurrentVMAnimSlot].weight = 1.0; cgi.anim->g_iCurrentVMDuration = 0; - fCrossblendTime = cgi.Anim_CrossblendTime(pTiki, cgi.anim->g_VMFrameInfo[cgi.anim->g_iCurrentVMAnimSlot].index); - if (!fCrossblendTime) { + if (!bWeaponChanged) { + fCrossblendTime = + cgi.Anim_CrossblendTime(pTiki, cgi.anim->g_VMFrameInfo[cgi.anim->g_iCurrentVMAnimSlot].index); + if (!fCrossblendTime) { + for (i = 0; i < MAX_FRAMEINFOS; ++i) { + if (i != cgi.anim->g_iCurrentVMAnimSlot) { + cgi.anim->g_VMFrameInfo[i].weight = 0.0; + } + } + + cgi.anim->g_bCrossblending = qfalse; + } else { + cgi.anim->g_bCrossblending = qtrue; + } + } else { + // Added in OPM + // If there is a new weapon, don't do any crossblend + cgi.anim->g_bCrossblending = qfalse; + + // clear crossblend values for (i = 0; i < MAX_FRAMEINFOS; ++i) { if (i != cgi.anim->g_iCurrentVMAnimSlot) { cgi.anim->g_VMFrameInfo[i].weight = 0.0; } } - - cgi.anim->g_bCrossblending = qfalse; - } else { - cgi.anim->g_bCrossblending = qtrue; } } From c9aedf242d4925397b4321f82a7bfff0a4b5317d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Feb 2024 21:03:10 +0100 Subject: [PATCH 0103/2040] Fixed scoreboard sending incorrect data for spectators --- code/fgame/dm_manager.cpp | 52 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/code/fgame/dm_manager.cpp b/code/fgame/dm_manager.cpp index 65b50e78..6125e0c1 100644 --- a/code/fgame/dm_manager.cpp +++ b/code/fgame/dm_manager.cpp @@ -271,7 +271,8 @@ void DM_Team::AddKills(Player *player, int numKills) if (m_teamnumber > TEAM_FREEFORALL) { m_iKills += numKills; - if ((g_gametype->integer >= GT_TEAM_ROUNDS && g_gametype->integer <= GT_TOW) || g_gametype->integer == GT_LIBERATION) { + if ((g_gametype->integer >= GT_TEAM_ROUNDS && g_gametype->integer <= GT_TOW) + || g_gametype->integer == GT_LIBERATION) { player->AddDeaths(numKills); } else { m_teamwins += numKills; @@ -285,7 +286,8 @@ void DM_Team::AddDeaths(Player *player, int numDeaths) return; } - if ((g_gametype->integer >= GT_TEAM_ROUNDS && g_gametype->integer <= GT_TOW) || g_gametype->integer == GT_LIBERATION) { + if ((g_gametype->integer >= GT_TEAM_ROUNDS && g_gametype->integer <= GT_TOW) + || g_gametype->integer == GT_LIBERATION) { return; } @@ -626,7 +628,11 @@ Event EV_DM_Manager_DoRoundTransition ); Event EV_DM_Manager_FinishRoundTransition ( - "finishroundtransition", EV_DEFAULT, NULL, NULL, "delayed function call to do the actual restart for the next round" + "finishroundtransition", + EV_DEFAULT, + NULL, + NULL, + "delayed function call to do the actual restart for the next round" ); CLASS_DECLARATION(Listener, DM_Manager, NULL) { @@ -667,7 +673,7 @@ DM_Manager::DM_Manager() m_csTeamBombPlantSide = STRING_DRAW; m_iNumTargetsToDestroy = 1; m_iNumTargetsDestroyed = 0; - m_iNumBombsPlanted = 0; + m_iNumBombsPlanted = 0; m_bAllowAxisRespawn = true; m_bAllowAlliedRespawn = true; m_bRoundActive = false; @@ -1048,11 +1054,11 @@ void DM_Manager::InitGame(void) } for (i = 1; i <= level.m_SimpleArchivedEntities.NumObjects(); i++) { - SimpleArchivedEntity* const ent = level.m_SimpleArchivedEntities.ObjectAt(i); - const char* const classname = ent->getClassID(); + SimpleArchivedEntity *const ent = level.m_SimpleArchivedEntities.ObjectAt(i); + const char *const classname = ent->getClassID(); if (!Q_stricmp(classname, "info_player_deathmatch")) { - PlayerStart* const spawnpoint = static_cast(ent); + PlayerStart *const spawnpoint = static_cast(ent); m_team_spectator.m_spawnpoints.AddObject(spawnpoint); m_team_freeforall.m_spawnpoints.AddObject(spawnpoint); @@ -1062,16 +1068,16 @@ void DM_Manager::InitGame(void) } } else if (!Q_stricmp(classname, "info_player_allied")) { if (g_gametype->integer >= GT_TEAM) { - PlayerStart* const spawnpoint = static_cast(ent); + PlayerStart *const spawnpoint = static_cast(ent); m_team_allies.m_spawnpoints.AddObject(spawnpoint); } } else if (!Q_stricmp(classname, "info_player_axis")) { if (g_gametype->integer >= GT_TEAM) { - PlayerStart* const spawnpoint = static_cast(ent); + PlayerStart *const spawnpoint = static_cast(ent); m_team_axis.m_spawnpoints.AddObject(spawnpoint); } } else if (!Q_stricmp(classname, "info_player_intermission")) { - PlayerStart* const spawnpoint = static_cast(ent); + PlayerStart *const spawnpoint = static_cast(ent); m_team_freeforall.m_spawnpoints.AddObject(spawnpoint); } } @@ -1100,10 +1106,10 @@ void DM_Manager::InitGame(void) m_bRoundBasedGame = false; } else { if (g_gametype->integer == GT_TOW || g_gametype->integer == GT_LIBERATION) { - m_bAllowRespawns = true; + m_bAllowRespawns = true; m_bRoundBasedGame = true; } else { - m_bAllowRespawns = false; + m_bAllowRespawns = false; m_bRoundBasedGame = true; } @@ -1534,7 +1540,7 @@ void DM_Manager::StartRound(void) } m_fRoundEndTime = 0.0f; - m_bRoundActive = true; + m_bRoundActive = true; // respawn all players for (i = 0, ent = g_entities; i < game.maxclients; i++, ent++) { @@ -1620,7 +1626,8 @@ float DM_Manager::GetMatchStartTime(void) return m_fRoundTime; } - if (g_gametype->integer == GT_TEAM_ROUNDS || g_gametype->integer == GT_OBJECTIVE || g_gametype->integer == GT_LIBERATION) { + if (g_gametype->integer == GT_TEAM_ROUNDS || g_gametype->integer == GT_OBJECTIVE + || g_gametype->integer == GT_LIBERATION) { if (m_fRoundTime > 0 && (m_team_allies.IsEmpty() || m_team_allies.IsEmpty())) { m_fRoundTime = 0; return -1; @@ -1796,15 +1803,15 @@ void DM_Manager::InsertEntry(const char *entry) } } -void DM_Manager::InsertEntryNoCount(const char* entry) +void DM_Manager::InsertEntryNoCount(const char *entry) { - size_t len = strlen(entry); + size_t len = strlen(entry); - if (scoreLength + len < MAX_STRING_CHARS) { - strcpy(scoreString + scoreLength, entry); + if (scoreLength + len < MAX_STRING_CHARS) { + strcpy(scoreString + scoreLength, entry); - scoreLength += len; - } + scoreLength += len; + } } void DM_Manager::InsertEmpty(void) @@ -1916,7 +1923,7 @@ void DM_Manager::BuildTeamInfo_ver15(DM_Team *dmTeam) iPing ); } else { - Com_sprintf(entry, sizeof(entry), "%i %i \"\" \"\" \"\" \"\" \"\" ", -1, dmTeam->m_teamnumber); + Com_sprintf(entry, sizeof(entry), "%i %i \"\" \"\" \"\" \"\" ", -1, dmTeam->m_teamnumber); } } else { Com_sprintf(entry, sizeof(entry), "%i \"\" \"\" \"\" \"\" ", -1 - dmTeam->m_teamnumber); @@ -1977,7 +1984,8 @@ void DM_Manager::BuildPlayerTeamInfo(DM_Team *dmTeam, int *iPlayerList, DM_Team bool DM_Manager::IsAlivePlayer(Player *player) const { - return !player->IsDead() && !player->IsSpectator() && !player->IsInJail() || player->GetDM_Team() == &m_team_spectator; + return !player->IsDead() && !player->IsSpectator() && !player->IsInJail() + || player->GetDM_Team() == &m_team_spectator; } CTeamSpawnClock::CTeamSpawnClock() From 336ba6181e7750f62afbd7c2cc2da7ec33305643 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Feb 2024 23:25:41 +0100 Subject: [PATCH 0104/2040] Don't allocate planes / facets if there are none --- code/qcommon/cm_patch.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/code/qcommon/cm_patch.c b/code/qcommon/cm_patch.c index ef4e31e6..34f367e9 100644 --- a/code/qcommon/cm_patch.c +++ b/code/qcommon/cm_patch.c @@ -1131,10 +1131,37 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { // copy the results out pf->numPlanes = numPlanes; pf->numFacets = numFacets; - pf->facets = Hunk_Alloc(numFacets * sizeof(*pf->facets), h_dontcare); - Com_Memcpy(pf->facets, facets, numFacets * sizeof(*pf->facets)); - pf->planes = Hunk_Alloc(numPlanes * sizeof(*pf->planes), h_dontcare); - Com_Memcpy(pf->planes, planes, numPlanes * sizeof(*pf->planes)); + if (numPlanes >= 1) { + pf->facets = Hunk_Alloc(numFacets * sizeof(*pf->facets), h_dontcare); + Com_Memcpy(pf->facets, facets, numFacets * sizeof(*pf->facets)); + } else { + pf->numPlanes = 0; + pf->planes = NULL; + Com_DPrintf( + "WARNING: CM_PatchCollideFromGrid: Degenerate patch - no planes (%i %i %i)-(%i %i %i)\n", + pf->bounds[0][0], + pf->bounds[0][1], + pf->bounds[0][2], + pf->bounds[1][0], + pf->bounds[1][1], + pf->bounds[1][2]); + } + + if (numFacets >= 1) { + pf->planes = Hunk_Alloc(numPlanes * sizeof(*pf->planes), h_dontcare); + Com_Memcpy(pf->planes, planes, numPlanes * sizeof(*pf->planes)); + } else { + pf->numFacets = 0; + pf->facets = NULL; + Com_DPrintf( + "WARNING: CM_PatchCollideFromGrid: Degenerate patch - no facets (%i %i %i)-(%i %i %i)\n", + pf->bounds[0][0], + pf->bounds[0][1], + pf->bounds[0][2], + pf->bounds[1][0], + pf->bounds[1][1], + pf->bounds[1][2]); + } } @@ -1436,11 +1463,8 @@ void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s * //never clip against the back side if (hitnum == facet->numBorders - 1) continue; - if (enterFrac < leaveFrac && enterFrac >= 0) { + if (enterFrac <= leaveFrac && enterFrac >= 0) { if (enterFrac < tw->trace.fraction) { - if (enterFrac < 0) { - enterFrac = 0; - } #ifndef BSPC if (!cv) { cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 ); From 4a39e5411f8c7aeaf8ceec04ccee30f445c902a9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Feb 2024 23:46:43 +0100 Subject: [PATCH 0105/2040] Fixed patch collision in position test --- code/qcommon/cm_patch.c | 106 ++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 69 deletions(-) diff --git a/code/qcommon/cm_patch.c b/code/qcommon/cm_patch.c index 34f367e9..89a0c0ad 100644 --- a/code/qcommon/cm_patch.c +++ b/code/qcommon/cm_patch.c @@ -1498,84 +1498,52 @@ CM_PositionTestInPatchCollide ==================== */ qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) { + byte cross[4096]; + patchPlane_t* planes; + facet_t* facet; int i, j; - float offset, t; - patchPlane_t *planes; - facet_t *facet; - float plane[4]; - vec3_t startp; + float offset, d; - if (tw->isPoint) { - return qfalse; + // Check if it's within the patch bounds + for (i = 0; i < 3; i++) { + if (tw->bounds[0][i] > pc->bounds[1][i] || tw->bounds[1][i] < pc->bounds[0][i]) { + return qfalse; + } } - // + + // Check for planes that are crossing + for (i = 0; i < pc->numPlanes; i++) { + planes = &pc->planes[i]; + + offset = fabs(DotProduct(tw->offsets[planes->signbits], planes->plane)); + d = DotProduct(tw->start, planes->plane) - planes->plane[3]; + + if (-offset > d) { + cross[i] = 0; + } else if (offset < d) { + cross[i] = 1; + } else { + cross[i] = 2; + } + } + + j = 0; facet = pc->facets; - for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) { - planes = &pc->planes[ facet->surfacePlane ]; - VectorCopy(planes->plane, plane); - plane[3] = planes->plane[3]; - if ( sphere.use ) { - // adjust the plane distance apropriately for radius - plane[3] += sphere.radius; - - // find the closest point on the capsule to the plane - t = DotProduct( plane, sphere.offset ); - if ( t > 0 ) { - VectorSubtract( tw->start, sphere.offset, startp ); - } - else { - VectorAdd( tw->start, sphere.offset, startp ); - } - } - else { - offset = DotProduct( tw->offsets[ planes->signbits ], plane); - plane[3] -= offset; - VectorCopy( tw->start, startp ); - } - - if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) { - continue; - } - - for ( j = 0; j < facet->numBorders; j++ ) { - planes = &pc->planes[ facet->borderPlanes[j] ]; - if (facet->borderInward[j]) { - VectorNegate(planes->plane, plane); - plane[3] = -planes->plane[3]; - } - else { - VectorCopy(planes->plane, plane); - plane[3] = planes->plane[3]; - } - if ( sphere.use ) { - // adjust the plane distance apropriately for radius - plane[3] += sphere.radius; - - // find the closest point on the capsule to the plane - t = DotProduct( plane, sphere.offset ); - if ( t > 0.0f ) { - VectorSubtract( tw->start, sphere.offset, startp ); - } - else { - VectorAdd( tw->start, sphere.offset, startp ); + for (i = 0; i < pc->numFacets; i++, facet++) { + if (cross[facet->surfacePlane] == 2) { + for (j = 0; j < facet->numBorders; j++) { + if (cross[facet->borderPlanes[j]] != 2 && cross[facet->borderPlanes[j]] != (uint8_t)facet->borderInward[j]) { + break; } } - else { - // NOTE: this works even though the plane might be flipped because the bbox is centered - offset = DotProduct( tw->offsets[ planes->signbits ], plane); - plane[3] += fabs(offset); - VectorCopy( tw->start, startp ); + + if (j < facet->numBorders) { + continue; } - if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) { - break; - } + // inside this patch facet + return qtrue; } - if (j < facet->numBorders) { - continue; - } - // inside this patch facet - return qtrue; } return qfalse; } From b848ee0fac8987bfe029319a589bbf559e049ee2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:48:55 +0100 Subject: [PATCH 0106/2040] Added rotateStart and rotateCoef for rotate tcMod --- code/renderer/tr_local.h | 4 +++- code/renderer/tr_shade.c | 4 +++- code/renderer/tr_shade_calc.c | 13 +++++++++++-- code/renderer/tr_shader.c | 26 +++++++++++++++++++++++++- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 2e554c5f..157261d8 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -428,6 +428,8 @@ typedef struct { // + = clockwise // - = counterclockwise float rotateSpeed; + float rotateStart; + float rotateCoef; } texModInfo_t; @@ -2216,7 +2218,7 @@ void RB_DeformTessGeometry( void ); void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); void RB_CalcEnvironmentTexCoords2( float *dstTexCoords ); void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords ); -void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords ); +void RB_CalcRotateTexCoords( float degsPerSecond, float degsPerSecondCoef, float* st, float start ); void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords ); void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords ); void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords ); diff --git a/code/renderer/tr_shade.c b/code/renderer/tr_shade.c index 24ca74b3..fbd47618 100644 --- a/code/renderer/tr_shade.c +++ b/code/renderer/tr_shade.c @@ -1381,7 +1381,9 @@ static void ComputeTexCoords( shaderStage_t *pStage ) { case TMOD_ROTATE: RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed, - ( float * ) tess.svars.texcoords[b] ); + pStage->bundle[b].texMods[tm].rotateCoef, + ( float * ) tess.svars.texcoords[b], + pStage->bundle[b].texMods[tm].rotateStart ); break; default: diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index 0f02b6d6..8297eaa6 100644 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -1188,7 +1188,7 @@ void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st ) /* ** RB_CalcRotateTexCoords */ -void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) +void RB_CalcRotateTexCoords(float degsPerSecond, float degsPerSecondCoef, float* st, float start) { float timeScale = tess.shaderTime; float degs; @@ -1196,7 +1196,16 @@ void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) float sinValue, cosValue; texModInfo_t tmi; - degs = -degsPerSecond * timeScale; + if (degsPerSecond != 1234567) { + degs = -degsPerSecond * degsPerSecondCoef * tess.shaderTime - start; + } else if (backEnd.currentEntity) { + degs = -backEnd.currentEntity->e.shader_data[0] * degsPerSecondCoef * tess.shaderTime - start; + } else { + degs = r_static_shaderdata0->value; + } + if (!backEnd.currentEntity) { + degs *= r_static_shadermultiplier0->value; + } index = degs * ( FUNCTABLE_SIZE / 360.0f ); sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index 25fa315c..ab0b2e1f 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -616,7 +616,31 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name ); return; } - tmi->rotateSpeed = atof( token ); + + if (!Q_stricmp(token, "fromEntity")) { + tmi->rotateSpeed = 1234567; + } else { + tmi->rotateSpeed = atof(token); + } + + token = COM_ParseExt(text, qfalse); + if (token[0]) { + if (!Q_stricmp(token, "fromEntity")) { + tmi->rotateStart = 1234567; + } else { + tmi->rotateStart = atof(token); + } + } else { + tmi->rotateStart = 0; + } + + token = COM_ParseExt(text, qfalse); + if (token[0]) { + tmi->rotateCoef = atof(token); + } else { + tmi->rotateCoef = 1; + } + tmi->type = TMOD_ROTATE; } // From fbf67fccc3c40b0fcbed78f05d81461046e55163 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:55:21 +0100 Subject: [PATCH 0107/2040] Added TMOD enum values from AA 1.11 --- code/renderer/tr_local.h | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 157261d8..6c407af8 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -383,14 +383,21 @@ typedef struct { #define TR_MAX_TEXMODS 4 typedef enum { - TMOD_NONE, - TMOD_TRANSFORM, - TMOD_TURBULENT, - TMOD_SCROLL, - TMOD_SCALE, - TMOD_STRETCH, - TMOD_ROTATE, - TMOD_ENTITY_TRANSLATE + TMOD_NONE, + TMOD_TRANSFORM, + TMOD_TURBULENT, + TMOD_SCROLL, + TMOD_SCALE, + TMOD_STRETCH, + TMOD_ROTATE, + TMOD_ENTITY_TRANSLATE, + TMOD_NOISE, + TMOD_OFFSET, + TMOD_PARALLAX, + TMOD_MACRO, + TMOD_WAVETRANS, + TMOD_WAVETRANT, + TMOD_BULGETRANS } texMod_t; #define MAX_SHADER_DEFORMS 3 From 8bd30ffb2212214e85ed6755f0277f70b2a36e01 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:59:14 +0100 Subject: [PATCH 0108/2040] Added rate tmod variable --- code/renderer/tr_local.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 6c407af8..34a6b550 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -428,6 +428,9 @@ typedef struct { float scale[2]; // s *= scale[0] // t *= scale[1] + // used for TMOD_PARALLAX + float rate[2]; + // used for TMOD_SCROLL float scroll[2]; // s' = s + scroll[0] * time // t' = t + scroll[1] * time From 1f2b5dcc863534622741107c03450116dd108daa Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:07:29 +0100 Subject: [PATCH 0109/2040] Added and fixed all missing tcMod parameters --- code/renderer/tr_shader.c | 212 ++++++++++++++++++++++++++++++-------- 1 file changed, 170 insertions(+), 42 deletions(-) diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index ab0b2e1f..c356aebd 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -459,6 +459,8 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) tmi->wave.frequency = atof( token ); tmi->type = TMOD_TURBULENT; + + shader.flags |= 2; } // // scale @@ -493,62 +495,103 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); return; } - tmi->scroll[0] = atof( token ); + if (!Q_stricmp(token, "fromEntity")) { + tmi->scroll[0] = 1234567; + } else { + tmi->scroll[0] = atof(token); + } + token = COM_ParseExt( text, qfalse ); if ( token[0] == 0 ) { ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); return; } - tmi->scroll[1] = atof( token ); + if (!Q_stricmp(token, "fromEntity")) { + tmi->scroll[1] = 1234567; + } else { + tmi->scroll[1] = atof(token); + } + + token = COM_ParseExt(text, qfalse); + if (token[0]) { + if (atof(token) < 0) { + tmi->scroll[0] -= (rand() % (int)(atof(token) * 1000.0)) / 1000.0; + } else if (atof(token) > 0) { + tmi->scroll[0] += (rand() % (int)(atof(token) * 1000.0)) / 1000.0; + } + } + + token = COM_ParseExt(text, qfalse); + if (token[0]) { + if (atof(token) < 0) { + tmi->scroll[1] -= (rand() % (int)(atof(token) * 1000.0)) / 1000.0; + } else if (atof(token) > 0) { + tmi->scroll[1] += (rand() % (int)(atof(token) * 1000.0)) / 1000.0; + } + } + tmi->type = TMOD_SCROLL; + + shader.flags |= 2; } // // stretch // else if ( !Q_stricmp( token, "stretch" ) ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.func = NameToGenFunc( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - + ParseWaveForm(text, &tmi->wave); tmi->type = TMOD_STRETCH; + shader.flags |= 2; + } + else if ( !Q_stricmp( token, "wavetrans" ) ) + { + ParseWaveForm(text, &tmi->wave); + tmi->type = TMOD_WAVETRANS; + shader.flags |= 2; + } + else if ( !Q_stricmp( token, "wavetrant" ) ) + { + ParseWaveForm(text, &tmi->wave); + tmi->type = TMOD_WAVETRANT; + shader.flags |= 2; + } + else if ( !Q_stricmp( token, "bulge" ) ) + { + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing tcMod bulge parms in shader '%s'\n", shader.name); + return; + } + + tmi->wave.base = atof(token); + + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing tcMod bulge parms in shader '%s'\n", shader.name); + return; + } + + tmi->wave.amplitude = atof(token); + + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing tcMod bulge parms in shader '%s'\n", shader.name); + return; + } + + tmi->wave.frequency = atof(token); + + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing tcMod bulge parms in shader '%s'\n", shader.name); + return; + } + + tmi->wave.phase = atof(token); + + tmi->type = TMOD_BULGETRANS; + shader.flags |= 2; } // // transform @@ -643,6 +686,51 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) tmi->type = TMOD_ROTATE; } + else if (!Q_stricmp(token, "offset")) { + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing offset parms in shader '%s'\n", shader.name); + return; + } + + if (!Q_stricmp(token, "fromEntity")) { + tmi->scroll[0] = 1234567; + } else { + tmi->scroll[0] = atof(token); + } + + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing offset parms in shader '%s'\n", shader.name); + return; + } + + if (!Q_stricmp(token, "fromEntity")) { + tmi->scroll[1] = 1234567; + } else { + tmi->scroll[1] = atof(token); + } + + token = COM_ParseExt(text, qfalse); + if (token[0]) { + if (atof(token) < 0) { + tmi->scroll[0] -= (rand() % (int)(atof(token) * 1000.0 + 1.0)) / 1000.0; + } else if (atof(token) > 0) { + tmi->scroll[0] += (rand() % (int)(atof(token) * 1000.0 + 1.0)) / 1000.0; + } + } + + token = COM_ParseExt(text, qfalse); + if (token[0]) { + if (atof(token) < 0) { + tmi->scroll[1] -= (rand() % (int)(atof(token) * 1000.0 + 1.0)) / 1000.0; + } else if (atof(token) > 0) { + tmi->scroll[1] += (rand() % (int)(atof(token) * 1000.0 + 1.0)) / 1000.0; + } + } + + tmi->type = TMOD_OFFSET; + } // // entityTranslate // @@ -650,6 +738,46 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) { tmi->type = TMOD_ENTITY_TRANSLATE; } + else if ( !Q_stricmp( token, "parallax" ) ) + { + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing rate parms in shader '%s'\n", shader.name); + return; + } + + tmi->rate[0] = atof(token); + + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing rate parms in shader '%s'\n", shader.name); + return; + } + + tmi->rate[1] = atof(token); + tmi->type = TMOD_PARALLAX; + } + else if ( !Q_stricmp( token, "macro" ) ) + { + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing scale parms in shader '%s' for macro definition\n", shader.name); + return; + } + + tmi->scale[0] = 1.0 / atof(token); + + token = COM_ParseExt(text, qfalse); + if (token[0] == 0) { + ri.Printf(PRINT_WARNING, "WARNING: missing scale parms in shader '%s' for macro definition\n", shader.name); + return; + } + + tmi->scale[1] = 1.0 / atof(token); + + tmi->type = TMOD_MACRO; + shader.needsNormal = qtrue; + } else { ri.Printf(PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name); From e032a1a6275d7628e8552828e078d0f80060bf48 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:16:20 +0100 Subject: [PATCH 0110/2040] Implemented all tcMod values --- code/renderer/tr_local.h | 10 ++ code/renderer/tr_shade.c | 26 ++++- code/renderer/tr_shade_calc.c | 184 ++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 34a6b550..9b229b2c 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -2227,6 +2227,11 @@ void RB_DeformTessGeometry( void ); void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); void RB_CalcEnvironmentTexCoords2( float *dstTexCoords ); +void RB_CalcOffsetTexCoords(const float* offset, float* st); +void RB_CalcParallaxTexCoords(const float* rate, float* st); +void RB_TextureAxisFromPlane(const vec3_t normal, vec3_t xv, vec3_t yv); +void RB_QuakeTextureVecs(const vec3_t normal, const vec2_t scale, vec3_t mappingVecs[2]); +void RB_CalcMacroTexCoords(const float* rate, float* st); void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords ); void RB_CalcRotateTexCoords( float degsPerSecond, float degsPerSecondCoef, float* st, float start ); void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords ); @@ -2254,6 +2259,11 @@ void RB_CalcAlphaFromDotView(unsigned char* colors, float alphaMin, float alphaM void RB_CalcAlphaFromOneMinusDotView(unsigned char* colors, float alphaMin, float alphaMax); void RB_CalcDiffuseColor( unsigned char *colors ); +void RB_CalcStretchTexCoords(const waveForm_t* wf, float* st); +void RB_CalcTransWaveTexCoords(const waveForm_t* wf, float* st); +void RB_CalcTransWaveTexCoordsT(const waveForm_t* wf, float* st); +void RB_CalcBulgeTexCoords(const waveForm_t* wf, float* st); + /* ============================================================= diff --git a/code/renderer/tr_shade.c b/code/renderer/tr_shade.c index fbd47618..52f8e144 100644 --- a/code/renderer/tr_shade.c +++ b/code/renderer/tr_shade.c @@ -1386,8 +1386,32 @@ static void ComputeTexCoords( shaderStage_t *pStage ) { pStage->bundle[b].texMods[tm].rotateStart ); break; + case TMOD_OFFSET: + RB_CalcOffsetTexCoords(pStage->bundle[b].texMods[tm].scroll, tess.svars.texcoords[b][0]); + break; + + case TMOD_PARALLAX: + RB_CalcParallaxTexCoords(pStage->bundle[b].texMods[tm].rate, tess.svars.texcoords[b][0]); + break; + + case TMOD_MACRO: + RB_CalcMacroTexCoords(pStage->bundle[b].texMods[tm].scale, tess.svars.texcoords[b][0]); + break; + + case TMOD_WAVETRANS: + RB_CalcTransWaveTexCoords(&pStage->bundle[b].texMods[tm].wave, tess.svars.texcoords[b][0]); + break; + + case TMOD_WAVETRANT: + RB_CalcTransWaveTexCoordsT(&pStage->bundle[b].texMods[tm].wave, tess.svars.texcoords[b][0]); + break; + + case TMOD_BULGETRANS: + RB_CalcBulgeTexCoords(&pStage->bundle[b].texMods[tm].wave, tess.svars.texcoords[b][0]); + break; + default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name ); + ri.Printf(PRINT_WARNING, "WARNING: invalid tcMod '%d' specified for shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name ); break; } } diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index 8297eaa6..fe9f8308 100644 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -101,6 +101,64 @@ void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st ) RB_CalcTransformTexCoords( &tmi, st ); } +/* +======================== +RB_CalcTransWaveTexCoords + +======================== +*/ +void RB_CalcTransWaveTexCoords(const waveForm_t* wf, float* st) +{ + float p; + int i; + + p = EvalWaveForm(wf); + for (i = 0; i < tess.numVertexes; i++, st += 2) { + st[0] += p; + } +} + +/* +======================== +RB_CalcTransWaveTexCoordsT + +======================== +*/ +void RB_CalcTransWaveTexCoordsT(const waveForm_t* wf, float* st) +{ + float p; + int i; + + p = EvalWaveForm(wf); + for (i = 0; i < tess.numVertexes; i++, st += 2) { + st[1] += p; + } +} + +/* +======================== +RB_CalcBulgeTexCoords + +======================== +*/ +void RB_CalcBulgeTexCoords(const waveForm_t* wf, float* st) +{ + int i; + int off; + float offset; + float now; + float amplitude; + float width; + + amplitude = wf->amplitude; + width = wf->base; + now = backEnd.refdef.time / 1000.0 * wf->frequency + wf->phase; + + for (i = 0; i < tess.numVertexes; i++, st += 2) { + offset = tr.sinTable[(int)((now + st[0] * width) * FUNCTABLE_SIZE) & FUNCTABLE_MASK] * amplitude; + } +} + /* ==================================================================== @@ -1144,6 +1202,132 @@ void RB_CalcScaleTexCoords( const float scale[2], float *st ) } } +/* +** RB_CalcOffsetTexCoords +*/ +void RB_CalcOffsetTexCoords( const float *offset, float *st ) +{ + int i; + float offsetS, offsetT; + + if (offset[0] != 1234567) { + offsetS = offset[0]; + } else if (backEnd.currentEntity) { + offsetS = backEnd.currentEntity->e.shader_data[0]; + } else { + offsetS = r_static_shaderdata0->value; + } + + if (offset[0] != 1234567) { + offsetT = offset[1]; + } else if (backEnd.currentEntity) { + offsetT = backEnd.currentEntity->e.shader_data[1]; + } else { + offsetT = r_static_shaderdata1->value; + } + + if (!backEnd.currentEntity) { + offsetS = offsetS * r_static_shadermultiplier0->value; + offsetT = offsetT * r_static_shadermultiplier1->value; + } + + for (i = 0; i < tess.numVertexes; i++, st += 2) { + float s, t; + + s = st[0]; + t = st[1]; + + st[0] = s + offsetS; + st[1] = t + offsetT; + } +} + +/* +** RB_CalcParallaxTexCoords +*/ +void RB_CalcParallaxTexCoords( const float *rate, float *st ) +{ + int i; + float offsetS, offsetT; + + offsetS = tr.refdef.vieworg[0] * rate[0]; + offsetT = tr.refdef.vieworg[1] * rate[1]; + for (i = 0; i < tess.numVertexes; i++, st += 2) { + st[0] += offsetS; + st[1] += offsetT; + } +} + +static vec3_t rb_baseaxis[18]; + + +void RB_TextureAxisFromPlane(const vec3_t normal, vec3_t xv, vec3_t yv) +{ + int bestaxis; + vec_t dot; + vec_t best; + int i; + + if (normal[0] == 1) { + bestaxis = 2; + } else if (normal[0] == -1) { + bestaxis = 3; + } else if (normal[1] == 1) { + bestaxis = 4; + } else if (normal[1] == -1) { + bestaxis = 5; + } else if (normal[2] == 1) { + bestaxis = 0; + } else if (normal[2] == -1) { + bestaxis = 1; + } else { + best = 0; + bestaxis = 0; + + for (i = 0; i < 6; i++) { + dot = DotProduct(rb_baseaxis[i * 3], normal); + if (dot > best) { + best = dot; + bestaxis = i; + } + } + } + + VectorCopy(rb_baseaxis[bestaxis * 3 + 1], xv); + VectorCopy(rb_baseaxis[bestaxis * 3 + 2], yv); +} + +void RB_QuakeTextureVecs(const vec3_t normal, const vec2_t scale, vec3_t mappingVecs[2]) +{ + RB_TextureAxisFromPlane(normal, mappingVecs[0], mappingVecs[1]); + + VectorScale(mappingVecs[0], scale[0], mappingVecs[0]); + VectorScale(mappingVecs[1], scale[1], mappingVecs[1]); +} + +/* +** RB_CalcMacroTexCoords +*/ +void RB_CalcMacroTexCoords( const float* rate, float *st ) +{ + int i; + vec3_t vecs[2]; + vec_t* v; + vec_t* normal; + float width, height; + v = tess.xyz[0]; + + normal = tess.normal[0]; + width = (float)tess.shader->unfoggedStages[0]->bundle[0].image[0]->uploadWidth; + height = (float)tess.shader->unfoggedStages[0]->bundle[0].image[0]->uploadHeight; + + for (i = 0; i < tess.numVertexes; i++, v += 4, normal += 4, st += 2) { + RB_QuakeTextureVecs(normal, rate, vecs); + st[0] = DotProduct(vecs[0], v) / width; + st[1] = DotProduct(vecs[1], v) / height; + } +} + /* ** RB_CalcScrollTexCoords */ From 84791c42bc02f84f3191131da20b240ee8b3add0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:23:26 +0100 Subject: [PATCH 0111/2040] Implemented RB_CalcSunReflectionTexCoords --- code/renderer/tr_local.h | 1 + code/renderer/tr_shade.c | 2 +- code/renderer/tr_shade_calc.c | 45 +++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 9b229b2c..aeaee13d 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -2227,6 +2227,7 @@ void RB_DeformTessGeometry( void ); void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); void RB_CalcEnvironmentTexCoords2( float *dstTexCoords ); +void RB_CalcSunReflectionTexCoords( float *dstTexCoords ); void RB_CalcOffsetTexCoords(const float* offset, float* st); void RB_CalcParallaxTexCoords(const float* rate, float* st); void RB_TextureAxisFromPlane(const vec3_t normal, vec3_t xv, vec3_t yv); diff --git a/code/renderer/tr_shade.c b/code/renderer/tr_shade.c index 52f8e144..2a4f7c60 100644 --- a/code/renderer/tr_shade.c +++ b/code/renderer/tr_shade.c @@ -1327,7 +1327,7 @@ static void ComputeTexCoords( shaderStage_t *pStage ) { RB_CalcEnvironmentTexCoords2((float*)tess.svars.texcoords[b]); break; case TCGEN_SUN_REFLECTION: - // FIXME: unimplemented + RB_CalcSunReflectionTexCoords(tess.svars.texcoords[b][0]); break; default: ri.Printf( diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index fe9f8308..d8d73276 100644 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -1168,6 +1168,51 @@ void RB_CalcEnvironmentTexCoords2(float* st) } } +/* +** RB_CalcSunReflectionTexCoords +*/ +void RB_CalcSunReflectionTexCoords(float* st) { + int i; + vec3_t viewer; + vec3_t reflected; + vec3_t sunReflected; + float d; + float* v; + float* normal; + vec3_t sunAxis[3]; + + v = tess.xyz[0]; + normal = tess.normal[0]; + sunAxis[0][0] = tr.sunDirection[0]; + sunAxis[0][1] = tr.sunDirection[1]; + sunAxis[0][2] = tr.sunDirection[2]; + sunAxis[1][0] = tr.sunDirection[1]; + sunAxis[1][1] = -tr.sunDirection[0]; + sunAxis[1][2] = 0.0; + VectorNormalizeFast(sunAxis[1]); + CrossProduct(sunAxis, sunAxis[1], sunAxis[2]); + + for (i = 0; i < tess.numVertexes; i++, v += 4, normal += 4, st += 2) { + VectorSubtract(v, backEnd.ori.viewOrigin, viewer); + VectorNormalizeFast(viewer); + + d = DotProduct(viewer, normal); + if (d > 0) { + VectorCopy(viewer, reflected); + } else { + d *= -2; + VectorMA(viewer, d, normal, reflected); + } + + VectorScale(sunAxis[0], reflected[0], sunReflected); + VectorMA(sunReflected, reflected[2], sunAxis[1], sunReflected); + VectorMA(sunReflected, -reflected[1], sunAxis[2], sunReflected); + + st[0] = sunReflected[1] + 0.5; + st[1] = sunReflected[2] + 0.5; + } +} + /* ** RB_CalcTurbulentTexCoords */ From c5dcf96717db7779bfd6fe5ddcf4c02f89b6b1ef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:54:48 +0100 Subject: [PATCH 0112/2040] Implemented all RB_Calc functions --- code/renderer/tr_shade_calc.c | 192 ++++++++++++++++++++++++++++++++-- 1 file changed, 182 insertions(+), 10 deletions(-) diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index d8d73276..041729b5 100644 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -155,7 +155,8 @@ void RB_CalcBulgeTexCoords(const waveForm_t* wf, float* st) now = backEnd.refdef.time / 1000.0 * wf->frequency + wf->phase; for (i = 0; i < tess.numVertexes; i++, st += 2) { - offset = tr.sinTable[(int)((now + st[0] * width) * FUNCTABLE_SIZE) & FUNCTABLE_MASK] * amplitude; + off = (now + st[0] * width) * FUNCTABLE_SIZE; + offset = tr.sinTable[off & FUNCTABLE_MASK] * amplitude; } } @@ -936,16 +937,66 @@ void RB_CalcColorFromConstant(unsigned char* dstColors, unsigned char* constantC } } +/* +** RB_CalcRGBFromDot +*/ void RB_CalcRGBFromDot(unsigned char* colors, float alphaMin, float alphaMax) { - // FIXME: unimplemented + int i; + vec3_t viewInModel; + + for (i = 0; i < tess.numVertexes; i++, colors += 4) { + union { + float f; + int i; + } u; + + VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); + VectorNormalizeFast(viewInModel); + + u.f = DotProduct(tess.normal[i], viewInModel); + u.f *= u.f; + u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; + u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + + u.i &= ~(u.i >> 31); + colors[0] = colors[1] = colors[2] = u.i; + } } +/* +** RB_CalcRGBFromOneMinusDot +*/ void RB_CalcRGBFromOneMinusDot(unsigned char* colors, float alphaMin, float alphaMax) { - // FIXME: unimplemented + int i; + vec3_t viewInModel; + float dot; + + for (i = 0; i < tess.numVertexes; i++, colors += 4) { + union { + float f; + int i; + } u; + + VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); + VectorNormalizeFast(viewInModel); + + dot = DotProduct(tess.normal[i], viewInModel); + dot *= dot; + + u.f = 1.0 - dot; + u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; + u.f = u.f - (long double)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + + u.i &= ~(u.i >> 31); + colors[0] = colors[1] = colors[2] = u.i; + } } +/* +** RB_CalcAlphaFromConstant +*/ void RB_CalcAlphaFromConstant(unsigned char* dstColors, int constantAlpha) { int i; @@ -955,11 +1006,36 @@ void RB_CalcAlphaFromConstant(unsigned char* dstColors, int constantAlpha) } } +/* +** RB_CalcAlphaFromDot +*/ void RB_CalcAlphaFromDot(unsigned char* colors, float alphaMin, float alphaMax) { - // FIXME: unimplemented + int i; + vec3_t viewInModel; + + for (i = 0; i < tess.numVertexes; i++, colors += 4) { + union { + float f; + int i; + } u; + + VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); + VectorNormalizeFast(viewInModel); + + u.f = DotProduct(tess.normal[i], viewInModel); + u.f *= u.f; + u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; + u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + + u.i &= ~(u.i >> 31); + colors[0] = colors[1] = colors[2] = u.i; + } } +/* +** RB_CalcAlphaFromHeightFade +*/ void RB_CalcAlphaFromHeightFade(unsigned char* colors, float alphaMin, float alphaMax) { int i; @@ -975,19 +1051,72 @@ void RB_CalcAlphaFromHeightFade(unsigned char* colors, float alphaMin, float alp } } +/* +** RB_CalcAlphaFromOneMinusDot +*/ void RB_CalcAlphaFromOneMinusDot(unsigned char* colors, float alphaMin, float alphaMax) { - // FIXME: unimplemented + int i; + vec3_t viewInModel; + float dot; + + for (i = 0; i < tess.numVertexes; i++, colors += 4) { + union { + float f; + int i; + } u; + + VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); + VectorNormalizeFast(viewInModel); + + dot = DotProduct(tess.normal[i], viewInModel); + dot *= dot; + + u.f = 1.0 - dot; + u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; + u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + + u.i &= ~(u.i >> 31); + colors[0] = colors[1] = colors[2] = u.i; + } } +/* +** RB_CalcAlphaFromTexCoords +*/ void RB_CalcAlphaFromTexCoords(unsigned char* colors, float alphaMin, float alphaMax, int alphaMinCap, int alphaCap, float sWeight, float tWeight, float* st) { - // FIXME: unimplemented + int i; + + for (i = 0; i < tess.numVertexes; i++, colors += 4, st += 2) { + float f; + + f = sWeight * tess.texCoords[i][0][0] + tWeight * tess.texCoords[i][0][1]; + f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; + f = f - (float)(~((int)(f - (float)(byte)alphaCap) >> 31) & (int)(f - (float)(byte)alphaCap)); + f = (float)((~((int)(f - (float)(byte)alphaMinCap) >> 31) & (int)(f - (float)(byte)alphaMinCap)) + (byte)alphaMinCap); + + colors[3] = f; + } } +/* +** RB_CalcRGBFromTexCoords +*/ void RB_CalcRGBFromTexCoords(unsigned char* colors, float alphaMin, float alphaMax, int alphaMinCap, int alphaCap, float sWeight, float tWeight, float* st) { - // FIXME: unimplemented + int i; + + for (i = 0; i < tess.numVertexes; i++, colors += 4, st += 2) { + float f; + + f = sWeight * tess.texCoords[i][0][0] + tWeight * tess.texCoords[i][0][1]; + f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; + f = f - (float)(~((int)(f - (float)(byte)alphaCap) >> 31) & (int)(f - (float)(byte)alphaCap)); + f = (float)((~((int)(f - (float)(byte)alphaMinCap) >> 31) & (int)(f - (float)(byte)alphaMinCap)) + (byte)alphaMinCap); + + colors[0] = colors[1] = colors[2] = f; + } } /* @@ -1190,7 +1319,7 @@ void RB_CalcSunReflectionTexCoords(float* st) { sunAxis[1][1] = -tr.sunDirection[0]; sunAxis[1][2] = 0.0; VectorNormalizeFast(sunAxis[1]); - CrossProduct(sunAxis, sunAxis[1], sunAxis[2]); + CrossProduct(sunAxis[0], sunAxis[1], sunAxis[2]); for (i = 0; i < tess.numVertexes; i++, v += 4, normal += 4, st += 2) { VectorSubtract(v, backEnd.ori.viewOrigin, viewer); @@ -1562,12 +1691,55 @@ void RB_CalcLightGridColor(unsigned char* colors) void RB_CalcAlphaFromDotView(unsigned char* colors, float alphaMin, float alphaMax) { - // FIXME/ unimplemented + int i; + vec3_t viewInModel; + + for (i = 0; i < tess.numVertexes; i++, colors += 4) { + union { + float f; + int i; + } u; + + VectorCopy(tr.refdef.viewaxis[0], viewInModel); + VectorNormalizeFast(viewInModel); + + u.f = DotProduct(viewInModel, tess.normal[i]); + u.f = fabs(u.f); + Com_Printf("normal: %f %f %f dot: %f i %d\n", tess.normal[i][0], tess.normal[i][1], tess.normal[i][2], u.f, i); + + u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; + u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + + u.i &= ~(u.i >> 31); + colors[3] = u.i; + } } void RB_CalcAlphaFromOneMinusDotView(unsigned char* colors, float alphaMin, float alphaMax) { - // FIXME/ unimplemented + int i; + vec3_t viewInModel; + + for (i = 0; i < tess.numVertexes; i++, colors += 4) { + union { + float f; + int i; + } u; + + VectorCopy(tr.refdef.viewaxis[0], viewInModel); + VectorNormalizeFast(viewInModel); + + u.f = DotProduct(viewInModel, tess.normal[i]); + u.f = fabs(u.f); + u.f = 1.0 - u.f; + Com_Printf("normal: %f %f %f dot: %f i %d\n", tess.normal[i][0], tess.normal[i][1], tess.normal[i][2], u.f, i); + + u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; + u.f = u.f - (long double)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + + u.i &= ~(u.i >> 31); + colors[3] = u.i; + } } /* From 434a48af7da4a95e8114a95b1d2917f761ce5443 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:57:37 +0100 Subject: [PATCH 0113/2040] Initialize m_iNumShotsFired --- code/fgame/weapon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index 935e303d..98a37e51 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -1133,6 +1133,7 @@ Weapon::Weapon() INITIALIZE_WEAPONMODE_VAR(meansofdeath, MOD_NONE); // Set the stats + m_iNumShotsFired = 0; m_iNumHits = 0; m_iNumGroinShots = 0; m_iNumHeadShots = 0; From ac63e6c62770de575210f80ee7b0020423f0de59 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:31:48 +0100 Subject: [PATCH 0114/2040] Rotate the client when blocked, and make sure the checked's velocity doesn't reach the push move speed --- code/fgame/g_phys.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index af01704d..fbb7c86a 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -729,6 +729,7 @@ qboolean G_Push pushed_t *pusher_p; float radius; int i, num; + int j; int touch[ MAX_GENTITIES ]; Event *ev; @@ -860,12 +861,12 @@ qboolean G_Push move2 = move; // FIXME: doesn't rotate monsters? - /*if( check->client && amove[ YAW ] ) + if( check->client && amove[ YAW ] ) { Sentient *sent = ( Sentient * )check; Vector a = sent->GetViewAngles() + Vector( 0, amove[ YAW ], 0 ); sent->SetViewAngles( a ); - }*/ + } // get the radius of the entity if( check->size.x > check->size.z ) @@ -917,7 +918,7 @@ qboolean G_Push end = check->origin + fwd * ( length + 64.0f ); - if( check->IsSubclassOfPlayer() ) + if( check->IsSubclassOfSentient() ) { trace = G_Trace( check->origin, check->mins, check->maxs, end, check, check->edict->clipmask, true, "G_Push" ); } @@ -928,7 +929,7 @@ qboolean G_Push if( !trace.allsolid ) { - if( check->IsSubclassOfPlayer() ) + if( check->IsSubclassOfSentient() ) { trace = G_Trace( Vector( trace.endpos ), check->mins, check->maxs, neworg, check, check->edict->clipmask, true, "G_Push" ); } @@ -949,6 +950,26 @@ qboolean G_Push if( check->groundentity != pusher->edict ) check->groundentity = NULL; } + else + { + move2 *= 1.f / level.frametime; + + for (j = 0; j < 3; j++) { + if (!move2[j]) { + continue; + } + + if (move2[j] < 0) { + if (check->velocity[j] > move2[j]) { + check->velocity[j] = move2[j]; + } + } else { + if (check->velocity[j] < move2[j]) { + check->velocity[j] = move2[j]; + } + } + } + } block = G_TestEntityPosition( check, check->origin ); if( block ) From 8fe054b063a60f56115a9793a0430f4f7ec3a827 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:32:33 +0100 Subject: [PATCH 0115/2040] Fixed door open direction --- code/fgame/doors.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/fgame/doors.cpp b/code/fgame/doors.cpp index 86296580..144c7d29 100644 --- a/code/fgame/doors.cpp +++ b/code/fgame/doors.cpp @@ -1311,8 +1311,6 @@ void RotatingDoor::DoOpen(Event *ev) } else { diropened = 0 - init_door_direction; } - } else { - diropened = -init_door_direction; } if (diropened < 0.0f) { @@ -1321,7 +1319,16 @@ void RotatingDoor::DoOpen(Event *ev) ang = startangle - Vector(0.0f, angle, 0.0f); } + if (localangles.yaw() + 360 <= ang.yaw()) { + localangles.setYaw(localangles.yaw() + 360); + } else if (localangles.yaw() - 360 >= ang.yaw()) { + localangles.setYaw(localangles.yaw() - 360); + } + MoveTo(origin, ang, fabs(speed * angle), EV_Door_OpenEnd); + + setContents(CONTENTS_SOLID); + setSolidType(SOLID_BSP); } void RotatingDoor::DoClose(Event *ev) From f0aad4bb2102f7b795ab976ea8c4cdf1b7943cc5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Feb 2024 22:51:50 +0100 Subject: [PATCH 0116/2040] Don't mark the driver slot as unused by default --- code/fgame/vehicle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 21f38dee..f9795501 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -1213,7 +1213,7 @@ void Vehicle::ResetSlots(void) driver.ent = NULL; driver.boneindex = -1; driver.enter_boneindex = -1; - driver.flags = SLOT_UNUSED; + driver.flags = 0; lastdriver.ent = NULL; lastdriver.boneindex = -1; lastdriver.enter_boneindex = -1; From 078aa01895ac16ed0d661f1642bfb110196a6c45 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Feb 2024 23:33:02 +0100 Subject: [PATCH 0117/2040] Reimplemented RefreshMaterial() --- code/uilib/uiwidget.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/uilib/uiwidget.cpp b/code/uilib/uiwidget.cpp index 1f7afce2..39151320 100644 --- a/code/uilib/uiwidget.cpp +++ b/code/uilib/uiwidget.cpp @@ -651,10 +651,9 @@ void UIReggedMaterial::RefreshMaterial ) { - if( !isGot ) + if( isGot ) { - isGot = true; - this->hMat = uii.Rend_RefreshMaterial( name.c_str() ); + this->hMat = uii.Rend_RegisterMaterial( name.c_str() ); } } From 1b8ad12b250f1424f2ea41f77016416971a32bea Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Feb 2024 23:33:12 +0100 Subject: [PATCH 0118/2040] Call RefreshMaterial() instead of ReregisterMaterial() --- code/uilib/uiwinman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/uilib/uiwinman.cpp b/code/uilib/uiwinman.cpp index c988d08f..d5d7377b 100644 --- a/code/uilib/uiwinman.cpp +++ b/code/uilib/uiwinman.cpp @@ -667,7 +667,7 @@ void UIWindowManager::RefreshShadersFromList(void) num = m_materiallist.NumObjects(); for (i = 1; i <= num; i++) { UIReggedMaterial *regged = m_materiallist.ObjectAt(i); - regged->ReregisterMaterial(); + regged->RefreshMaterial(); } } From f018c2c15af2a89905ce9f11c6d6ce78f9fd77e4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Feb 2024 23:36:04 +0100 Subject: [PATCH 0119/2040] Ignore shaders for surface starting with the name "material" --- code/tiki/tiki_files.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 3d87867d..dbfd5e76 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -470,7 +470,7 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapname, surf->name, sizeof(tikiSurf->name)); - if (strlen(surf->name) != 9 || !Q_strncmp(surf->name, "material", 8)) { + if (strlen(surf->name) != 9 || Q_strncmp(surf->name, "material", 8)) { Q_strncpyz(tikiSurf->shader[0], surf->name, sizeof(tikiSurf->shader[0])); } From 5aa70d91f333f84b4b33fa54f5f4e1cf0613fae1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Feb 2024 23:44:59 +0100 Subject: [PATCH 0120/2040] Fixed patch subdivisions --- code/renderer/tr_bsp.c | 10 ++++++++-- code/renderer/tr_curve.c | 4 ++-- code/renderer/tr_local.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 79cec179..15541cdd 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -763,8 +763,14 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { R_ColorShiftLightingBytesAlpha( verts[i].color, points[i].color ); } - // pre-tesseleate - grid = R_SubdividePatchToGrid( width, height, points ); + // pre-tesseleate + if (ds->subdivisions) { + grid = R_SubdividePatchToGrid(width, height, ds->subdivisions * (r_subdivisions->value / 10.0), points); + } else if (surf->shader->subdivisions) { + grid = R_SubdividePatchToGrid(width, height, surf->shader->subdivisions * (r_subdivisions->value / 10.0), points); + } else { + grid = R_SubdividePatchToGrid(width, height, r_subdivisions->value, points); + } surf->data = (surfaceType_t *)grid; if (tr.numLightmaps && lightmapNum != -1 && surf->shader->lightmapIndex >= 0) diff --git a/code/renderer/tr_curve.c b/code/renderer/tr_curve.c index 14db39ad..446650f5 100644 --- a/code/renderer/tr_curve.c +++ b/code/renderer/tr_curve.c @@ -357,7 +357,7 @@ void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) { R_SubdividePatchToGrid ================= */ -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, +srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, float subdivide, drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { int i, j, k, l; drawVert_t prev, next, mid; @@ -431,7 +431,7 @@ srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, continue; // can't subdivide any more } - if ( maxLen <= r_subdivisions->value ) { + if ( maxLen <= subdivide ) { errorTable[dir][j+1] = 1.0f/maxLen; continue; // didn't need subdivision } diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index aeaee13d..d99f8b6d 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -2006,7 +2006,7 @@ CURVE TESSELATION #define PATCH_STITCHING -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, +srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, float subdivide, drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ); srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ); From 1d765125c735549c76c98d1c8f07147b85a24822 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:35:11 +0100 Subject: [PATCH 0121/2040] Fixed facets and planes being badly initialized --- code/qcommon/cm_patch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/qcommon/cm_patch.c b/code/qcommon/cm_patch.c index 89a0c0ad..b2fa6a99 100644 --- a/code/qcommon/cm_patch.c +++ b/code/qcommon/cm_patch.c @@ -1132,8 +1132,8 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { pf->numPlanes = numPlanes; pf->numFacets = numFacets; if (numPlanes >= 1) { - pf->facets = Hunk_Alloc(numFacets * sizeof(*pf->facets), h_dontcare); - Com_Memcpy(pf->facets, facets, numFacets * sizeof(*pf->facets)); + pf->planes = Hunk_Alloc(numPlanes * sizeof(*pf->planes), h_dontcare); + Com_Memcpy(pf->planes, planes, numPlanes * sizeof(*pf->planes)); } else { pf->numPlanes = 0; pf->planes = NULL; @@ -1148,8 +1148,8 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { } if (numFacets >= 1) { - pf->planes = Hunk_Alloc(numPlanes * sizeof(*pf->planes), h_dontcare); - Com_Memcpy(pf->planes, planes, numPlanes * sizeof(*pf->planes)); + pf->facets = Hunk_Alloc(numFacets * sizeof(*pf->facets), h_dontcare); + Com_Memcpy(pf->facets, facets, numFacets * sizeof(*pf->facets)); } else { pf->numFacets = 0; pf->facets = NULL; From 1fa2031f111ab20998c514a6db232c03ea5d4ecb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:41:33 +0100 Subject: [PATCH 0122/2040] When a player is inside a vehicle, use the vehicle's health for the health stat --- code/fgame/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 0ed199f1..d80e454a 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -7216,7 +7216,7 @@ void Player::UpdateStats(void) healthfrac = (health / max_health * 100.0f); if (m_pVehicle && !m_pTurret) { - if (m_pVehicle->isSubclassOf(FixedTurret)) { + if (!m_pVehicle->isSubclassOf(FixedTurret)) { healthfrac = (m_pVehicle->health / m_pVehicle->max_health * 100.f); } } From d3870309fbe4a191ade427650e5dfc9ac69ba2c0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:56:44 +0100 Subject: [PATCH 0123/2040] Fixed MASK_MONSTERSOLID --- code/fgame/bg_public.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 890fa1d2..5822dd99 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -621,7 +621,7 @@ movement on the server game. #define MASK_PLAYERSTART (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BODY) #define MASK_VIEWSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_FENCE | CONTENTS_TRIGGER) #define MASK_DEADSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_CORPSE | CONTENTS_NOTTEAM2 | CONTENTS_FENCE) -#define MASK_MONSTERSOLID (CONTENTS_SOLID | CONTENTS_MONSTERCLIP | CONTENTS_BODY) +#define MASK_MONSTERSOLID (CONTENTS_SOLID | CONTENTS_MONSTERCLIP | CONTENTS_BODY | CONTENTS_TRIGGER | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) #define MASK_WATER (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME) #define MASK_OPAQUE (CONTENTS_SOLID | CONTENTS_SLIME | CONTENTS_LAVA) #define MASK_SHOT \ From e1f2a51f2bd246644ab6d8a92536416463779c8a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:07:32 +0100 Subject: [PATCH 0124/2040] Only move angles if there is an angular velocity --- code/fgame/g_phys.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index fbb7c86a..8be9e7a9 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -1258,8 +1258,10 @@ void G_Physics_Toss G_AddGravity( ent ); } - // move angles - ent->setAngles( ent->angles + ent->avelocity * level.frametime ); + if (ent->avelocity.lengthSquared()) { + // move angles + ent->setAngles(ent->angles + ent->avelocity * level.frametime); + } // move origin move = ( ent->velocity + basevel ) * level.frametime; From ed3f212bd8a7f2256813223ddcf45fa66c9df47b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:10:21 +0100 Subject: [PATCH 0125/2040] Also check for slide with bounce movetype --- code/fgame/g_phys.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index 8be9e7a9..27abbac2 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -1291,13 +1291,13 @@ void G_Physics_Toss trace = G_PushEntity( ent, move ); } - if( ( trace.fraction == 0 ) && ( ent->movetype == MOVETYPE_SLIDE ) ) + if( ( trace.fraction == 0 ) && ( ent->movetype == MOVETYPE_SLIDE || ent->movetype == MOVETYPE_BOUNCE ) ) { // Check for slide by removing the downward velocity Vector slide; - slide[ 0 ] = move[ 0 ] * 0.7f; - slide[ 1 ] = move[ 1 ] * 0.7f; + slide[ 0 ] = move[ 0 ] * level.frametime * 15; + slide[ 1 ] = move[ 1 ] * level.frametime * 15; slide[ 2 ] = 0; G_PushEntity( ent, slide ); } From 6840df4eca9d9cef1a6a348e78111113eeb187a8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:11:11 +0100 Subject: [PATCH 0126/2040] backoff value should be 1.4 for bounce and 1.6 for Gib --- code/fgame/g_phys.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index 27abbac2..4ceac5e7 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -1309,9 +1309,13 @@ void G_Physics_Toss if( trace.fraction < 1 ) { - if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_GIB ) + if( ent->movetype == MOVETYPE_BOUNCE ) { - backoff = 1.5; + backoff = 1.4; + } + else if ( ent->movetype == MOVETYPE_GIB ) + { + backoff = 1.6; } else { From 109686aca20bbfb6d95e41146954c5a4d51afe03 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:14:08 +0100 Subject: [PATCH 0127/2040] Reduce the velocity when bouncing --- code/fgame/g_phys.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index 4ceac5e7..f9a6495d 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -1326,6 +1326,12 @@ void G_Physics_Toss G_ClipVelocity( ent->velocity, normal, ent->velocity, backoff ); + if (ent->movetype == MOVETYPE_BOUNCE) { + // Reduce the velocity when bouncing + ent->velocity[0] -= level.frametime * 1.75f; + ent->velocity[1] -= level.frametime * 1.75f; + } + // stop if on ground if( trace.plane.normal[ 2 ] > 0.7 ) { From b893f4f89f142a0922eac7e445d997fdf5ba19bd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:20:52 +0100 Subject: [PATCH 0128/2040] Properly stop if on ground --- code/fgame/g_phys.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index f9a6495d..7eee0844 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -1311,11 +1311,11 @@ void G_Physics_Toss { if( ent->movetype == MOVETYPE_BOUNCE ) { - backoff = 1.4; + backoff = 1.4f; } else if ( ent->movetype == MOVETYPE_GIB ) { - backoff = 1.6; + backoff = 1.6f; } else { @@ -1335,20 +1335,22 @@ void G_Physics_Toss // stop if on ground if( trace.plane.normal[ 2 ] > 0.7 ) { - if( ( ent->velocity[ 2 ] < 60 || ( ent->movetype != MOVETYPE_BOUNCE && ent->movetype != MOVETYPE_GIB ) ) && + ent->groundentity = trace.ent; + ent->groundplane = trace.plane; + ent->groundcontents = trace.contents; + + if( ( ( ent->movetype == MOVETYPE_GIB && ent->velocity[ 2 ] < 60 ) || ( ent->movetype == MOVETYPE_BOUNCE && ent->velocity.length() < 40 ) ) && ( ent->movetype != MOVETYPE_SLIDE ) ) { - ent->groundentity = trace.ent; - ent->groundplane = trace.plane; - ent->groundcontents = trace.contents; ent->velocity = vec_zero; ent->avelocity = vec_zero; ent->ProcessEvent( EV_Stop ); } - else if( ent->movetype == MOVETYPE_GIB ) + else if( ent->movetype == MOVETYPE_TOSS || ent->movetype == MOVETYPE_GIB ) { // Stop spinning after we bounce on the ground ent->avelocity = vec_zero; + ent->ProcessEvent( EV_Stop ); } } } From ca7cacfdcc8cc140b0f4e95298329e1c041435cf Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:23:24 +0100 Subject: [PATCH 0129/2040] Add a debug line when bouncing if enabled (for AI) --- code/fgame/g_phys.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index 7eee0844..a8dcaaab 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "sentient.h" #include "actor.h" #include "player.h" +#include "debuglines.h" /* @@ -1399,6 +1400,10 @@ void G_Physics_Toss { G_TouchTriggers( ent ); } + + if (ai_debug_grenades->integer && ent->movetype == MOVETYPE_BOUNCE) { + G_DebugLine(origin2, ent->origin, 1, 1, 0, 1); + } } /* From bf700186d0face573ce32d103621c88e97700371 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:31:26 +0100 Subject: [PATCH 0130/2040] Fixed bounce velocity reduction --- code/fgame/g_phys.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index a8dcaaab..33133913 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -1329,8 +1329,8 @@ void G_Physics_Toss if (ent->movetype == MOVETYPE_BOUNCE) { // Reduce the velocity when bouncing - ent->velocity[0] -= level.frametime * 1.75f; - ent->velocity[1] -= level.frametime * 1.75f; + ent->velocity[0] -= ent->velocity[0] * level.frametime * 1.75f; + ent->velocity[1] -= ent->velocity[1] * level.frametime * 1.75f; } // stop if on ground From 3853d1ef39959e27d6a87e7b1716d2534a5a238e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:38:14 +0100 Subject: [PATCH 0131/2040] Properly map the CGM message depending on the protocol version --- code/fgame/weaputils.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index 166e74d9..b8ed2239 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -2272,7 +2272,7 @@ float BulletAttack( if (ent->edict->solid == SOLID_BBOX && !(trace.contents & CONTENTS_CLAYPIDGEON)) { if (trace.surfaceFlags & MASK_SURF_TYPE) { gi.SetBroadcastVisible(vTmpEnd, NULL); - gi.MSG_StartCGM(CGM_BULLET_6); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_6)); gi.MSG_WriteCoord(vTmpEnd[0]); gi.MSG_WriteCoord(vTmpEnd[1]); gi.MSG_WriteCoord(vTmpEnd[2]); @@ -2281,7 +2281,7 @@ float BulletAttack( gi.MSG_EndCGM(); } else if (trace.location >= 0 && ent->IsSubclassOfPlayer()) { gi.SetBroadcastVisible(vTmpEnd, NULL); - gi.MSG_StartCGM(CGM_BULLET_8); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_8)); gi.MSG_WriteCoord(vTmpEnd[0]); gi.MSG_WriteCoord(vTmpEnd[1]); gi.MSG_WriteCoord(vTmpEnd[2]); @@ -2290,7 +2290,7 @@ float BulletAttack( gi.MSG_EndCGM(); } else if (ent->edict->r.contents & CONTENTS_SOLID) { gi.SetBroadcastVisible(vTmpEnd, NULL); - gi.MSG_StartCGM(CGM_BULLET_7); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_7)); gi.MSG_WriteCoord(vTmpEnd[0]); gi.MSG_WriteCoord(vTmpEnd[1]); gi.MSG_WriteCoord(vTmpEnd[2]); @@ -2300,7 +2300,7 @@ float BulletAttack( } } else if (ent->edict->solid == SOLID_BSP && !(trace.contents & CONTENTS_CLAYPIDGEON)) { gi.SetBroadcastVisible(vTmpEnd, NULL); - gi.MSG_StartCGM(CGM_BULLET_6); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_6)); gi.MSG_WriteCoord(vTmpEnd[0]); gi.MSG_WriteCoord(vTmpEnd[1]); gi.MSG_WriteCoord(vTmpEnd[2]); @@ -2432,13 +2432,13 @@ float BulletAttack( if (count == 1) { if (iTracerCount) { - gi.MSG_StartCGM(CGM_BULLET_1); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_1)); gi.MSG_WriteCoord(vBarrel[0]); gi.MSG_WriteCoord(vBarrel[1]); gi.MSG_WriteCoord(vBarrel[2]); } else { - gi.MSG_StartCGM(CGM_BULLET_2); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_2)); } gi.MSG_WriteCoord(start[0]); @@ -2463,7 +2463,7 @@ float BulletAttack( } } else { if (iTracerCount) { - gi.MSG_StartCGM(CGM_BULLET_3); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_3)); gi.MSG_WriteCoord(vBarrel[0]); gi.MSG_WriteCoord(vBarrel[1]); @@ -2475,7 +2475,7 @@ float BulletAttack( gi.MSG_WriteBits(Q_min(iTracerCount, 63), 6); } else { - gi.MSG_StartCGM(CGM_BULLET_4); + gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_4)); } gi.MSG_WriteCoord(start[0]); From 3e190ca4b37ea726331bd283059d270bb69f0b0e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 00:02:28 +0100 Subject: [PATCH 0132/2040] Added MASK_SHOT_FLUID (there are so many masks) --- code/fgame/bg_public.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 5822dd99..091508b7 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -630,6 +630,9 @@ movement on the server game. #define MASK_SHOT_TRIG \ (CONTENTS_SOLID | CONTENTS_CLAYPIDGEON | CONTENTS_WATER | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 \ | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY | CONTENTS_TRIGGER) +#define MASK_SHOT_FLUID \ + (CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_FENCE \ + | CONTENTS_WEAPONCLIP | CONTENTS_SHOOTONLY | CONTENTS_BODY | CONTENTS_TRIGGER) #define MASK_PROJECTILE \ (CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_TRIGGER | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_UNKNOWN2 \ | CONTENTS_NOBOTCLIP | CONTENTS_BBOX) From b95b8c4c205e894197741668b421310a7ad30d9e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 00:17:30 +0100 Subject: [PATCH 0133/2040] Fixed water bullet effect --- code/cgame/cg_parsemsg.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/code/cgame/cg_parsemsg.cpp b/code/cgame/cg_parsemsg.cpp index 12fc0e4d..7b86d14e 100644 --- a/code/cgame/cg_parsemsg.cpp +++ b/code/cgame/cg_parsemsg.cpp @@ -160,49 +160,49 @@ static void CG_MakeBulletHoleType( float fVolume; switch (iEffectNum) { - case 0: + case SFX_BHIT_PAPER_LITE: sBulletHole += "paper"; break; - case 2: + case SFX_BHIT_WOOD_LITE: sBulletHole += "wood"; break; - case 4: + case SFX_BHIT_METAL_LITE: sBulletHole += "metal"; break; - case 6: + case SFX_BHIT_STONE_LITE: sBulletHole += "stone"; break; - case 8: + case SFX_BHIT_DIRT_LITE: sBulletHole += "dirt"; break; - case 10: + case SFX_BHIT_GRILL_LITE: sBulletHole += "grill"; break; - case 12: + case SFX_BHIT_GRASS_LITE: sBulletHole += "grass"; break; - case 14: + case SFX_BHIT_MUD_LITE: sBulletHole += "mud"; break; - case 16: + case SFX_BHIT_PUDDLE_LITE: sBulletHole += "puddle"; break; - case 18: + case SFX_BHIT_GLASS_LITE: sBulletHole += "glass"; break; - case 20: + case SFX_BHIT_GRAVEL_LITE: sBulletHole += "gravel"; break; - case 22: + case SFX_BHIT_SAND_LITE: sBulletHole += "sand"; break; - case 24: + case SFX_BHIT_FOLIAGE_LITE: sBulletHole += "foliage"; break; - case 26: + case SFX_BHIT_SNOW_LITE: sBulletHole += "snow"; break; - case 28: + case SFX_BHIT_CARPET_LITE: sBulletHole += "carpet"; break; default: @@ -366,7 +366,7 @@ static void CG_MakeBubbleTrail(const vec3_t i_vStart, const vec3_t i_vEnd, int i fDist -= fMove; while (fDist > 0.f) { VectorMA(vPos, fMove, vDir, vPos); - sfxManager.MakeEffect_Angles(32, vPos, vec_zero); + sfxManager.MakeEffect_Angles(SFX_WATER_TRAIL_BUBBLE, vPos, vec_zero); fMove = 16.f + crandom() * 8.f * alpha; fDist -= fMove; @@ -535,7 +535,7 @@ static void CG_MakeBulletTracerInternal( while (trace.fraction < 1) { if (bIgnoreEntities) { - cgi.CM_BoxTrace(&trace, vTraceStart, vTraceEnd, vec_zero, vec_zero, 0, MASK_SHOT, qfalse); + cgi.CM_BoxTrace(&trace, vTraceStart, vTraceEnd, vec_zero, vec_zero, 0, MASK_SHOT_FLUID, qfalse); if (trace.fraction == 1.0f) { trace.entityNum = ENTITYNUM_NONE; @@ -564,11 +564,11 @@ static void CG_MakeBulletTracerInternal( if (trace.contents & CONTENTS_FLUID) { fDist = DotProduct(vDir, trace.plane.normal) * -2.0f; VectorMA(vDir, fDist, trace.plane.normal, vTmp); - VectorAdd(vTmp, vTmp, trace.plane.normal); + VectorMA(trace.plane.normal, 2.0, vTmp, trace.plane.normal); VectorNormalizeFast(trace.plane.normal); } - if (!bInWater && trace.fraction < 1.0f && iNumImpacts <= 127) { + if (!bInWater && trace.fraction < 1.0f && iNumImpacts < ARRAY_LEN(tImpacts)) { memcpy(&tImpacts[iNumImpacts], &trace, sizeof(trace_t)); iNumImpacts++; } From 5cc599984d50b0bdcec136214bddedadaebfe1ec Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 00:18:18 +0100 Subject: [PATCH 0134/2040] Fixed bullet hit effect for glass --- code/cgame/cg_parsemsg.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/cgame/cg_parsemsg.cpp b/code/cgame/cg_parsemsg.cpp index 7b86d14e..966b041d 100644 --- a/code/cgame/cg_parsemsg.cpp +++ b/code/cgame/cg_parsemsg.cpp @@ -283,7 +283,7 @@ CG_MakeBulletHole(const vec3_t i_vPos, const vec3_t i_vNorm, int iLarge, trace_t break; case SURF_GLASS: sBulletHole += "glass"; - iEffect = SFX_BHIT_GRASS_LITE; + iEffect = SFX_BHIT_GLASS_LITE; break; case SURF_GRAVEL: fRadius = 0.f; @@ -554,7 +554,7 @@ static void CG_MakeBulletTracerInternal( vec_zero, vTraceStart, ENTITYNUM_NONE, - MASK_SHOT, + MASK_SHOT_FLUID, qfalse, qfalse, "CG_MakeBulletTracerInternal" From dd8b3f607a6a8d7d40dad66b4984b4d58cce7b29 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:36:56 +0100 Subject: [PATCH 0135/2040] Fixed terrain tri sphere collision not returning correct results with small objects --- code/qcommon/cm_terrain.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 2babe2aa..9aa58ff9 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -612,9 +612,9 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) bFitsDiag = qtrue; } iX[0] = 1; - iX[1] = 1; + iX[1] = 0; iX[2] = 1; - iY[0] = 0; + iY[0] = 1; iY[1] = 1; iY[2] = 0; break; @@ -637,9 +637,9 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) } iX[0] = 0; iX[1] = 1; - iX[2] = 1; + iX[2] = 0; iY[0] = 1; - iY[1] = 0; + iY[1] = 1; iY[2] = 0; break; case 5: @@ -661,9 +661,9 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) } iX[0] = 1; iX[1] = 0; - iX[2] = 0; + iX[2] = 1; iY[0] = 0; - iY[1] = 1; + iY[1] = 0; iY[2] = 1; break; case 6: @@ -684,9 +684,9 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) bFitsDiag = qtrue; } iX[0] = 0; - iX[1] = 0; + iX[1] = 1; iX[2] = 0; - iY[0] = 1; + iY[0] = 0; iY[1] = 0; iY[2] = 1; break; @@ -699,22 +699,22 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) if (bFitsDiag) { return fSpherePlane; } else { - return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iY[0], iX[1], iY[1], iY[2]); + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[1], iY[1], iX[2], iY[2]); } } else if (bFitsDiag) { - return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iX[2], iY[0], iX[1]); + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iY[0], iX[1], iY[1]); } else { - return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iY[0], iX[1]); + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[1], iY[1]); } } else if (bFitsY) { if (bFitsDiag) { - return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iX[2], iY[1], iY[2]); + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iY[0], iX[2], iY[2]); } else { - return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iY[1], iY[2]); + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[2], iY[2]); } } else { if (bFitsDiag) { - return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[0], iX[2]); + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[0], iY[0]); } else { return g_trace.tw->trace.fraction; } From c40d073d7a678eb1af899a56c631c98373057c8c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:39:13 +0100 Subject: [PATCH 0136/2040] Refactored CM_CheckTerrainTriSphere --- code/qcommon/cm_terrain.c | 112 ++++++++++++-------------------------- 1 file changed, 35 insertions(+), 77 deletions(-) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 9aa58ff9..042b0ac9 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -595,22 +595,10 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) switch (eMode) { case 3: - if (d1 > 64) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if (d2 > 64) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + bFitsX = d1 <= 64; + bFitsY = d2 <= 64; + bFitsDiag = d1 >= 64 - d2; - if (d1 < 64 - d2) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } iX[0] = 1; iX[1] = 0; iX[2] = 1; @@ -619,22 +607,10 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) iY[2] = 0; break; case 4: - if (d1 < 0) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if (d2 > 64) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + bFitsX = d1 >= 0; + bFitsY = d2 <= 64; + bFitsDiag = d1 <= d2; - if (d1 > d2) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } iX[0] = 0; iX[1] = 1; iX[2] = 0; @@ -643,22 +619,10 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) iY[2] = 0; break; case 5: - if (d1 > 64) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if (d2 < 0) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + bFitsX = d1 <= 64; + bFitsY = d2 >= 0; + bFitsDiag = d1 >= d2; - if (d1 < d2) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } iX[0] = 1; iX[1] = 0; iX[2] = 1; @@ -667,22 +631,10 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) iY[2] = 1; break; case 6: - if (d1 < 0) { - bFitsX = qfalse; - } else { - bFitsX = qtrue; - } - if (d2 < 0) { - bFitsY = qfalse; - } else { - bFitsY = qtrue; - } + bFitsX = d1 >= 0; + bFitsY = d2 >= 0; + bFitsDiag = d1 <= 64 - d2; - if (d1 > 64 - d2) { - bFitsDiag = qfalse; - } else { - bFitsDiag = qtrue; - } iX[0] = 0; iX[1] = 1; iX[2] = 0; @@ -694,31 +646,37 @@ float CM_CheckTerrainTriSphere(float x0, float y0, int iPlane) return 0; } - if (bFitsX) { - if (bFitsY) { - if (bFitsDiag) { - return fSpherePlane; - } else { - return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[1], iY[1], iX[2], iY[2]); - } - } else if (bFitsDiag) { - return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iY[0], iX[1], iY[1]); - } else { - return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[1], iY[1]); + if (bFitsX && bFitsY) { + if (bFitsDiag) { + return fSpherePlane; } - } else if (bFitsY) { + + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[1], iY[1], iX[2], iY[2]); + } + + if (bFitsX && !bFitsY) { + if (bFitsDiag) { + return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iY[0], iX[1], iY[1]); + } + + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[1], iY[1]); + } + + if (!bFitsX && bFitsY) { if (bFitsDiag) { return CM_CheckTerrainTriSphereEdge(plane, x0, y0, iX[0], iY[0], iX[2], iY[2]); - } else { - return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[2], iY[2]); } - } else { + + return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[2], iY[2]); + } + + if (!bFitsX && !bFitsY) { if (bFitsDiag) { return CM_CheckTerrainTriSphereCorner(plane, x0, y0, iX[0], iY[0]); - } else { - return g_trace.tw->trace.fraction; } } + + return g_trace.tw->trace.fraction; } /* From b0e597cf55d2ceed0d60b9eb8346cda247ff43fd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 15:02:49 +0100 Subject: [PATCH 0137/2040] Fixed vehicle collision orientation --- code/fgame/vehicleturret.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/vehicleturret.cpp b/code/fgame/vehicleturret.cpp index 7ed211fd..aae7c987 100644 --- a/code/fgame/vehicleturret.cpp +++ b/code/fgame/vehicleturret.cpp @@ -1502,7 +1502,7 @@ void VehicleTurretGun::UpdateCollisionEntity() vec3_t axis[3]; vec3_t mat[3]; - AnglesToAxis(m_vLocalAngles, mat); + AnglesToAxis(m_vLocalAngles, axis); MatrixMultiply(axis, m_mBaseOrientation, mat); MatrixToEulerAngles(mat, newAngles); } else { From 7a1f7773bfdf9a099ca95c33afa7546ea4b93a58 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 15:05:33 +0100 Subject: [PATCH 0138/2040] Use sin/cos instead of sinf/cosf (accuracy) --- code/qcommon/q_math.c | 118 +++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index f21b52fe..a09fc656 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -650,10 +650,10 @@ void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; rad = DEG2RAD( degrees ); - zrot[0][0] = cosf( rad ); - zrot[0][1] = sinf( rad ); - zrot[1][0] = -sinf( rad ); - zrot[1][1] = cosf( rad ); + zrot[0][0] = cos( rad ); + zrot[0][1] = sin( rad ); + zrot[1][0] = -sin( rad ); + zrot[1][1] = cos( rad ); Matrix3x3Multiply( m, zrot, tmpmat ); Matrix3x3Multiply( tmpmat, im, rot ); @@ -768,14 +768,14 @@ void AnglesToAxis( const vec3_t angles, vec3_t axis[3] ) { // static to help MS compiler fp bugs angle = angles[ YAW ] * ( M_PI * 2 / 360 ); - sy = sinf( angle ); - cy = cosf( angle ); + sy = sin( angle ); + cy = cos( angle ); angle = angles[ PITCH ] * ( M_PI * 2 / 360 ); - sp = sinf( angle ); - cp = cosf( angle ); + sp = sin( angle ); + cp = cos( angle ); angle = angles[ ROLL ] * ( M_PI * 2 / 360 ); - sr = sinf( angle ); - cr = cosf( angle ); + sr = sin( angle ); + cr = cos( angle ); axis[ 0 ][ 0 ] = cp*cy; axis[ 0 ][ 1 ] = cp*sy; @@ -903,7 +903,7 @@ the msvc acos doesn't always return a value between -PI and PI: int i; i = 1065353246; -acosf(*(float*) &i) == -1.#IND0 +acos(*(float*) &i) == -1.#IND0 This should go in q_math but it is too late to add new traps to game and ui @@ -912,7 +912,7 @@ acosf(*(float*) &i) == -1.#IND0 float Q_acos(float c) { float angle; - angle = acosf(c); + angle = acos(c); if (angle > M_PI) { return (float)M_PI; @@ -2051,14 +2051,14 @@ void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up // static to help MS compiler fp bugs angle = angles[ YAW ] * ( M_PI * 2 / 360 ); - sy = sinf( angle ); - cy = cosf( angle ); + sy = sin( angle ); + cy = cos( angle ); angle = angles[ PITCH ] * ( M_PI * 2 / 360 ); - sp = sinf( angle ); - cp = cosf( angle ); + sp = sin( angle ); + cp = cos( angle ); angle = angles[ ROLL ] * ( M_PI * 2 / 360 ); - sr = sinf( angle ); - cr = cosf( angle ); + sr = sin( angle ); + cr = cos( angle ); if( forward ) { @@ -2087,11 +2087,11 @@ void AngleVectorsLeft( const vec3_t angles, vec3_t forward, vec3_t left, vec3_t // static to help MS compiler fp bugs angle = angles[ YAW ] * ( M_PI * 2 / 360 ); - sy = sinf( angle ); - cy = cosf( angle ); + sy = sin( angle ); + cy = cos( angle ); angle = angles[ PITCH ] * ( M_PI * 2 / 360 ); - sp = sinf( angle ); - cp = cosf( angle ); + sp = sin( angle ); + cp = cos( angle ); if( forward ) { @@ -2103,8 +2103,8 @@ void AngleVectorsLeft( const vec3_t angles, vec3_t forward, vec3_t left, vec3_t if( left || up ) { angle = angles[ ROLL ] * ( M_PI * 2 / 360 ); - sr = sinf( angle ); - cr = cosf( angle ); + sr = sin( angle ); + cr = cos( angle ); if( left ) { @@ -2717,8 +2717,8 @@ void MatrixSetupXRotation(matrix_t m, vec_t degrees) vec_t a = DEG2RAD(degrees); m[ 0] = 1; m[ 4] = 0; m[ 8] = 0; m[12] = 0; - m[ 1] = 0; m[ 5] = cosf(a); m[ 9] =-sinf(a); m[13] = 0; - m[ 2] = 0; m[ 6] = sinf(a); m[10] = cosf(a); m[14] = 0; + m[ 1] = 0; m[ 5] = cos(a); m[ 9] =-sin(a); m[13] = 0; + m[ 2] = 0; m[ 6] = sin(a); m[10] = cos(a); m[14] = 0; m[ 3] = 0; m[ 7] = 0; m[11] = 0; m[15] = 1; } @@ -2726,9 +2726,9 @@ void MatrixSetupYRotation(matrix_t m, vec_t degrees) { vec_t a = DEG2RAD(degrees); - m[ 0] = cosf(a); m[ 4] = 0; m[ 8] = sinf(a); m[12] = 0; + m[ 0] = cos(a); m[ 4] = 0; m[ 8] = sin(a); m[12] = 0; m[ 1] = 0; m[ 5] = 1; m[ 9] = 0; m[13] = 0; - m[ 2] =-sinf(a); m[ 6] = 0; m[10] = cosf(a); m[14] = 0; + m[ 2] =-sin(a); m[ 6] = 0; m[10] = cos(a); m[14] = 0; m[ 3] = 0; m[ 7] = 0; m[11] = 0; m[15] = 1; } @@ -2736,8 +2736,8 @@ void MatrixSetupZRotation(matrix_t m, vec_t degrees) { vec_t a = DEG2RAD(degrees); - m[ 0] = cosf(a); m[ 4] =-sinf(a); m[ 8] = 0; m[12] = 0; - m[ 1] = sinf(a); m[ 5] = cosf(a); m[ 9] = 0; m[13] = 0; + m[ 0] = cos(a); m[ 4] =-sin(a); m[ 8] = 0; m[12] = 0; + m[ 1] = sin(a); m[ 5] = cos(a); m[ 9] = 0; m[13] = 0; m[ 2] = 0; m[ 6] = 0; m[10] = 1; m[14] = 0; m[ 3] = 0; m[ 7] = 0; m[11] = 0; m[15] = 1; } @@ -2939,8 +2939,8 @@ void MatrixToAngles(const matrix_t m, vec3_t angles) sp = -1.0; } - theta = -asinf(sp); - cp = cosf(theta); + theta = -asin(sp); + cp = cos(theta); if(cp > 8192 * FLT_EPSILON) { @@ -2958,8 +2958,8 @@ void MatrixToAngles(const matrix_t m, vec3_t angles) double a; double ca; - a = asinf(-m[2]); - ca = cosf(a); + a = asin(-m[2]); + ca = cos(a); if(fabs(ca) > 0.005) // Gimbal lock? { @@ -2983,14 +2983,14 @@ void MatrixFromAngles(matrix_t m, vec_t pitch, vec_t yaw, vec_t roll) static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs - sp = sinf(DEG2RAD(pitch)); - cp = cosf(DEG2RAD(pitch)); + sp = sin(DEG2RAD(pitch)); + cp = cos(DEG2RAD(pitch)); - sy = sinf(DEG2RAD(yaw)); - cy = cosf(DEG2RAD(yaw)); + sy = sin(DEG2RAD(yaw)); + cy = cos(DEG2RAD(yaw)); - sr = sinf(DEG2RAD(roll)); - cr = cosf(DEG2RAD(roll)); + sr = sin(DEG2RAD(roll)); + cr = cos(DEG2RAD(roll)); m[ 0] = cp*cy; m[ 4] = (sr*sp*cy+cr*-sy); m[ 8] = (cr*sp*cy+-sr*-sy); m[12] = 0; m[ 1] = cp*sy; m[ 5] = (sr*sp*sy+cr*cy); m[ 9] = (cr*sp*sy+-sr*cy); m[13] = 0; @@ -3663,14 +3663,14 @@ void QuatFromAngles(quat_t q, vec_t pitch, vec_t yaw, vec_t roll) static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs - sp = sinf(DEG2RAD(pitch)); - cp = cosf(DEG2RAD(pitch)); + sp = sin(DEG2RAD(pitch)); + cp = cos(DEG2RAD(pitch)); - sy = sinf(DEG2RAD(yaw)); - cy = cosf(DEG2RAD(yaw)); + sy = sin(DEG2RAD(yaw)); + cy = cos(DEG2RAD(yaw)); - sr = sinf(DEG2RAD(roll)); - cr = cosf(DEG2RAD(roll)); + sr = sin(DEG2RAD(roll)); + cr = cos(DEG2RAD(roll)); q[0] = sr * cp * cy - cr * sp * sy; // x q[1] = cr * sp * cy + sr * cp * sy; // y @@ -3818,19 +3818,19 @@ void QuatToRotAngle( const quat_t q, vec_t *angle ) { void QuatToRotAngleAxis( const quat_t q, vec_t *angle, vec3_t axis ) { *angle = atan( VectorLength(q)/q[3] ); - axis[0] = q[0] / sinf(*angle); - axis[1] = q[1] / sinf(*angle); - axis[2] = q[2] / sinf(*angle); + axis[0] = q[0] / sin(*angle); + axis[1] = q[1] / sin(*angle); + axis[2] = q[2] / sin(*angle); *angle *= 360.0f / M_PI; } void QuatFromRotAngleAxis( quat_t q, vec_t angle, const vec3_t axis ) { - q[0] = axis[0] * sinf( angle*M_PI/360 ); - q[1] = axis[1] * sinf( angle*M_PI/360 ); - q[2] = axis[2] * sinf( angle*M_PI/360 ); - q[3] = cosf( angle*M_PI/360 ); + q[0] = axis[0] * sin( angle*M_PI/360 ); + q[1] = axis[1] * sin( angle*M_PI/360 ); + q[2] = axis[2] * sin( angle*M_PI/360 ); + q[3] = cos( angle*M_PI/360 ); } void QuatToAngles( const quat_t q, vec3_t angles ) @@ -3842,7 +3842,7 @@ void QuatToAngles( const quat_t q, vec3_t angles ) q2[ 2 ] = q[ 2 ] * q[ 2 ]; q2[ 3 ] = q[ 3 ] * q[ 3 ]; - angles[ PITCH ] = RAD2DEG( asinf( -2 * ( q[ 2 ] * q[ 0 ] - q[ 3 ] * q[ 1 ] ) ) ); + angles[ PITCH ] = RAD2DEG( asin( -2 * ( q[ 2 ] * q[ 0 ] - q[ 3 ] * q[ 1 ] ) ) ); angles[ YAW ] = RAD2DEG( atan2( 2 * ( q[ 2 ] * q[ 3 ] + q[ 0 ] * q[ 1 ] ), ( q2[ 2 ] - q2[ 3 ] - q2[ 0 ] + q2[ 1 ] ) ) ); angles[ ROLL ] = RAD2DEG( atan2( 2 * ( q[ 3 ] * q[ 0 ] + q[ 2 ] * q[ 1 ] ), ( -q2[ 2 ] - q2[ 3 ] + q2[ 0 ] + q2[ 1 ] ) ) ); } @@ -3869,7 +3869,7 @@ void QuatToAngles( const quat_t q, vec3_t angles ) } else { - angles[ PITCH ] = asinf( 2.f*( SingularityTest ) ) * RAD_TO_DEG; + angles[ PITCH ] = asin( 2.f*( SingularityTest ) ) * RAD_TO_DEG; angles[ YAW ] = atan2( YawY, YawX ) * RAD_TO_DEG; angles[ ROLL ] = atan2( -2.f*( q[W]*q[X] + q[Y]*q[Z] ), ( 1.f - 2.f*( Square( q[X] ) + Square( q[Y] ) ) ) ) * RAD_TO_DEG; } @@ -4006,8 +4006,8 @@ void QuatSlerp(const quat_t from, const quat_t to, float frac, quat_t out) sinom = 1.0f / sqrtf(sinSqr); omega = atan2f(sinSqr * sinom, absCosom); - scale0 = sinf((1.0f - frac) * omega) * sinom; - scale1 = sinf(frac * omega) * sinom; + scale0 = sin((1.0f - frac) * omega) * sinom; + scale1 = sin(frac * omega) * sinom; } else { @@ -4054,8 +4054,8 @@ void MatrixToEulerAngles sp = -1.0; } - theta = -asinf( sp ); - cp = cosf( theta ); + theta = -asin( sp ); + cp = cos( theta ); if( cp > 8192 * FLT_EPSILON ) { From 5a0aeb2f88a3b0b3fc18c423991b586fce345326 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 15:12:55 +0100 Subject: [PATCH 0139/2040] Fixed last fire time being incorrectly set in the future --- code/fgame/vehicleturret.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/vehicleturret.cpp b/code/fgame/vehicleturret.cpp index aae7c987..674e95a6 100644 --- a/code/fgame/vehicleturret.cpp +++ b/code/fgame/vehicleturret.cpp @@ -949,7 +949,7 @@ void VehicleTurretGun::UpdateOwner(Sentient *pOwner) void VehicleTurretGun::TurretHasBeenMounted() { - m_fLastFireTime = level.time + m_fWarmupDelay + fire_delay[FIRE_PRIMARY]; + m_fLastFireTime = (level.time + m_fWarmupDelay) - fire_delay[FIRE_PRIMARY]; if (m_fWarmupDelay > 0.25) { Sound(m_sSoundSet + "snd_warmup"); } From 1577927d99c0f723899db133d7f3520c373b67df Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:48:58 +0100 Subject: [PATCH 0140/2040] Ignore collision if the brush has a trace content and the trace content wasn't specified in the trace flags --- code/qcommon/cm_trace.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/qcommon/cm_trace.c b/code/qcommon/cm_trace.c index 10460b29..7122f200 100644 --- a/code/qcommon/cm_trace.c +++ b/code/qcommon/cm_trace.c @@ -677,6 +677,11 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { leaveFrac2 = 1.0; clipplane2 = NULL; leadside2 = NULL; + + if (!(tw->contents & CONTENTS_FENCE)) { + return; + } + // // compare the trace against all planes of the brush // find the latest time the trace crosses a plane towards the interior From 5cadab46abdbf9366db1741c24cccf628b52e36c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:49:27 +0100 Subject: [PATCH 0141/2040] Fixed fence mask being incorrectly specified as transparent rather than opaque --- code/qcommon/cm_fencemask.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/qcommon/cm_fencemask.c b/code/qcommon/cm_fencemask.c index eacf6aad..a32291ac 100644 --- a/code/qcommon/cm_fencemask.c +++ b/code/qcommon/cm_fencemask.c @@ -468,11 +468,11 @@ qboolean CM_GenerateFenceMask( const char *szName, cfencemask_t **pMask ) for( i = 0; i < iImageSize; i++, pCurrImage += sizeof( unsigned int ) ) { - if( *pCurrImage >= 0 ) + if( *pCurrImage & 0x80 ) { - bHasTrans = qtrue; - } else { bHasOpaque = qtrue; + } else { + bHasTrans = qtrue; } if( bHasOpaque && bHasTrans ) { From 74e8a38c00d5a7974a04131207826fc0508c528b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:59:20 +0100 Subject: [PATCH 0142/2040] When idle, limit the turret's pitch to the max idle pitch --- code/fgame/weapturret.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index 6f0d806a..0a96c220 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -573,7 +573,12 @@ void TurretGun::ThinkIdle(void) m_fIdlePitchSpeed -= level.frametime * 300.0f; - vNewAngles = Vector(angles[0] + level.frametime * m_fIdlePitchSpeed, angles[1], angles[2]); + vNewAngles = Vector( + Q_max(angles[0] + level.frametime * m_fIdlePitchSpeed, m_fMaxIdlePitch), + angles[1], + angles[2] + ); + vNewAngles.AngleVectorsLeft(&vDir); vEnd = origin + vDir * m_vIdleCheckOffset[0]; From 0591152f99ea8b9ec23ba7a7e162423e7db05ef2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 17:18:51 +0100 Subject: [PATCH 0143/2040] Added ifCvar / ifCvarnot support --- code/renderer/tr_shader.c | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index c356aebd..3a919800 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -798,6 +798,7 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) int cntBundle = 0; int depthTestBits = 0; int fogBits = 0; + qboolean shouldProcess = qtrue; stage->active = qtrue; stage->noMipMaps = shader_noMipMaps; @@ -815,6 +816,13 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) if (token[0] == '}') { + // Added in 2.0 + // Ignore vars that didn't met with 'ifCvar' / 'ifCvarnot' + if (!shouldProcess) { + stage->active = qfalse; + stage->rgbGen = CGEN_BAD; + return qtrue; + } break; } // no picmip adjustment @@ -1628,6 +1636,43 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) } continue; } + // + // Added in 2.0 + // + else if (!Q_stricmp(token, "ifCvar") || !Q_stricmp(token, "ifCvarnot")) + { + cvar_t* var; + qboolean isNot = token[6] != 0; + qboolean evaluatedValue; + + token = COM_ParseExt(text, qfalse); + if (!token[0]) { + ri.Printf(PRINT_WARNING, "WARNING: missing cvar name in %s", isNot ? "ifCvarnot" : "ifCvar"); + return qfalse; + } + + var = ri.Cvar_Get(token, "0", 0); + + token = COM_ParseExt(text, qfalse); + if (!token[0]) { + ri.Printf(PRINT_WARNING, "WARNING: missing cvar value in %s", isNot ? "ifCvarnot" : "ifCvar"); + return qfalse; + } + + if (atof(token) != var->value) { + evaluatedValue = qfalse; + } else if (var->value) { + evaluatedValue = qtrue; + } else if (token[0] == '0' || (token[0] == '.' && token[1] == '0')) { + evaluatedValue = qtrue; + } else if (!Q_stricmp(var->string, token)) { + evaluatedValue = qtrue; + } else { + return qfalse; + } + + shouldProcess &= evaluatedValue ^ isNot; + } else { ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); From 304645d720de15f7889215094f821fe7e0bcb415 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:50:32 +0100 Subject: [PATCH 0144/2040] Ignore CGEN_BAD stages --- code/renderer/tr_shader.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index 3a919800..019d88a2 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -2175,7 +2175,17 @@ static qboolean ParseShader( char **text ) { return qfalse; } - unfoggedStages[s].active = qtrue; + if (unfoggedStages[s].rgbGen != CGEN_BAD) { + unfoggedStages[s].active = qtrue; + if (s > 0) { + if (!(unfoggedStages[s].stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS))) { + ri.Printf(PRINT_WARNING, "WARNING: shader '%s' has opaque maps defined after stage 0!!!\n", shader.name); + } + if (unfoggedStages[s].stateBits & GLS_DEPTHMASK_TRUE) { + ri.Printf(PRINT_WARNING, "WARNING: shader '%s' has depthmask enabled after stage 0!!!\n", shader.name); + } + } + } s++; continue; } From d5be69239a02fea0a867e94375f14d4b7b501306 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:18:52 +0100 Subject: [PATCH 0145/2040] Added GL 1.3 functions --- code/renderer/tr_local.h | 1 + code/sdl/sdl_glimp.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index d99f8b6d..eb782eb5 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA QGL_1_1_PROCS; QGL_1_1_FIXED_FUNCTION_PROCS; +QGL_1_3_PROCS; QGL_DESKTOP_1_1_PROCS; QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS; QGL_3_0_PROCS; diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index 30986ab1..528f3a06 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -293,6 +293,9 @@ static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) { } else { Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 1.1 is required", version ); } + if ( QGL_VERSION_ATLEAST( 1, 3 ) ) { + QGL_1_3_PROCS; + } } else { if ( QGL_VERSION_ATLEAST( 2, 0 ) ) { QGL_1_1_PROCS; From 5475624b7fbea132acb075fb4eb38b27e423641f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:19:33 +0100 Subject: [PATCH 0146/2040] Added DDS support + handle compressed textures correctly --- code/renderer/tr_image.c | 245 ++++++++++++++++++++------------------- 1 file changed, 127 insertions(+), 118 deletions(-) diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 3333e12c..350e6835 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -519,7 +519,8 @@ static void Upload32( scaled_height >>= 1; } - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); + //scaledBuffer = ri.Hunk_AllocateTempMemory( 4 * scaled_width * scaled_height ); + scaledBuffer = data; // // scan the texture for each channel's max values @@ -622,10 +623,11 @@ static void Upload32( *pUploadWidth = scaled_width; *pUploadHeight = scaled_height; *format = internalFormat; + *bytesUsed = samples * scaled_width * scaled_height; goto done; } - Com_Memcpy (scaledBuffer, data, width*height*4); + //Com_Memcpy (scaledBuffer, data, width*height*4); } else { @@ -641,7 +643,7 @@ static void Upload32( height = 1; } } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); + //Com_Memcpy( scaledBuffer, data, width * height * 4 ); } R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !numMipmaps); @@ -652,6 +654,8 @@ static void Upload32( qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + *bytesUsed = samples * scaled_width * scaled_height; + if (numMipmaps) { int miplevel; @@ -697,13 +701,12 @@ done: GL_CheckErrors(); - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); + //if ( scaledBuffer != 0 ) + // ri.Hunk_FreeTempMemory( scaledBuffer ); if ( resampledBuffer != 0 ) ri.Hunk_FreeTempMemory( resampledBuffer ); } -/* static void UploadCompressed( byte* data, int width, @@ -813,7 +816,7 @@ static void UploadCompressed( size = blockSize * w * h; if (w > 1 && h > 1) *pBytesUsed += size; - qglCompressedTexImage2DARB(3553, i - iStartImage, glCompressMode, scaled_width, scaled_height, 0, size, data); + qglCompressedTexImage2D(GL_TEXTURE_2D, i - iStartImage, glCompressMode, scaled_width, scaled_height, 0, size, data); GL_CheckErrors(); if (i < iMipmapsAvailable) @@ -858,7 +861,6 @@ static void UploadCompressed( GL_CheckErrors(); } -*/ /* ================ @@ -943,21 +945,38 @@ image_t* R_CreateImage( GL_Bind(image); - Upload32( - (unsigned*)pic, - image->width, - image->height, - image->numMipmaps, - allowPicmip, - image->dynamicallyUpdated, - force32bit, - hasAlpha, - &image->internalFormat, - &image->uploadWidth, - &image->uploadHeight, - &image->bytesUsed, - isLightmap - ); + if (glCompressMode) { + UploadCompressed( + (unsigned*)pic, + image->width, + image->height, + image->numMipmaps, + iMipmapsAvailable, + allowPicmip, + glCompressMode, + &image->internalFormat, + &image->uploadWidth, + &image->uploadHeight, + &image->bytesUsed + ); + } + else { + Upload32( + (unsigned*)pic, + image->width, + image->height, + image->numMipmaps, + allowPicmip, + image->dynamicallyUpdated, + force32bit, + hasAlpha, + &image->internalFormat, + &image->uploadWidth, + &image->uploadHeight, + &image->bytesUsed, + isLightmap + ); + } qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampModeX ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampModeY ); @@ -1488,16 +1507,19 @@ typedef enum DXGI_FORMAT { static void LoadDDS(const char* name, byte** pic, int* width, int* height, qboolean* hasAlpha, int* glCompressMode, int* numMipmaps, int* piMipmapsAvailable) { - union { - byte* b; - void* v; - } buffer; int len; - ddsHeader_t* ddsHeader = NULL; + unsigned int signature; + ddsHeader_t ddsHeader; ddsHeaderDxt10_t* ddsHeaderDxt10 = NULL; + fileHandle_t handle; byte* data; + int w, h; + int minWidth, minHeight; + int numMips = 0; + int size; + int intSize; - *pic = 0; + *pic = NULL; *piMipmapsAvailable = 0; if (width) @@ -1505,126 +1527,113 @@ static void LoadDDS(const char* name, byte** pic, int* width, int* height, qbool if (height) *height = 0; - *pic = NULL; - // // load the file // - len = ri.FS_ReadFile((char*)name, &buffer.v); - if (!buffer.b || len < 0) { + len = ri.FS_OpenFile((char*)name, &handle, qtrue, qtrue); + if (len < 0) { return; } // // reject files that are too small to hold even a header // - if (len < 4 + sizeof(*ddsHeader)) + if (len < 4 + sizeof(ddsHeader)) { ri.Printf(PRINT_ALL, "File %s is too small to be a DDS file.\n", name); - ri.FS_FreeFile(buffer.v); + ri.FS_CloseFile(handle); return; } // // reject files that don't start with "DDS " // - if (*((ui32_t*)(buffer.b)) != EncodeFourCC("DDS ")) + ri.FS_Read(&signature, sizeof(signature), handle); + if (signature != EncodeFourCC("DDS ")) { ri.Printf(PRINT_ALL, "File %s is not a DDS file.\n", name); - ri.FS_FreeFile(buffer.v); + ri.FS_CloseFile(handle); return; } - // - // parse header and dx10 header if available - // - ddsHeader = (ddsHeader_t*)(buffer.b + 4); - if ((ddsHeader->pixelFormatFlags & DDSPF_FOURCC) && ddsHeader->fourCC == EncodeFourCC("DX10")) - { - if (len < 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10)) - { - ri.Printf(PRINT_ALL, "File %s indicates a DX10 header it is too small to contain.\n", name); - ri.FS_FreeFile(buffer.v); - return; - } - - ddsHeaderDxt10 = (ddsHeaderDxt10_t*)(buffer.b + 4 + sizeof(ddsHeader_t)); - data = buffer.b + 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10); - len -= 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10); - } - else - { - data = buffer.b + 4 + sizeof(*ddsHeader); - len -= 4 + sizeof(*ddsHeader); - } - - if (width) - *width = ddsHeader->width; - if (height) - *height = ddsHeader->height; - - if (piMipmapsAvailable) - { - if (ddsHeader->flags & _DDSFLAGS_MIPMAPCOUNT) - *piMipmapsAvailable = ddsHeader->numMips; - else - *piMipmapsAvailable = 1; - } - - // FIXME: handle cube map - //if ((ddsHeader->caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP) + ri.FS_Read(&ddsHeader, sizeof(ddsHeader), handle); // // Convert DXGI format/FourCC into OpenGL format // - if (ddsHeaderDxt10) - { - ri.Printf(PRINT_ALL, "DDS File %s has unsupported DXGI format %d.", name, ddsHeaderDxt10->dxgiFormat); - ri.FS_FreeFile(buffer.v); + if (ddsHeader.fourCC == EncodeFourCC("DXT1")) { + intSize = 2; + *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } else if (ddsHeader.fourCC == EncodeFourCC("DXT2")) { + intSize = 4; + *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + } else if (ddsHeader.fourCC == EncodeFourCC("DXT3")) { + intSize = 4; + *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + } else if (ddsHeader.fourCC == EncodeFourCC("DXT4")) { + intSize = 4; + *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } else if (ddsHeader.fourCC == EncodeFourCC("DXT5")) { + intSize = 4; + *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } else { + ri.FS_CloseFile(handle); return; } - else - { - if (ddsHeader->pixelFormatFlags & DDSPF_FOURCC) - { - if (ddsHeader->fourCC == EncodeFourCC("DXT1")) - *glCompressMode = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - else if (ddsHeader->fourCC == EncodeFourCC("DXT2")) - *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - else if (ddsHeader->fourCC == EncodeFourCC("DXT3")) - *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - else if (ddsHeader->fourCC == EncodeFourCC("DXT4")) - *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - else if (ddsHeader->fourCC == EncodeFourCC("DXT5")) - *glCompressMode = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - else - { - ri.Printf(PRINT_ALL, "DDS File %s has unsupported FourCC.", name); - ri.FS_FreeFile(buffer.v); - return; - } - } - else if (ddsHeader->pixelFormatFlags == (DDSPF_RGB | DDSPF_ALPHAPIXELS) - && ddsHeader->rgbBitCount == 32 - && ddsHeader->rBitMask == 0x000000ff - && ddsHeader->gBitMask == 0x0000ff00 - && ddsHeader->bBitMask == 0x00ff0000 - && ddsHeader->aBitMask == 0xff000000) - { - *glCompressMode = GL_RGBA8; - } - else - { - ri.Printf(PRINT_ALL, "DDS File %s has unsupported RGBA format.", name); - ri.FS_FreeFile(buffer.v); - return; + + minWidth = ddsHeader.width; + for (w = 1; w < ddsHeader.width; w *= 2) {} + + minHeight = ddsHeader.height; + for (h = 1; h < ddsHeader.height; h *= 2) {} + + if (w != ddsHeader.width || h != ddsHeader.height) { + ri.FS_CloseFile(handle); + if (w == ddsHeader.width) { + ri.Printf(PRINT_DEVELOPER, "LoadDDS: Image %s - height not a power of 2\n", name); + } else if (h == ddsHeader.height) { + ri.Printf(PRINT_DEVELOPER, "LoadDDS: Image %s - width not a power of 2\n", name); + } else { + ri.Printf(PRINT_DEVELOPER, "LoadDDS: Image %s - width and height not a powers of 2\n", name); } + + return; } - *pic = ri.Malloc(len); - Com_Memcpy(*pic, data, len); + // + // Parse width and height + // + if (!minWidth) { + minWidth = 1; + } + *width = minWidth; - ri.FS_FreeFile(buffer.v); + if (!minHeight) { + minHeight = 1; + } + *height = minHeight; + + *hasAlpha = ddsHeader.fourCC != EncodeFourCC("DXT1"); + + numMips = ddsHeader.numMips; + if (!numMips) { + numMips = 1; + } + + *piMipmapsAvailable = numMips; + if (*numMipmaps) { + *numMipmaps = numMips; + } + + size = ddsHeader.pitchOrFirstMipSize; + if (*piMipmapsAvailable > 1) { + size = intSize * ddsHeader.pitchOrFirstMipSize; + } + + *pic = ri.Malloc(size); + ri.FS_Read(*pic, size, handle); + + ri.FS_CloseFile(handle); } /* @@ -2430,7 +2439,7 @@ static void R_LoadImage(const char* name, byte** pic, int* width, int* height, q strcpy(altname, name); len = strlen(altname); - if (glConfig.textureCompression == 1) + if (glConfig.textureCompression == TC_S3TC || glConfig.textureCompression == TC_S3TC_ARB) { len = strlen(altname); altname[len - 3] = 'd'; From 186583148a44f8ad8822c8974143c26d51153484 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 22:10:00 +0100 Subject: [PATCH 0147/2040] Use proper values for GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T --- code/renderer/tr_backend.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index eb8c0e83..433beb78 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -448,19 +448,19 @@ void GL_State( unsigned long stateBits ) if (r_forceClampToEdge->value) { if (stateBits & GLS_CLAMP_EDGE) { - clampValue = 33071.0; + clampValue = GL_CLAMP_TO_EDGE; } else { - clampValue = 10497.0; + clampValue = GL_REPEAT; } } else { if (stateBits & GLS_CLAMP_EDGE) { - clampValue = 10496.0; + clampValue = GL_CLAMP; } else { - clampValue = 10497.0; + clampValue = GL_REPEAT; } } From 3b2223ad22658a829c8c9238a1ffb588b521a04b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 22:11:00 +0100 Subject: [PATCH 0148/2040] image validity check --- code/renderer/tr_backend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 433beb78..4783749a 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -63,7 +63,9 @@ void GL_Bind( image_t *image ) { } if ( glState.currenttextures[glState.currenttmu] != texnum ) { - image->frameUsed = tr.frameCount; + if (image) { + image->frameUsed = tr.frameCount; + } glState.currenttextures[glState.currenttmu] = texnum; qglBindTexture (GL_TEXTURE_2D, texnum); } From 0b16d599d50219ee5629bfb7370dcaebfecdd562 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 22:11:15 +0100 Subject: [PATCH 0149/2040] Added UseCount for image_t --- code/renderer/tr_backend.c | 1 + code/renderer/tr_local.h | 1 + 2 files changed, 2 insertions(+) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 4783749a..373ed828 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -56,6 +56,7 @@ void GL_Bind( image_t *image ) { texnum = tr.defaultImage->texnum; } else { texnum = image->texnum; + image->UseCount++; } if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index eb782eb5..0f027be2 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -236,6 +236,7 @@ typedef struct image_s { int wrapClampModeX; int wrapClampModeY; int r_sequence; + int UseCount; struct image_s* next; } image_t; From 51ba1e295104385c9b00ad476f3cd936c855464c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Feb 2024 23:47:07 +0100 Subject: [PATCH 0150/2040] Properly use identity / identitylighting when cgen isn't explicitly specified --- code/renderer/tr_shader.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index 019d88a2..e301f4fa 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -1684,10 +1684,11 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) // if cgen isn't explicitly specified, use either identity or identitylighting // if ( stage->rgbGen == CGEN_BAD ) { - if ( (!cntBundle && !stage->bundle[0].isLightmap) || - blendSrcBits == 0 || - blendSrcBits == GLS_SRCBLEND_ONE || - blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { + if (cntBundle || stage->bundle[0].isLightmap) { + stage->rgbGen = CGEN_IDENTITY; + } else if (blendSrcBits == 0 || + blendSrcBits == GLS_SRCBLEND_ONE || + blendSrcBits == GLS_SRCBLEND_SRC_ALPHA) { stage->rgbGen = CGEN_IDENTITY_LIGHTING; } else { stage->rgbGen = CGEN_IDENTITY; @@ -1709,7 +1710,7 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) } // decide which agens we can skip - if ( stage->alphaGen == CGEN_IDENTITY ) { + if ( stage->alphaGen == AGEN_IDENTITY ) { if ( stage->rgbGen == CGEN_IDENTITY || stage->rgbGen == CGEN_LIGHTING_GRID || stage->rgbGen == CGEN_LIGHTING_SPHERICAL ) { From 7c33f98ae9ff141811f5e703d55f9aa0849330a4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:57:37 +0100 Subject: [PATCH 0151/2040] Use m_fFollowRelativeYaw --- code/fgame/scriptslave.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index f2929f18..12956162 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1504,6 +1504,14 @@ void ScriptSlave::FollowingPath(Event *ev) if (vWishAngles.length() > 0.0f) { VectorNormalize(vWishAngles); VectorToAngles(vWishAngles, vNextWishAngles); + + // + // Added in 2.0 + // Relative yaw + vNextWishAngles[1] += m_fFollowRelativeYaw; + if (m_fFollowRelativeYaw == 180) { + vNextWishAngles[0] *= -1; + } } else { AngleVectorsLeft(angles, vWishAngles, NULL, NULL); vNextWishAngles = angles; From 0ef743d945c0425461aa6019e57c57cfe2713e32 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 01:01:39 +0100 Subject: [PATCH 0152/2040] Forgot newline --- code/client/snd_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index 584f3c7a..662b02a8 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -788,7 +788,7 @@ void S_Base_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t ve // Fixed in OPM // Why should it crash??? //Com_Error( ERR_DROP, "%s has length 0", sfx->soundName ); - Com_Printf( "%s has length 0", sfx->soundName ); + Com_Printf( "%s has length 0\n", sfx->soundName ); return; } From 796a3a711fc772082e5bbfc86421038d81ffffce Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 01:01:51 +0100 Subject: [PATCH 0153/2040] Fixed animation delta over time --- code/skeletor/skeletor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 13c395d1..1654f49a 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -105,6 +105,7 @@ SkelVec3 skelAnimDataGameHeader_s::GetDeltaOverTime(float time1, float time2) if (frameNum1 < frameNum2) { delta = m_frame[frameNum1 % numFrames].delta; + VectorScale(delta, d, delta); for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) { delta += m_frame[currFrame % numFrames].delta; From 6418d79d7652917408d68d1b225190f03219b582 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:22:18 +0100 Subject: [PATCH 0154/2040] Call PostThink() in Think_Alarm() --- code/fgame/actor_alarm.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/fgame/actor_alarm.cpp b/code/fgame/actor_alarm.cpp index f485839d..57514a9e 100644 --- a/code/fgame/actor_alarm.cpp +++ b/code/fgame/actor_alarm.cpp @@ -120,6 +120,8 @@ void Actor::Think_Alarm(void) Com_Printf("Actor::Think_Alarm: invalid think state %i\n", m_State); break; } + + PostThink(true); } void Actor::FinishedAnimation_Alarm(void) From 4f5abb34126c358db2b99d49ae9f6571b45b2c27 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:22:39 +0100 Subject: [PATCH 0155/2040] Fixed int conversion when printing the awareness --- code/fgame/actorenemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actorenemy.cpp b/code/fgame/actorenemy.cpp index f339e680..5c83595f 100644 --- a/code/fgame/actorenemy.cpp +++ b/code/fgame/actorenemy.cpp @@ -389,7 +389,7 @@ void ActorEnemySet::CheckEnemies(Actor *pSelf) "ent #%3i: enemy #%i: awareness = %5.1f%%, threat = %i\n", pSelf->entnum, pActorEnemy->GetEnemy()->entnum, - (fVisibility * 100.0), + (int)(fVisibility * 100.0), 0 ); } From eb993dbd4341e240169acfcd608eb852c64e5c2a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:22:56 +0100 Subject: [PATCH 0156/2040] Fixed grenade toss location and wall facing --- code/fgame/actor.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 6a5ca672..2d7630c7 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -9823,7 +9823,7 @@ void Actor::GenericGrenadeTossThink(void) eGrenadeTossMode eGrenadeMode; if (m_Enemy && level.inttime >= m_iStateTime + 200) { - if (CanGetGrenadeFromAToB(origin, m_Enemy->velocity - m_Enemy->origin, false, &vGrenadeVel, &eGrenadeMode)) { + if (CanGetGrenadeFromAToB(origin, m_Enemy->origin + m_Enemy->velocity, false, &vGrenadeVel, &eGrenadeMode)) { m_vGrenadeVel = vGrenadeVel; m_eGrenadeMode = eGrenadeMode; } @@ -10924,15 +10924,9 @@ void Actor::DontFaceWall(void) VectorSub2D(m_vDfwPos, origin, vDelta); - if (Square(fErrorLerp * -14.0 + 16.0) > VectorLength2DSquared(vDelta)) { - if (AvoidingFacingWall()) { - SetDesiredYaw(m_fDfwDerivedYaw); - } - return; - } - - if (fabs(AngleNormalize180(m_fDfwRequestedYaw - m_DesiredYaw)) <= fErrorLerp * -29.0 + 30.0 - && fabs(AngleNormalize180(m_fDfwRequestedYaw - m_DesiredYaw)) <= fErrorLerp * -29.0 + 30.0) { + if (Square(fErrorLerp * -14.0 + 16.0) > VectorLength2DSquared(vDelta) && + (fabs(AngleNormalize180(m_fDfwRequestedYaw - m_DesiredYaw)) <= fErrorLerp * -29.0 + 30.0 + || fabs(AngleNormalize180(m_fDfwDerivedYaw - m_DesiredYaw)) <= fErrorLerp * -29.0 + 30.0)) { if (AvoidingFacingWall()) { SetDesiredYaw(m_fDfwDerivedYaw); } From 1e5e5e24f68034da0932242d9fb01016fdae772c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:23:06 +0100 Subject: [PATCH 0157/2040] Fixed entity monitoring never printing --- code/fgame/entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 904cd28a..8d6b5d92 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -5467,7 +5467,7 @@ void Entity::MPrintf(const char *fmt, ...) va_list argptr; char msg[MAXPRINTMSG]; - if (g_monitorNum->integer == entnum && g_monitor->string == targetname) { + if (g_monitorNum->integer == entnum || g_monitor->string == targetname) { va_start(argptr, fmt); Q_vsnprintf(msg, sizeof(msg), fmt, argptr); va_end(argptr); From 03ceaf82ce4f88fb138e0eb041f3c95e3b122b42 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:23:47 +0100 Subject: [PATCH 0158/2040] Fixed AngleMod() being inaccurate This caused issues with Actor never finishing turning (because it expected the desired yaw to be at the exact same angle rounded by 0.001) --- code/qcommon/q_math.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index a09fc656..1459f69a 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -1108,7 +1108,11 @@ void AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 ) { float AngleMod(float a) { - a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); + if (a >= 360) { + return a - 360 * (int)(a / 360.0); + } else if (a < 0) { + return 360 * ((int)(-a / 360) + 1) + a; + } return a; } From 0f37a8f6ea0e497c0f560ed38159d68e06c3d628 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:42:54 +0100 Subject: [PATCH 0159/2040] Fixed m_fLeashSquared initialization --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 2d7630c7..fc49017d 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -2792,7 +2792,7 @@ Actor::Actor() m_fMaxDistance = 1024; m_fMaxDistanceSquared = Square(m_fMaxDistanceSquared); m_fLeash = 512; - m_fLeashSquared = Square(m_fLeashSquared); + m_fLeashSquared = Square(m_fLeash); m_iEyeUpdateTime = level.inttime; if (m_iEyeUpdateTime < 1000) { From bc0d373dcdafcf30937905df93a1bbcf6d4b52f8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:37:28 +0100 Subject: [PATCH 0160/2040] Fixed AI getting blocked because of an obstacle --- code/fgame/actor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index fc49017d..8ac5fd17 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -5400,8 +5400,6 @@ void Actor::MovePath(float fMoveSpeed) } else { m_iWallDodgeTimeout = level.inttime + 1000; } - - GetMoveInfo(&mm); } else { if (m_WallDir >= 0) { mm.desired_dir[0] = mm.obstacle_normal[1]; @@ -5418,6 +5416,8 @@ void Actor::MovePath(float fMoveSpeed) m_iWallDodgeTimeout = 0; } } + + GetMoveInfo(&mm); } } From 45108c6f4b888243860b962d518b74896bc8e38a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:38:06 +0100 Subject: [PATCH 0161/2040] Fixed curious' finished animation global function This fixes AI being permanently stuck in a curious animation --- code/fgame/actor_curious.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor_curious.cpp b/code/fgame/actor_curious.cpp index ba1720ea..fdaab297 100644 --- a/code/fgame/actor_curious.cpp +++ b/code/fgame/actor_curious.cpp @@ -31,7 +31,7 @@ void Actor::InitCurious(GlobalFuncs_t *func) func->EndState = &Actor::End_Curious; func->ResumeState = &Actor::Resume_Curious; func->SuspendState = &Actor::Suspend_Curious; - func->FinishedAnimation = &Actor::FinishedAnimation_Cover; + func->FinishedAnimation = &Actor::FinishedAnimation_Curious; func->PassesTransitionConditions = &Actor::PassesTransitionConditions_Curious; func->IsState = &Actor::IsCuriousState; } From 5e461786f9f94521ef4038e85514e1960f394ee9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:15:54 +0100 Subject: [PATCH 0162/2040] Added a comment about FriendlyInLineOfFire --- code/fgame/actor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 8ac5fd17..c0c54567 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -3879,6 +3879,7 @@ bool Actor::CanShoot(Entity *ent) Vector vGunPos; if (FriendlyInLineOfFire(ent)) { + // This check was added in 2.0 bCanShoot = false; } else if (ent->IsSubclassOfSentient()) { Sentient *sen = static_cast(ent); From a4003dd61cd406ab5b4029b4fe6e6b7ea27916a5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:16:52 +0100 Subject: [PATCH 0163/2040] Only execute anim/suppress.scr if targeting 2.0 and above --- code/fgame/actor_turret.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/fgame/actor_turret.cpp b/code/fgame/actor_turret.cpp index c4e48fff..6b315cb0 100644 --- a/code/fgame/actor_turret.cpp +++ b/code/fgame/actor_turret.cpp @@ -233,6 +233,7 @@ void Actor::Turret_BeginRetarget(void) SetEnemyPos(m_Enemy->origin); AimAtEnemyBehavior(); + // Was ACTOR_STATE_TURRET_RETARGET_SNIPER_NODE before 2.0 TransitionState(ACTOR_STATE_TURRET_RETARGET_SUPPRESS, 0); } @@ -307,7 +308,9 @@ void Actor::State_Turret_Shoot(void) } AimAtTargetPos(); - Anim_Suppress(); + if (g_target_game >= target_game_e::TG_MOHTA) { + Anim_Suppress(); + } if (level.inttime >= m_iStateTime + 15000) { Turret_SelectState(); From 651b86b066803ab7b492d69b5059814c40a81b30 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:23:00 +0100 Subject: [PATCH 0164/2040] Added comment for more clarity --- code/fgame/actor_turret.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/fgame/actor_turret.cpp b/code/fgame/actor_turret.cpp index 6b315cb0..93dfbb3d 100644 --- a/code/fgame/actor_turret.cpp +++ b/code/fgame/actor_turret.cpp @@ -233,7 +233,9 @@ void Actor::Turret_BeginRetarget(void) SetEnemyPos(m_Enemy->origin); AimAtEnemyBehavior(); - // Was ACTOR_STATE_TURRET_RETARGET_SNIPER_NODE before 2.0 + // Replaced in 2.0 + // Use the Retarget_Suppress state instead of the Retarget_Sniper_Node state + //TransitionState(ACTOR_STATE_TURRET_RETARGET_SNIPER_NODE, 0); TransitionState(ACTOR_STATE_TURRET_RETARGET_SUPPRESS, 0); } From ceb901e9ca30e27d5b506f962d727ffd352b4817 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:32:06 +0100 Subject: [PATCH 0165/2040] Fixed disconnected menu not being pushed properly --- code/client/cl_cgame.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index 13471caa..238fed26 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -358,7 +358,9 @@ qboolean CL_ProcessServerCommand(const char* origString, const char* cmd, qboole // because this function might be called from a module that would be unloaded // inside Com_Error UI_ForceMenuOff(1); - Cbuf_AddText("disconnect;pushmenu disconnected"); + // Fixed in OPM + // Added a newline for next commands + Cbuf_AddText("disconnect;pushmenu disconnected\n"); return qtrue; } From 07ec6adecb7ddb3f4b4ee5ce2a98b2804ec9cef8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:40:34 +0100 Subject: [PATCH 0166/2040] Fixed ViewJitter never being removed --- code/fgame/earthquake.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/earthquake.cpp b/code/fgame/earthquake.cpp index 4d008b6a..835e5603 100644 --- a/code/fgame/earthquake.cpp +++ b/code/fgame/earthquake.cpp @@ -133,7 +133,7 @@ ViewJitter::ViewJitter() m_fDuration = 0; - m_bDoneDeath = qfalse; + m_bDoneDeath = false; } ViewJitter::ViewJitter( Vector vOrigin, float fRadius, float fEdgeEffect, Vector vStrength, float fDuration, Vector vTimeDecay, float fStartDecay ) @@ -154,7 +154,7 @@ ViewJitter::ViewJitter( Vector vOrigin, float fRadius, float fEdgeEffect, Vector m_fDuration = fDuration; - m_bDoneDeath = false; + m_bDoneDeath = true; m_fTimeRunning = 0; PostEvent( EV_ViewJitter_Think, fStartDecay ); From a5c6654dcb84990298fe585a05dcc1c81892f866 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:22:19 +0100 Subject: [PATCH 0167/2040] Fixed m_fMaxDistanceSquared initialization value --- code/fgame/actor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index c0c54567..5d617752 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -2790,7 +2790,7 @@ Actor::Actor() m_fMinDistance = 128; m_fMinDistanceSquared = Square(m_fMinDistance); m_fMaxDistance = 1024; - m_fMaxDistanceSquared = Square(m_fMaxDistanceSquared); + m_fMaxDistanceSquared = Square(m_fMaxDistance); m_fLeash = 512; m_fLeashSquared = Square(m_fLeash); @@ -2848,7 +2848,7 @@ Actor::Actor() m_iNextDisguiseTime = 1; m_iDisguisePeriod = 30000; - m_fMaxDisguiseDistSquared = 256 * 256; + m_fMaxDisguiseDistSquared = Square(256); m_iDisguiseLevel = 1; m_patrolCurrentNode = NULL; From 33b403d6eb46047b12cf5d41f9f485a30f05417c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:58:29 +0100 Subject: [PATCH 0168/2040] Fixed MASK_CANSEE --- code/fgame/bg_public.h | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 091508b7..e9af867f 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -617,20 +617,21 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_LADDER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_CLAYPIDGEON | CONTENTS_BBOX \ | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_UNKNOWN3 | CONTENTS_FENCE | CONTENTS_BODY | CONTENTS_CORPSE \ | CONTENTS_TRIGGER) -#define MASK_FOOTSHADOW (CONTENTS_FENCE | CONTENTS_SLIME | CONTENTS_LAVA | CONTENTS_SOLID) -#define MASK_PLAYERSTART (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BODY) -#define MASK_VIEWSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_FENCE | CONTENTS_TRIGGER) -#define MASK_DEADSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_CORPSE | CONTENTS_NOTTEAM2 | CONTENTS_FENCE) -#define MASK_MONSTERSOLID (CONTENTS_SOLID | CONTENTS_MONSTERCLIP | CONTENTS_BODY | CONTENTS_TRIGGER | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) -#define MASK_WATER (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME) -#define MASK_OPAQUE (CONTENTS_SOLID | CONTENTS_SLIME | CONTENTS_LAVA) +#define MASK_FOOTSHADOW (CONTENTS_FENCE | CONTENTS_SLIME | CONTENTS_LAVA | CONTENTS_SOLID) +#define MASK_PLAYERSTART (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BODY) +#define MASK_VIEWSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_FENCE | CONTENTS_TRIGGER) +#define MASK_DEADSOLID (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_CORPSE | CONTENTS_NOTTEAM2 | CONTENTS_FENCE) +#define MASK_MONSTERSOLID \ + (CONTENTS_SOLID | CONTENTS_MONSTERCLIP | CONTENTS_BODY | CONTENTS_TRIGGER | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) +#define MASK_WATER (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME) +#define MASK_OPAQUE (CONTENTS_SOLID | CONTENTS_SLIME | CONTENTS_LAVA) #define MASK_SHOT \ (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_FENCE | CONTENTS_WEAPONCLIP \ | CONTENTS_BODY | CONTENTS_TRIGGER) #define MASK_SHOT_TRIG \ (CONTENTS_SOLID | CONTENTS_CLAYPIDGEON | CONTENTS_WATER | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 \ | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY | CONTENTS_TRIGGER) -#define MASK_SHOT_FLUID \ +#define MASK_SHOT_FLUID \ (CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_FENCE \ | CONTENTS_WEAPONCLIP | CONTENTS_SHOOTONLY | CONTENTS_BODY | CONTENTS_TRIGGER) #define MASK_PROJECTILE \ @@ -654,13 +655,14 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_FENCE | CONTENTS_VEHICLECLIP \ | CONTENTS_BODY | CONTENTS_TRIGGER) #define MASK_VEHICLE_TIRES (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_FENCE | CONTENTS_VEHICLECLIP | CONTENTS_TRIGGER) -#define MASK_CLICK (CONTENTS_VEHICLECLIP | CONTENTS_WEAPONCLIP | CONTENTS_MONSTERCLIP | CONTENTS_PLAYERCLIP | CONTENTS_SOLID) -#define MASK_CANSEE \ - (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY) +#define MASK_CLICK \ + (CONTENTS_VEHICLECLIP | CONTENTS_WEAPONCLIP | CONTENTS_MONSTERCLIP | CONTENTS_PLAYERCLIP | CONTENTS_SOLID) +#define MASK_CANSEE \ + (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 \ + | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY) #define MASK_CANSEE_NOENTS (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) #define MASK_ITEM (CONTENTS_SOLID | CONTENTS_TRIGGER | CONTENTS_PLAYERCLIP | CONTENTS_FENCE) -#define MASK_TRANSITION \ - (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_UNKNOWN2 | CONTENTS_NOTTEAM1 | CONTENTS_WEAPONCLIP) +#define MASK_TRANSITION (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) #define MASK_TARGETPATH \ (CONTENTS_SOLID | CONTENTS_TRIGGER | CONTENTS_MONSTERCLIP | CONTENTS_FENCE | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) #define MASK_ACTORPATH (CONTENTS_SOLID | CONTENTS_FENCE | CONTENTS_MONSTERCLIP | CONTENTS_TRIGGER) From 4fa457118f62a80aeeb591a4f731efe95eb47c2d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:06:35 +0100 Subject: [PATCH 0169/2040] Fixed CanMovePathWithLeash() not returning the correct result --- code/fgame/actor.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 5d617752..af49f1f1 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -10076,11 +10076,8 @@ bool Actor::CanMovePathWithLeash(void) const } VectorSub2D(origin, m_vHome, delta); - if (VectorLength2DSquared(delta) >= m_fLeashSquared) { - return true; - } - - if (DotProduct2D(m_Path.CurrentDelta(), delta) >= 0) { + if (VectorLength2DSquared(delta) >= m_fLeashSquared + && DotProduct2D(m_Path.CurrentDelta(), delta) >= 0) { return false; } From c4855029a9cc6ab97ab6331736802144735885cf Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:22:44 +0100 Subject: [PATCH 0170/2040] Fixed motion facing --- code/fgame/actor.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index af49f1f1..19ecc979 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -8448,11 +8448,14 @@ void Actor::FaceEnemyOrMotion(int iTimeIntoMove) return; } - if (vDelta[0] >= 15 || vDelta[0] <= -15 || vDelta[1] >= 15 || vDelta[1] <= -15) { - vDelta[0] = -vDelta[0]; - vDelta[1] = -vDelta[1]; - FaceDirectionDuringMotion(vDelta); + if (vDelta[0] < 15 && vDelta[0] > -15 && vDelta[1] < 15 && vDelta[1] > -15) { + FaceMotion(); + return; } + + vDelta[0] = -vDelta[0]; + vDelta[1] = -vDelta[1]; + FaceDirectionDuringMotion(vDelta); } /* @@ -8547,10 +8550,12 @@ void Actor::FaceMotion(void) VectorCopy2D(velocity, dir); VectorSub2D(origin, m_vOriginHistory[m_iCurrentHistory], vDelta); - if (VectorLength2DSquared(vDelta) >= 1 && DotProduct2D(velocity, vDelta) > 0) { + if (VectorLength2DSquared(vDelta) >= 1 && DotProduct2D(vDelta, dir) > 0) { VectorCopy2D(vDelta, dir); } + dir[2] = 0; + if (m_ThinkState == THINKSTATE_IDLE) { IdleLook(dir); } else { From 1533c02a41b23feb54c018f8d5aca3f3833993dc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:32:57 +0100 Subject: [PATCH 0171/2040] Fixed cover hide --- code/fgame/actor_cover.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor_cover.cpp b/code/fgame/actor_cover.cpp index 97701778..456f2efc 100644 --- a/code/fgame/actor_cover.cpp +++ b/code/fgame/actor_cover.cpp @@ -79,7 +79,7 @@ bool Actor::Cover_SetPath(PathNode *node) fPathDist = PathDist(); fMinDistSquared = Square(fPathDist); - if ((node->origin - origin).lengthSquared() <= fMinDistSquared * 4.0f && fPathDist > 128.0f) { + if ((node->origin - origin).lengthSquared() * 4 <= fMinDistSquared && fPathDist > 128.0f) { return false; } @@ -343,7 +343,7 @@ void Actor::State_Cover_Hide(void) bool bCanShoot, bCanSee; if (m_Enemy) { - SetEnemyPos(origin); + SetEnemyPos(m_Enemy->origin); } if (!m_pCoverNode) { From e450156bf7e63520488837241283869ab0933185 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:46:43 +0100 Subject: [PATCH 0172/2040] Fixed path goal movement --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 19ecc979..6d97726b 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -5459,7 +5459,7 @@ void Actor::MovePathGoal(float fMoveSpeed) m_eAnimMode = ANIM_MODE_NORMAL; } } - } else if (fDeltaSquareLen < Square(fMoveSpeed * 0.5f)) { + } else if (fDeltaSquareLen < fMoveSpeed * Square(0.5f)) { fTimeToGo = 0.5f; m_fPathGoalTime = level.time + fTimeToGo; if (m_csPathGoalEndAnimScript == STRING_EMPTY) { From aab24260e27a46837a708ffe0cc4572e135ed90f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:47:54 +0100 Subject: [PATCH 0173/2040] FriendlyInLineOfFire should return false below 2.0 --- code/fgame/actor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 6d97726b..5c46fe70 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -4009,6 +4009,10 @@ bool Actor::FriendlyInLineOfFire(Entity *other) Vector delta; float inverseDot; + if (g_target_game <= target_game_e::TG_MOH) { + return false; + } + delta = other->origin - origin; inverseDot = 1.0 / (delta * delta); @@ -4022,7 +4026,7 @@ bool Actor::FriendlyInLineOfFire(Entity *other) Vector org; org = squadDot * inverseDot * delta - squadDelta; - if (org * org >= 4096) { + if (org * org >= Square(64)) { return true; } } From c9f2603692660b5fccf074180c69dae6ee5aa3bc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:48:11 +0100 Subject: [PATCH 0174/2040] Don't suppress below 2.0 --- code/fgame/actor_turret.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/code/fgame/actor_turret.cpp b/code/fgame/actor_turret.cpp index 93dfbb3d..8db46a58 100644 --- a/code/fgame/actor_turret.cpp +++ b/code/fgame/actor_turret.cpp @@ -235,8 +235,11 @@ void Actor::Turret_BeginRetarget(void) // Replaced in 2.0 // Use the Retarget_Suppress state instead of the Retarget_Sniper_Node state - //TransitionState(ACTOR_STATE_TURRET_RETARGET_SNIPER_NODE, 0); - TransitionState(ACTOR_STATE_TURRET_RETARGET_SUPPRESS, 0); + if (g_target_game >= target_game_e::TG_MOHTA) { + TransitionState(ACTOR_STATE_TURRET_RETARGET_SUPPRESS, 0); + } else { + TransitionState(ACTOR_STATE_TURRET_RETARGET_SNIPER_NODE, 0); + } } void Actor::Turret_NextRetarget(void) @@ -290,30 +293,31 @@ void Actor::Turret_SideStep(int iStepSize, vec3_t vDir) AimAtEnemyBehavior(); StrafeToAttack(iStepSize, vDir); - if (!PathExists() || PathComplete() || !PathAvoidsSquadMates()) { - StrafeToAttack(-iStepSize, vDir); + if (PathExists() && !PathComplete() && PathAvoidsSquadMates()) { + TransitionState(ACTOR_STATE_TURRET_REACQUIRE); + return; } + StrafeToAttack(-iStepSize, vDir); + if (PathExists() && !PathComplete() && PathAvoidsSquadMates()) { TransitionState(ACTOR_STATE_TURRET_REACQUIRE); - } else { - Turret_NextRetarget(); + return; } + + Turret_NextRetarget(); } void Actor::State_Turret_Shoot(void) { + assert(g_target_game > target_game_e::TG_MOH); + if (CanSeeEnemy(200) || FriendlyInLineOfFire(m_Enemy)) { TransitionState(ACTOR_STATE_TURRET_COMBAT); State_Turret_Combat(); return; } - AimAtTargetPos(); - if (g_target_game >= target_game_e::TG_MOHTA) { - Anim_Suppress(); - } - if (level.inttime >= m_iStateTime + 15000) { Turret_SelectState(); if (m_State == ACTOR_STATE_TURRET_SHOOT) { @@ -326,6 +330,8 @@ void Actor::State_Turret_Retarget_Suppress(void) { trace_t trace; + assert(g_target_game > target_game_e::TG_MOH); + if (rand() % 100 >= m_iSuppressChance) { AimAtEnemyBehavior(); Turret_NextRetarget(); From efc1354dcb5105088255f8d77124795fe7fd65a8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:58:08 +0100 Subject: [PATCH 0175/2040] Fixed entity monitoring always used --- code/fgame/entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 8d6b5d92..3b9156dc 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -5467,7 +5467,7 @@ void Entity::MPrintf(const char *fmt, ...) va_list argptr; char msg[MAXPRINTMSG]; - if (g_monitorNum->integer == entnum || g_monitor->string == targetname) { + if (g_monitorNum->integer == entnum || g_monitor->string[0] && g_monitor->string == targetname) { va_start(argptr, fmt); Q_vsnprintf(msg, sizeof(msg), fmt, argptr); va_end(argptr); From abfdac59ba132b02f5490d229ecc93127c20fabf Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 15 Feb 2024 00:21:01 +0100 Subject: [PATCH 0176/2040] Make aiMaxDeviation only supported on 2.0 and above --- code/fgame/actor.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 5c46fe70..600e02a6 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -10150,12 +10150,14 @@ Vector Actor::GunTarget(bool bNoCollision, const vec3_t position, const vec3_t f Vector dir = mTargetPos - EyePosition(); dir.normalize(); - if (DotProduct2D(forward, dir) < aiMaxDeviation->value) { - Vector vOut; + if (g_target_game > target_game_e::TG_MOH) { + if (DotProduct2D(forward, dir) < aiMaxDeviation->value) { + Vector vOut; - VectorMA(position, 2048, forward, vOut); + VectorMA(position, 2048, forward, vOut); - return vOut; + return vOut; + } } if (mTargetPos == vec_zero) { From 373a35acf0dc4d48db4c0eff776183e9b72d0bc5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:23:17 +0100 Subject: [PATCH 0177/2040] Fixed target trigger being triggered by itself --- code/fgame/vehicle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index f9795501..123fbc92 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -6923,7 +6923,7 @@ void DrivableVehicle::Killed(Event *ev) if (name && strcmp(name, "")) { for (ent = G_FindTarget(NULL, name); ent; ent = G_FindTarget(ent, name)) { event = new Event(EV_Activate); - event->AddEntity(ent); + event->AddEntity(attacker); ent->ProcessEvent(event); } } From fdf1dac618a1e1f7b71c9956519768504adb6bab Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:23:46 +0100 Subject: [PATCH 0178/2040] Wrong condition for SetDesiredYawDest (should set only if values are non-zero) --- code/fgame/simpleactor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/simpleactor.h b/code/fgame/simpleactor.h index 873a8885..4aea2112 100644 --- a/code/fgame/simpleactor.h +++ b/code/fgame/simpleactor.h @@ -469,7 +469,7 @@ inline void SimpleActor::SetDesiredYawDest(const vec3_t vec) vec2_t facedir; VectorSub2D(vec, origin, facedir); - if (!facedir[0] || !facedir[1]) { + if (facedir[0] || facedir[1]) { SetDesiredYawDir(facedir); } } From 60f6bb17e31fe416533c7a6189ac23d65d1ca31c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:40:55 +0100 Subject: [PATCH 0179/2040] Fixed AI parameters not fixing AI parameters --- code/fgame/actor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 600e02a6..f24d9204 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -8004,8 +8004,8 @@ void Actor::FixAIParameters(void) if (m_pTetherEnt) { fMinLeash = 64; if (m_pTetherEnt->IsSubclassOfEntity()) { - fMinLeash = - m_pTetherEnt->angles.y - m_pTetherEnt->origin.y + m_pTetherEnt->angles.z + m_pTetherEnt->origin.z; + Entity* pEnt = static_cast(m_pTetherEnt.Pointer()); + fMinLeash = pEnt->maxs[0] - pEnt->mins[1] + pEnt->maxs[1] - pEnt->mins[1]; } if (m_fLeash < fMinLeash) { From f46078965d1b3c95130fd0cc9f28f4e372044d69 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 15 Feb 2024 21:15:37 +0100 Subject: [PATCH 0180/2040] info_null must inherits from Listener instead of Entity This fixes Level::AllocEdict issues on some maps that use it a lot (like t2l4) #206 --- code/fgame/misc.cpp | 2 +- code/fgame/misc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/misc.cpp b/code/fgame/misc.cpp index c2e95139..2165c049 100644 --- a/code/fgame/misc.cpp +++ b/code/fgame/misc.cpp @@ -91,7 +91,7 @@ Used as a positional target for spotlights, etc. ******************************************************************************/ -CLASS_DECLARATION(Entity, InfoNull, "info_null") { +CLASS_DECLARATION(Listener, InfoNull, "info_null") { {NULL, NULL} }; diff --git a/code/fgame/misc.h b/code/fgame/misc.h index 924fad3b..f164c072 100644 --- a/code/fgame/misc.h +++ b/code/fgame/misc.h @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "mover.h" #include "animate.h" -class InfoNull : public Entity +class InfoNull : public Listener { public: CLASS_PROTOTYPE(InfoNull); From bd999a6d9c18ac120889bfd409db15f3c9ac7fec Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 15 Feb 2024 23:48:23 +0100 Subject: [PATCH 0181/2040] Fixed Trace's pass_entities parameter (didn't properly ignore entities) --- code/fgame/scriptthread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index be8438a9..a5f74957 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -3759,7 +3759,7 @@ void ScriptThread::EventTrace(Event *ev) mins = ev->GetVector(4); case 3: if (ev->GetInteger(3)) { - content_mask = MASK_SOLID; + content_mask &= ~MASK_SCRIPT_SLAVE; } case 2: end = ev->GetVector(2); From 8a3b62e93fb8acf0e062589554ba70d2d1b70f17 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 16 Feb 2024 23:50:57 +0100 Subject: [PATCH 0182/2040] Fixed targetname error --- code/script/scriptvm.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/script/scriptvm.cpp b/code/script/scriptvm.cpp index 1f9e6cff..c3251dd2 100644 --- a/code/script/scriptvm.cpp +++ b/code/script/scriptvm.cpp @@ -1794,12 +1794,13 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) targetList = world->GetExistingTargetList(m_VMStack.GetTop().constStringValue()); if (!targetList || !targetList->NumObjects()) { + str targetname = m_VMStack.GetTop().stringValue(); // the target name was not found m_VMStack.GetTop().setListenerValue(NULL); if ((*m_CodePos >= OP_BIN_EQUALITY && *m_CodePos <= OP_BIN_GREATER_THAN_OR_EQUAL) || (*m_CodePos >= OP_BOOL_UN_NOT && *m_CodePos <= OP_UN_CAST_BOOLEAN)) { - ScriptError("Targetname '%s' does not exist.", m_VMStack.GetTop().stringValue().c_str()); + ScriptError("Targetname '%s' does not exist.", targetname.c_str()); } } else if (targetList->NumObjects() == 1) { // single listener From 6ba9f2655cc9af09ec3ac13cdf6a4b7fafca1cdd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 16 Feb 2024 23:51:34 +0100 Subject: [PATCH 0183/2040] Call PostSpawn after constructing the health instance --- code/fgame/health.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/fgame/health.cpp b/code/fgame/health.cpp index 5af8fd15..eeaaec6a 100644 --- a/code/fgame/health.cpp +++ b/code/fgame/health.cpp @@ -44,12 +44,18 @@ SafePtr Health::mHealthQueue[MAX_HEALTH_QUEUE]; Health::Health() { + if (LoadingSavegame) { + return; + } + if (DM_FLAG(DF_NO_HEALTH)) { PostEvent(EV_Remove, EV_REMOVE); return; } setAmount(20); + + PostEvent(EV_Health_PostSpawn, EV_POSTSPAWN); } void Health::PickupHealth(Event *ev) From 776012fedfa82c000aeade4c33723331f6d9b88b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 16 Feb 2024 23:52:25 +0100 Subject: [PATCH 0184/2040] Health must have a targetname by default in 2.0 and above --- code/fgame/health.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/health.cpp b/code/fgame/health.cpp index eeaaec6a..87e05825 100644 --- a/code/fgame/health.cpp +++ b/code/fgame/health.cpp @@ -55,6 +55,10 @@ Health::Health() setAmount(20); + // Added in 2.0 + // Set the targetname to health by default + SetTargetName("health"); + PostEvent(EV_Health_PostSpawn, EV_POSTSPAWN); } From 685dc0336a8c03c98519d23661d7e37a7e241ee1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:05:39 +0100 Subject: [PATCH 0185/2040] Corrected loop ordering --- code/fgame/navigate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/navigate.cpp b/code/fgame/navigate.cpp index 4d786a95..b7b76eb9 100644 --- a/code/fgame/navigate.cpp +++ b/code/fgame/navigate.cpp @@ -1041,8 +1041,8 @@ void PathSearch::ResetNodes(void) } } - for (x = PATHMAP_GRIDSIZE - 1; x >= 0; x--) { - for (y = PATHMAP_GRIDSIZE - 1; y >= 0; y--) { + for (x = 0; x < PATHMAP_GRIDSIZE; x++){ + for (y = 0; y < PATHMAP_GRIDSIZE; y++) { PathMap[x][y].numnodes = 0; PathMap[x][y].nodes = NULL; } From 03943a23ac2ef836f56284fb39ac0702b1257874 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 17 Feb 2024 20:10:00 +0100 Subject: [PATCH 0186/2040] Fixed badplace and run and shoot think never working --- code/fgame/actor.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index f24d9204..e7344e3d 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -2685,7 +2685,12 @@ const_str Actor::m_csThinkNames[NUM_THINKS] = { STRING_BALCONY_KILLED, STRING_WEAPONLESS, STRING_NOCLIP, - STRING_DEAD}; + STRING_DEAD, + // Added in 2.0 + STRING_BADPLACE, + // Added in 2.30 + STRING_RUNANDSHOOT +}; const_str Actor::m_csThinkStateNames[NUM_THINKSTATES] = { STRING_VOID, STRING_IDLE, @@ -2695,7 +2700,9 @@ const_str Actor::m_csThinkStateNames[NUM_THINKSTATES] = { STRING_CURIOUS, STRING_DISGUISE, STRING_GRENADE, - STRING_NOCLIP}; + STRING_BADPLACE, // Added in 2.0 + STRING_NOCLIP +}; SafePtr Actor::mBodyQueue[MAX_BODYQUEUE]; int Actor::mCurBody; @@ -4080,7 +4087,7 @@ void Actor::ShowInfo(void) { Com_Printf("-------------------------------------------------------------------------------\n"); Com_Printf("Info for Actor:\n"); - Com_Printf("Current think type: %s %s\n", ThinkName().c_str(), ThinkStateName().c_str()); + Com_Printf("Current think type: %s %s\n", ThinkStateName().c_str(), ThinkName().c_str()); Com_Printf("leash: %f\n", m_fLeash); Com_Printf("mindist: %f\n", m_fMinDistance); Com_Printf("maxdist: %f\n", m_fMaxDistance); From a770df1e0b6d0156ebf427013006a4f3174bb3e5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 17 Feb 2024 20:10:17 +0100 Subject: [PATCH 0187/2040] Fixed path not found spam --- code/fgame/simpleactor.cpp | 58 +++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/code/fgame/simpleactor.cpp b/code/fgame/simpleactor.cpp index 7c4aecf6..ad76f12e 100644 --- a/code/fgame/simpleactor.cpp +++ b/code/fgame/simpleactor.cpp @@ -187,30 +187,42 @@ void SimpleActor::SetPath( m_Path.FindPath(origin, vDestPos, this, 0.0, vLeashHome, fLeashDistSquared); if (!PathExists()) { - if (g_patherror->integer && description - && (g_patherror->integer - || g_patherror->integer == 2 - && (static_cast(this)->m_ThinkState == THINKSTATE_IDLE - || static_cast(this)->m_ThinkState == THINKSTATE_CURIOUS) - && m_bPathErrorTime + 5000 < level.inttime)) { - m_bPathErrorTime = level.inttime; - - Com_Printf( - "^~^~^ Path not found in '%s' for (entnum %d, radnum %d, targetname '%s') from (%f %f " - "%f) to (%f %f %f)\n", - description, - entnum, - radnum, - targetname.c_str(), - origin.x, - origin.y, - origin.z, - vDestPos.x, - vDestPos.y, - vDestPos.z - ); - Com_Printf("Reason: %s\n", PathSearch::last_error); + if (!g_patherror->integer || !description) { + return; } + + if (g_patherror->integer != 1 && g_patherror->integer != 2) { + return; + } + + if (g_patherror->integer == 2) { + int thinkState = static_cast(this)->m_ThinkState; + if (thinkState != THINKSTATE_IDLE && thinkState != THINKSTATE_CURIOUS) { + return; + } + } + + if (m_bPathErrorTime + 5000 >= level.inttime) { + return; + } + + m_bPathErrorTime = level.inttime; + + Com_Printf( + "^~^~^ Path not found in '%s' for (entnum %d, radnum %d, targetname '%s') from (%f %f " + "%f) to (%f %f %f)\n", + description, + entnum, + radnum, + targetname.c_str(), + origin.x, + origin.y, + origin.z, + vDestPos.x, + vDestPos.y, + vDestPos.z + ); + Com_Printf("Reason: %s\n", PathSearch::last_error); } } From 5521cf9ab39b7db44f610be970fa60e06f7bd9f8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:10:18 +0100 Subject: [PATCH 0188/2040] Fixed m_fMaxSpeed being always set to 250 --- code/fgame/vehicle.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 123fbc92..0baedf59 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -3375,7 +3375,7 @@ void Vehicle::EventDriveInternal(Event *ev, bool wait) m_fLookAhead = 256; m_fIdealAccel = 35; m_fIdealSpeed = 250; - m_fMaxSpeed = 250; + m_fMaxSpeed = 250; // Added in 2.30 switch (ev->NumArgs()) { case 6: @@ -3388,6 +3388,7 @@ void Vehicle::EventDriveInternal(Event *ev, bool wait) m_fIdealAccel = ev->GetFloat(3); case 2: m_fIdealSpeed = ev->GetFloat(2); + m_fMaxSpeed = m_fIdealSpeed;// Added in 2.30 case 1: path = ev->GetSimpleEntity(1); if (!path) { @@ -4088,21 +4089,22 @@ void Vehicle::SlidePush(Vector vPush) if (j == i && other->entity) { other->entity->CheckGround(); - if (other->entity->groundentity - && (other->entity->groundentity == edict || other->entity == m_pCollisionEntity)) { - // save the entity - pSkippedEntities[iNumSkipped] = other->entity; - iContentsEntities[iNumSkipped] = other->r.contents; - solidEntities[iNumSkipped] = other->solid; - iNumSkipped++; + if (other->entity->groundentity) { + if (other->entity->groundentity == edict || m_pCollisionEntity && other->entity->groundentity->entity == m_pCollisionEntity) { + // save the entity + pSkippedEntities[iNumSkipped] = other->entity; + iContentsEntities[iNumSkipped] = other->r.contents; + solidEntities[iNumSkipped] = other->solid; + iNumSkipped++; - if (iNumSkipped >= MAX_SKIPPED_ENTITIES) { - gi.Error(ERR_DROP, "MAX_SKIPPED_ENTITIES hit in VehicleMove.\n"); - return; + if (iNumSkipped >= MAX_SKIPPED_ENTITIES) { + gi.Error(ERR_DROP, "MAX_SKIPPED_ENTITIES hit in VehicleMove.\n"); + return; + } + + other->entity->setSolidType(SOLID_NOT); + iNumSkippedEntities++; } - - other->entity->setSolidType(SOLID_NOT); - iNumSkippedEntities++; } if (g_showvehiclemovedebug->integer) { From 46cc00d66984985a02594d0f0c3bedd0a6704bd9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 18 Feb 2024 21:53:33 +0100 Subject: [PATCH 0189/2040] Set m_fMaxSpeed --- code/fgame/vehicle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 0baedf59..33664086 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -1096,6 +1096,7 @@ Vehicle::Vehicle() m_bAutoPilot = qfalse; m_fIdealSpeed = 0; + m_fMaxSpeed = 0; m_fIdealAccel = 0; m_fIdealDistance = 100; m_bBounceBackwards = false; From 65b47a2b3a02390ec20f63170ab7dabee12481d8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 18 Feb 2024 21:54:18 +0100 Subject: [PATCH 0190/2040] Fixed AnimDone never being called This fixes maps like e1l2 never starting because it waits for an anim to finish --- code/fgame/scriptslave.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 12956162..89157267 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1925,7 +1925,7 @@ void ScriptModel::SetAnimEvent(Event *ev) animnum = gi.Anim_NumForName(edict->tiki, animname); if (animnum >= 0) { - NewAnim(animnum); + NewAnim(animnum, EV_ScriptModel_AnimDone); } } } From 10a8d13ade97158d9ca5a0efd9881c766ebf6170 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 18 Feb 2024 23:27:15 +0100 Subject: [PATCH 0191/2040] Added missing variables to archive --- code/fgame/vehicle.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 33664086..1d47f275 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -6471,6 +6471,7 @@ void Vehicle::Archive(Archiver& arc) arc.ArchiveVector(&Corners[3]); arc.ArchiveBoolean(&drivable); + arc.ArchiveBoolean(&pathDrivable); // Added in 2.30 arc.ArchiveBoolean(&locked); arc.ArchiveBoolean(&hasweapon); arc.ArchiveBoolean(&showweapon); @@ -6478,6 +6479,11 @@ void Vehicle::Archive(Archiver& arc) arc.ArchiveBoolean(&jumpable); arc.ArchiveBoolean(&m_bMovementLocked); + arc.ArchiveBoolean(&m_bAnimMove); // Added in 2.0 + arc.ArchiveBoolean(&m_bDamageSounds); // Added in 2.0 + arc.ArchiveBoolean(&m_bRunSounds); // Added in 2.0 + arc.ArchiveInteger(&m_iProjectileHitsRemaining); // Added in 2.30 + driver.Archive(arc); lastdriver.Archive(arc); @@ -6714,6 +6720,8 @@ void Vehicle::Archive(Archiver& arc) m_sMoveGrid->Archive(arc); arc.ArchiveFloat(&m_fIdealSpeed); + arc.ArchiveFloat(&m_fMaxSpeed); // Added in 2.30 + arc.ArchiveBool(&m_bBounceBackwards); // Added in 2.30 arc.ArchiveVector(&m_vIdealPosition); arc.ArchiveVector(&m_vIdealDir); arc.ArchiveFloat(&m_fIdealAccel); @@ -6727,6 +6735,10 @@ void Vehicle::Archive(Archiver& arc) arc.ArchiveSafePointer(&m_pVehicleSoundEntities[1]); arc.ArchiveSafePointer(&m_pVehicleSoundEntities[2]); arc.ArchiveSafePointer(&m_pVehicleSoundEntities[3]); + + // Added in 2.30 + arc.ArchiveFloat(&m_fMaxUseAngle); + arc.ArchiveBool(&m_bBounceStayFullSpeed); } /* From 7956746b65587086cfa6cde708439638fb1226bc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:23:27 +0100 Subject: [PATCH 0192/2040] Fixed inward sphere argument: the argument should be optional See #209 --- code/cgame/cg_commands.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/cgame/cg_commands.cpp b/code/cgame/cg_commands.cpp index 6103d7a9..30e45fda 100644 --- a/code/cgame/cg_commands.cpp +++ b/code/cgame/cg_commands.cpp @@ -2157,7 +2157,9 @@ void ClientGameCommandManager::SetInwardSphere(Event *ev) } m_spawnthing->cgd.flags |= T_INWARDSPHERE; - m_spawnthing->sphereRadius = ev->GetFloat(1); + if (ev->NumArgs() > 0) { + m_spawnthing->sphereRadius = ev->GetFloat(1); + } } //============= From 1da41131101a443cded6a2c2154582becc157614 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:35:59 +0100 Subject: [PATCH 0193/2040] Added FuncLadder archive method This fixes bug where ladder would get unusable after loading from save game (see #211) --- code/fgame/misc.cpp | 547 ++++++++++++++++++++++++++++++++++---------- code/fgame/misc.h | 14 +- 2 files changed, 435 insertions(+), 126 deletions(-) diff --git a/code/fgame/misc.cpp b/code/fgame/misc.cpp index 2165c049..333874f1 100644 --- a/code/fgame/misc.cpp +++ b/code/fgame/misc.cpp @@ -144,15 +144,62 @@ If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenade #define ACCUMULATIVE (1 << 6) #define TWOSTAGE (1 << 7) -Event EV_ExplodingWall_StopRotating("stoprotating", EV_DEFAULT, NULL, NULL, "Stop rotating the wall.", EV_NORMAL); -Event EV_ExplodingWall_OnGround( - "checkonground", EV_DEFAULT, NULL, NULL, "Check if exploding wall is on ground.", EV_NORMAL +Event EV_ExplodingWall_StopRotating +( + "stoprotating", + EV_DEFAULT, + NULL, + NULL, + "Stop rotating the wall.", + EV_NORMAL ); -Event EV_ExplodingWall_AngleSpeed("anglespeed", EV_DEFAULT, "f", "speed", "Set the angle speed.", EV_NORMAL); -Event EV_ExplodingWall_LandRadius("land_radius", EV_DEFAULT, "f", "radius", "Set the land radius.", EV_NORMAL); -Event EV_ExplodingWall_LandAngles("land_angles", EV_DEFAULT, "v", "angles", "Set the land angles.", EV_NORMAL); -Event EV_ExplodingWall_BaseVelocity("base_velocity", EV_DEFAULT, "v", "velocity", "Set the base velocity.", EV_NORMAL); -Event EV_ExplodingWall_RandomVelocity( +Event EV_ExplodingWall_OnGround +( + "checkonground", + EV_DEFAULT, + NULL, + NULL, + "Check if exploding wall is on ground.", + EV_NORMAL +); +Event EV_ExplodingWall_AngleSpeed +( + "anglespeed", + EV_DEFAULT, + "f", + "speed", + "Set the angle speed.", + EV_NORMAL +); +Event EV_ExplodingWall_LandRadius +( + "land_radius", + EV_DEFAULT, + "f", + "radius", + "Set the land radius.", + EV_NORMAL +); +Event EV_ExplodingWall_LandAngles +( + "land_angles", + EV_DEFAULT, + "v", + "angles", + "Set the land angles.", + EV_NORMAL +); +Event EV_ExplodingWall_BaseVelocity +( + "base_velocity", + EV_DEFAULT, + "v", + "velocity", + "Set the base velocity.", + EV_NORMAL +); +Event EV_ExplodingWall_RandomVelocity +( "random_velocity", EV_DEFAULT, "v", @@ -160,11 +207,33 @@ Event EV_ExplodingWall_RandomVelocity( "Set the amount of random variation of the base velocity.", EV_NORMAL ); -Event EV_ExplodingWall_SetDmg("dmg", EV_DEFAULT, "i", "dmg", "Set the damage from the exploding wall.", EV_NORMAL); -Event EV_ExplodingWall_SetExplosions( - "explosions", EV_DEFAULT, "i", "explosions", "Set the number of explosions.", EV_NORMAL +Event EV_ExplodingWall_SetDmg +( + "dmg", + EV_DEFAULT, + "i", + "dmg", + "Set the damage from the exploding wall.", + EV_NORMAL +); +Event EV_ExplodingWall_SetExplosions +( + "explosions", + EV_DEFAULT, + "i", + "explosions", + "Set the number of explosions.", + EV_NORMAL +); +Event EV_ExplodingWall_Setup +( + "setup", + EV_CODEONLY, + NULL, + NULL, + "Initializes the exploding wall.", + EV_NORMAL ); -Event EV_ExplodingWall_Setup("setup", EV_CODEONLY, NULL, NULL, "Initializes the exploding wall.", EV_NORMAL); CLASS_DECLARATION(Trigger, ExplodingWall, "func_explodingwall") { {&EV_ExplodingWall_Setup, &ExplodingWall::Setup }, @@ -564,13 +633,26 @@ If NO_EFFECTS is set, the special effect will not happen and the teleport will b #define NO_EFFECTS (1 << 5) -Event EV_Teleporter_Teleport("teleport", EV_CODEONLY, "e", "entity", "Teleports the entity to destination.", EV_NORMAL); - -Event EV_Teleporter_StopTeleport( - "stopteleport", EV_CODEONLY, "e", "entity", "Releases the entity at the end of the teleport.", EV_NORMAL +Event EV_Teleporter_Teleport +( + "teleport", + EV_CODEONLY, + "e", + "entity", + "Teleports the entity to destination.", + EV_NORMAL ); - -Event EV_Teleporter_SetThread( +Event EV_Teleporter_StopTeleport +( + "stopteleport", + EV_CODEONLY, + "e", + "entity", + "Releases the entity at the end of the teleport.", + EV_NORMAL +); +Event EV_Teleporter_SetThread +( "teleportthread", EV_CODEONLY, "s", @@ -884,19 +966,35 @@ it waits until the player has left the trigger field. ******************************************************************************/ -Event EV_UseAnim_Reset( - "_reset", EV_CODEONLY, NULL, NULL, "Reset's the Use Anim after it has no longer been touched.", EV_NORMAL +Event EV_UseAnim_Reset +( + "_reset", + EV_CODEONLY, + NULL, + NULL, + "Reset's the Use Anim after it has no longer been touched.", + EV_NORMAL ); - -Event EV_UseAnim_Thread( - "setthread", EV_DEFAULT, "s", "label", "Sets which thread to use when this UseAnim is triggered.", EV_NORMAL +Event EV_UseAnim_Thread +( + "setthread", + EV_DEFAULT, + "s", + "label", + "Sets which thread to use when this UseAnim is triggered.", + EV_NORMAL ); - -Event EV_UseAnim_Count( - "count", EV_DEFAULT, "i", "newCount", "Sets how many times the UseAnim can be triggered.", EV_NORMAL +Event EV_UseAnim_Count +( + "count", + EV_DEFAULT, + "i", + "newCount", + "Sets how many times the UseAnim can be triggered.", + EV_NORMAL ); - -Event EV_UseAnim_TriggerTarget( +Event EV_UseAnim_TriggerTarget +( "triggertarget", EV_DEFAULT, "s", @@ -904,16 +1002,35 @@ Event EV_UseAnim_TriggerTarget( "Sets what should be triggered, when this UseAnim is triggered.", EV_NORMAL ); - -Event EV_UseAnim_SetAnim("anim", EV_DEFAULT, "s", "animName", "set the animation to use for player.", EV_NORMAL); - -Event EV_UseAnim_SetKey( - "key", EV_DEFAULT, "s", "keyName", "set the key needed to make this UseAnim function.", EV_NORMAL +Event EV_UseAnim_SetAnim +( + "anim", + EV_DEFAULT, + "s", + "animName", + "set the animation to use for player.", + EV_NORMAL ); - -Event EV_UseAnim_SetState("state", EV_CHEAT, "s", "stateName", "set the state to use for the player.", EV_NORMAL); - -Event EV_UseAnim_SetCamera( +Event EV_UseAnim_SetKey +( + "key", + EV_DEFAULT, + "s", + "keyName", + "set the key needed to make this UseAnim function.", + EV_NORMAL +); +Event EV_UseAnim_SetState +( + "state", + EV_CHEAT, + "s", + "stateName", + "set the state to use for the player.", + EV_NORMAL +); +Event EV_UseAnim_SetCamera +( "camera", EV_DEFAULT, "s", @@ -922,12 +1039,17 @@ Event EV_UseAnim_SetCamera( "topdown, behind, front, side, behind_fixed, side_left, side_right", EV_NORMAL ); - -Event EV_UseAnim_SetNumLoops( - "num_loops", EV_DEFAULT, "i", "loopCount", "set the number of times to loop an animation per use.", EV_NORMAL +Event EV_UseAnim_SetNumLoops +( + "num_loops", + EV_DEFAULT, + "i", + "loopCount", + "set the number of times to loop an animation per use.", + EV_NORMAL ); - -Event EV_UseAnim_SetDelay( +Event EV_UseAnim_SetDelay +( "delay", EV_DEFAULT, "f", @@ -1379,7 +1501,8 @@ int UseAnimDestination::GetNumLoops(void) return num_loops; } -Event EV_UseObject_MoveThread( +Event EV_UseObject_MoveThread +( "move_thread", EV_DEFAULT, "s", @@ -1387,38 +1510,80 @@ Event EV_UseObject_MoveThread( "Sets which move thread to use when this UseObject has finshed looping.", EV_NORMAL ); - -Event EV_UseObject_StopThread( - "stop_thread", EV_DEFAULT, "s", "label", "Sets which stop thread to use when this UseObject is finished.", EV_NORMAL +Event EV_UseObject_StopThread +( + "stop_thread", + EV_DEFAULT, + "s", + "label", + "Sets which stop thread to use when this UseObject is finished.", + EV_NORMAL ); - -Event EV_UseObject_ResetThread( - "reset_thread", EV_DEFAULT, "s", "label", "Sets which thread to call when resetting.", EV_NORMAL +Event EV_UseObject_ResetThread +( + "reset_thread", + EV_DEFAULT, + "s", + "label", + "Sets which thread to call when resetting.", + EV_NORMAL ); - -Event EV_UseObject_Count( - "count", EV_DEFAULT, "i", "newCount", "Sets how many times the UseObject can be triggered.", EV_NORMAL +Event EV_UseObject_Count +( + "count", + EV_DEFAULT, + "i", + "newCount", + "Sets how many times the UseObject can be triggered.", + EV_NORMAL ); - -Event EV_UseObject_Cone( - "cone", EV_DEFAULT, "f", "newCone", "Sets the cone in angles of where the Useobject can be used.", EV_NORMAL +Event EV_UseObject_Cone +( + "cone", + EV_DEFAULT, + "f", + "newCone", + "Sets the cone in angles of where the Useobject can be used.", + EV_NORMAL ); - -Event EV_UseObject_Offset( - "offset", EV_DEFAULT, "v", "newOffset", "Sets the offset to use for this UseObject.", EV_NORMAL +Event EV_UseObject_Offset +( + "offset", + EV_DEFAULT, + "v", + "newOffset", + "Sets the offset to use for this UseObject.", + EV_NORMAL ); - -Event EV_UseObject_YawOffset( - "yaw_offset", EV_DEFAULT, "f", "newYawOffset", "Sets the yaw offset to use for this UseObject.", EV_NORMAL +Event EV_UseObject_YawOffset +( + "yaw_offset", + EV_DEFAULT, + "f", + "newYawOffset", + "Sets the yaw offset to use for this UseObject.", + EV_NORMAL ); - -Event EV_UseObject_State("state", EV_DEFAULT, "s", "newState", "Sets the state to use for this UseObject.", EV_NORMAL); - -Event EV_UseObject_StateBackwards( - "state_backwards", EV_DEFAULT, "s", "newState", "Sets the backward state to use for this UseObject.", EV_NORMAL +Event EV_UseObject_State +( + "state", + EV_DEFAULT, + "s", + "newState", + "Sets the state to use for this UseObject.", + EV_NORMAL ); - -Event EV_UseObject_TriggerTarget( +Event EV_UseObject_StateBackwards +( + "state_backwards", + EV_DEFAULT, + "s", + "newState", + "Sets the backward state to use for this UseObject.", + EV_NORMAL +); +Event EV_UseObject_TriggerTarget +( "triggertarget", EV_DEFAULT, "s", @@ -1426,8 +1591,8 @@ Event EV_UseObject_TriggerTarget( "Sets what should be triggered, when this UseObject is triggered.", EV_NORMAL ); - -Event EV_UseObject_ResetTime( +Event EV_UseObject_ResetTime +( "reset_time", EV_DEFAULT, "f", @@ -1435,8 +1600,8 @@ Event EV_UseObject_ResetTime( "Sets the time it takes for the UseObject to reset itself.", EV_NORMAL ); - -Event EV_UseObject_DamageType( +Event EV_UseObject_DamageType +( "damage_type", EV_DEFAULT, "s", @@ -1444,8 +1609,8 @@ Event EV_UseObject_DamageType( "Sets what kind of damage is needed to activate the trigger.", EV_NORMAL ); - -Event EV_UseObject_Reset( +Event EV_UseObject_Reset +( "_useobject_reset", EV_DEFAULT, NULL, @@ -1453,12 +1618,17 @@ Event EV_UseObject_Reset( "Resets the useobject to the start state after a certain amount of time.", EV_NORMAL ); - -Event EV_UseObject_Resetting( - "_useobject_resetting", EV_DEFAULT, NULL, NULL, "Intermediate function for useobject reset.", EV_NORMAL +Event EV_UseObject_Resetting +( + "_useobject_resetting", + EV_DEFAULT, + NULL, + NULL, + "Intermediate function for useobject reset.", + EV_NORMAL ); - -Event EV_UseObject_DamageTriggered( +Event EV_UseObject_DamageTriggered +( "_useobject_damagetriggered", EV_DEFAULT, "e", @@ -1466,18 +1636,41 @@ Event EV_UseObject_DamageTriggered( "Intermediate function for when the useobject was triggered by damage.", EV_NORMAL ); - -Event EV_UseObject_Activate("activate", EV_DEFAULT, NULL, NULL, "Allow the useobject to be used.", EV_NORMAL); - -Event - EV_UseObject_Deactivate("deactivate", EV_DEFAULT, NULL, NULL, "Do not allow the useobject to be used.", EV_NORMAL); - -Event EV_UseObject_UseMaterial( - "usematerial", EV_DEFAULT, "s", "nameOfUseMaterial", "the name of the material that glows when active.", EV_NORMAL +Event EV_UseObject_Activate +( + "activate", + EV_DEFAULT, + NULL, + NULL, + "Allow the useobject to be used.", + EV_NORMAL ); - -Event EV_UseObject_SetActiveState( - "_setactivestate", EV_DEFAULT, NULL, NULL, "event that sets up the proper skin for the useobject.", EV_NORMAL +Event EV_UseObject_Deactivate +( + "deactivate", + EV_DEFAULT, + NULL, + NULL, + "Do not allow the useobject to be used.", + EV_NORMAL +); +Event EV_UseObject_UseMaterial +( + "usematerial", + EV_DEFAULT, + "s", + "nameOfUseMaterial", + "the name of the material that glows when active.", + EV_NORMAL +); +Event EV_UseObject_SetActiveState +( + "_setactivestate", + EV_DEFAULT, + NULL, + NULL, + "event that sets up the proper skin for the useobject.", + EV_NORMAL ); #define MULTI_STATE (1 << 0) @@ -1979,7 +2172,14 @@ Like info_waypoints, but with spawnflags for vehicles. ******************************************************************************/ -Event EV_VehiclePoint_SetSpawnFlags("spawnflags", EV_DEFAULT, "i", "spawn_flags", "Sets the spawn flags."); +Event EV_VehiclePoint_SetSpawnFlags +( + "spawnflags", + EV_DEFAULT, + "i", + "spawn_flags", + "Sets the spawn flags." +); CLASS_DECLARATION(Waypoint, VehiclePoint, "info_vehiclepoint") { {&EV_VehiclePoint_SetSpawnFlags, &VehiclePoint::SetSpawnFlags}, @@ -2061,11 +2261,16 @@ void HorizontalPipe::SetAngleEvent(Event *ev) // TossObject /*****************************************************************************/ -Event EV_TossObject_SetBounceSound( - "bouncesound", EV_DEFAULT, "s", "sound", "When bouncing, what sound to play on impact", EV_NORMAL +Event EV_TossObject_SetBounceSound +( + "bouncesound", EV_DEFAULT, + "s", + "sound", + "When bouncing, what sound to play on impact", + EV_NORMAL ); - -Event EV_TossObject_SetBounceSoundChance( +Event EV_TossObject_SetBounceSoundChance +( "bouncesoundchance", EV_DEFAULT, "f[0,1]", @@ -2206,11 +2411,35 @@ Pushable object ******************************************************************************/ -Event EV_PushObject_Start("start", EV_DEFAULT, NULL, NULL, "Sets up the pushobject.", EV_NORMAL); +Event EV_PushObject_Start +( + "start", + EV_DEFAULT, + NULL, + NULL, + "Sets up the pushobject.", + EV_NORMAL +); -Event EV_PushObject_SetDamage("dmg", EV_DEFAULT, "i", "damage", "Set the damage.", EV_NORMAL); +Event EV_PushObject_SetDamage +( + "dmg", + EV_DEFAULT, + "i", + "damage", + "Set the damage.", + EV_NORMAL +); -Event EV_PushObject_SetPushSound("pushsound", EV_DEFAULT, "s", "sound", "Set the pushing sound", EV_NORMAL); +Event EV_PushObject_SetPushSound +( + "pushsound", + EV_DEFAULT, + "s", + "sound", + "Set the pushing sound", + EV_NORMAL +); CLASS_DECLARATION(Entity, PushObject, "func_pushobject") { {&EV_PushObject_Start, &PushObject::Start }, @@ -2341,21 +2570,68 @@ REMOVE_ON_GROUND - remove the rocks when done ******************************************************************************/ -Event EV_FallingRock_Bounce("bounce", EV_DEFAULT, NULL, NULL, "sent to entity when touched.", EV_NORMAL); - -Event EV_FallingRock_Rotate("rotate", EV_DEFAULT, NULL, NULL, "rotates the falling rock.", EV_NORMAL); - -Event - EV_FallingRock_SetWait("wait", EV_DEFAULT, "f", "wait", "How long to wait before rock starts falling.", EV_NORMAL); - -Event EV_FallingRock_Start("start", EV_DEFAULT, NULL, NULL, "Starts rock falling.", EV_NORMAL); - -Event EV_FallingRock_SetDmg("dmg", EV_DEFAULT, "i", "dmg", "Set the damage from the rock.", EV_NORMAL); - -Event EV_FallingRock_SetSpeed("speed", EV_DEFAULT, "f", "speed", "Set the speed that the rock moves at.", EV_NORMAL); - -Event EV_FallingRock_SetBounceSound( - "noise", EV_DEFAULT, "s", "sound", "Set the sound to play when the rock bounces", EV_NORMAL +Event EV_FallingRock_Bounce +( + "bounce", + EV_DEFAULT, + NULL, + NULL, + "sent to entity when touched.", + EV_NORMAL +); +Event EV_FallingRock_Rotate +( + "rotate", + EV_DEFAULT, + NULL, + NULL, + "rotates the falling rock.", + EV_NORMAL +); +Event EV_FallingRock_SetWait +( + "wait", + EV_DEFAULT, + "f", + "wait", + "How long to wait before rock starts falling.", + EV_NORMAL +); +Event EV_FallingRock_Start +( + "start", + EV_DEFAULT, + NULL, + NULL, + "Starts rock falling.", + EV_NORMAL +); +Event EV_FallingRock_SetDmg +( + "dmg", + EV_DEFAULT, + "i", + "dmg", + "Set the damage from the rock.", + EV_NORMAL +); +Event EV_FallingRock_SetSpeed +( + "speed", + EV_DEFAULT, + "f", + "speed", + "Set the speed that the rock moves at.", + EV_NORMAL +); +Event EV_FallingRock_SetBounceSound +( + "noise", + EV_DEFAULT, + "s", + "sound", + "Set the sound to play when the rock bounces", + EV_NORMAL ); CLASS_DECLARATION(Entity, FallingRock, "func_fallingrock") { @@ -2622,7 +2898,14 @@ Ladder trigger volume ******************************************************************************/ -Event EV_LadderSetup("_ladder_setup", EV_CODEONLY, NULL, NULL, "Does the post spawn setup of the ladder"); +Event EV_LadderSetup +( + "_ladder_setup", + EV_CODEONLY, + NULL, + NULL, + "Does the post spawn setup of the ladder" +); CLASS_DECLARATION(Entity, FuncLadder, "func_ladder") { {&EV_Use, NULL }, @@ -2652,6 +2935,14 @@ void FuncLadder::LadderSetup(Event *ev) edict->r.svFlags |= SVF_NOCLIENT; } +void FuncLadder::SetLadderFacing(Event *ev) +{ + m_vFacingAngles = vec_zero; + m_vFacingAngles[1] = AngleMod(ev->GetFloat(1)); + + AngleVectorsLeft(m_vFacingAngles, m_vFacingDir, NULL, NULL); +} + qboolean FuncLadder::CanUseLadder(Entity *pUser) { int iMask; @@ -2764,14 +3055,6 @@ void FuncLadder::PositionOnLadder(Entity *pUser) pUser->setAngles(m_vFacingAngles); } -void FuncLadder::SetLadderFacing(Event *ev) -{ - m_vFacingAngles = vec_zero; - m_vFacingAngles[1] = AngleMod(ev->GetFloat(1)); - - AngleVectorsLeft(m_vFacingAngles, m_vFacingDir, NULL, NULL); -} - void FuncLadder::AdjustPositionOnLadder(Entity *pUser) { float fHeight; @@ -2872,8 +3155,24 @@ void FuncLadder::EnsureForwardOffLadder(Entity *pUser) pUser->setOrigin(trace.endpos); } -Event EV_InfoLandmark_Name("landmark_name", EV_DEFAULT, "s", "name", "Set the name of this landmark", EV_NORMAL); -Event EV_InfoLandmark_SetOrigin("origin", EV_DEFAULT, "v", "origin", "Set the origin of the landmark.", EV_NORMAL); +Event EV_InfoLandmark_Name +( + "landmark_name", + EV_DEFAULT, + "s", + "name", + "Set the name of this landmark", + EV_NORMAL +); +Event EV_InfoLandmark_SetOrigin +( + "origin", + EV_DEFAULT, + "v", + "origin", + "Set the origin of the landmark.", + EV_NORMAL +); CLASS_DECLARATION(Listener, InfoLandmark, "info_landmark") { {&EV_InfoLandmark_Name, &InfoLandmark::SetLandmarkName}, diff --git a/code/fgame/misc.h b/code/fgame/misc.h index f164c072..3edc142a 100644 --- a/code/fgame/misc.h +++ b/code/fgame/misc.h @@ -133,7 +133,7 @@ public: virtual void Teleport(Event *ev); virtual void StopTeleport(Event *ev); void SetThread(Event *ev); - void Archive(Archiver &arc) override; + void Archive(Archiver& arc) override; }; inline void Teleporter::Archive(Archiver& arc) @@ -488,7 +488,7 @@ private: Entity *SetNextBounceDir(void); void SetBounceSound(str sound); void SetBounceSound(Event *ev); - void Archive(Archiver &arc) override; + void Archive(Archiver& arc) override; public: CLASS_PROTOTYPE(FallingRock); @@ -564,8 +564,18 @@ public: void EnsureOverLadder(Entity *pUser); void EnsureForwardOffLadder(Entity *pUser); + + void Archive(Archiver& arc); }; +inline void FuncLadder::Archive(Archiver& arc) +{ + Entity::Archive(arc); + + arc.ArchiveVector(&m_vFacingAngles); + arc.ArchiveVector(&m_vFacingDir); +} + class InfoLandmark : public Listener { private: From ea6e865cc81054bc073de3c7e089308b881ad30d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:59:14 +0100 Subject: [PATCH 0194/2040] Added MASK_CLICKITEM --- code/fgame/bg_public.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index e9af867f..5d14c9a5 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -661,6 +661,7 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 \ | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY) #define MASK_CANSEE_NOENTS (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) +#define MASK_CLICKITEM (MASK_SOLID | CONTENTS_UNKNOWN3) #define MASK_ITEM (CONTENTS_SOLID | CONTENTS_TRIGGER | CONTENTS_PLAYERCLIP | CONTENTS_FENCE) #define MASK_TRANSITION (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) #define MASK_TARGETPATH \ From a0728b4a8a47c5f15d11a772520c5a4f74237850 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:59:46 +0100 Subject: [PATCH 0195/2040] Using MASK_CLICKITEM mask for ClickItemAttack --- code/fgame/weaputils.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index b8ed2239..7e1f5db5 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -1306,7 +1306,7 @@ void Projectile::SetOwner(Entity *owner) if (owner->IsSubclassOfPlayer()) { Player *p = (Player *)owner; m_iTeam = p->GetTeam(); - // Added in OPM + // Added in OPM // this was added to prevent glitches, like when the player // disconnects or when the player spectates m_bHadPlayerOwner = true; @@ -1804,7 +1804,7 @@ void PlaceLandmine(const Vector& origin, Entity *owner, const str& model, Weapon weap->m_iNumShotsFired++; if (owner && owner->IsSubclassOfPlayer() && weap->IsSubclassOfTurretGun()) { - Player* p = static_cast(owner); + Player *p = static_cast(owner); p->m_iNumShotsFired++; } } @@ -2585,30 +2585,37 @@ void FakeBulletAttack( void ClickItemAttack(Vector vStart, Vector vForward, float fRange, Entity *pOwner) { + Event *ev; Vector vEnd; trace_t trace; vEnd = vStart + vForward * fRange; - trace = G_Trace(vStart, vec_zero, vec_zero, vEnd, pOwner, MASK_ALL, qfalse, "ClickItemAttack"); + trace = G_Trace(vStart, vec_zero, vec_zero, vEnd, pOwner, MASK_CLICKITEM, qfalse, "ClickItemAttack"); if (g_showbullettrace->integer) { - G_DebugLine(vStart, vEnd, 1, 1, 1, 1); + //G_DebugLine(vStart, vEnd, 1, 1, 1, 1); + // Added in OPM + // White line between start and end trace position + G_DebugLine(vStart, trace.endpos, 1, 1, 1, 1); + G_DebugLine(trace.endpos, vEnd, 1, 0, 0, 1); } - if (trace.entityNum != ENTITYNUM_NONE && trace.ent && trace.ent->entity - && trace.ent->entity->isSubclassOf(TriggerClickItem)) { - Event *ev = new Event(EV_Activate); - ev->AddEntity(pOwner); - trace.ent->entity->PostEvent(ev, 0); - } else { + if (trace.entityNum == ENTITYNUM_WORLD || !trace.ent || !trace.ent->entity + || !trace.ent->entity->isSubclassOf(TriggerClickItem)) { ScriptThreadLabel failThread; // Try to execute a fail thread if (failThread.TrySet("clickitem_fail")) { failThread.Execute(); } + + return; } + + ev = new Event(EV_Activate); + ev->AddEntity(pOwner); + trace.ent->entity->PostEvent(ev, 0); } Projectile *HeavyAttack(Vector start, Vector dir, str projectileModel, float real_speed, Entity *owner, Weapon *weap) From 783bf1b63cabb912422e09891098574b889bc19e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:22:53 +0100 Subject: [PATCH 0196/2040] Archive ignorevelocity member --- code/fgame/scriptslave.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/scriptslave.h b/code/fgame/scriptslave.h index 9e1a6cfe..c37a133e 100644 --- a/code/fgame/scriptslave.h +++ b/code/fgame/scriptslave.h @@ -201,6 +201,7 @@ inline void ScriptSlave::Archive(Archiver& arc) arc.ArchiveFloat(&splineTime); arc.ArchiveBoolean(&splineangles); arc.ArchiveBoolean(&ignoreangles); + arc.ArchiveBoolean(&ignorevelocity); arc.ArchiveBoolean(&moving); if (arc.Saving()) { From b77f62ab58843f09874eb6db87ef9fb151b7fc0c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:23:15 +0100 Subject: [PATCH 0197/2040] Load/Save SimpleArchivedEntity This fixes #213 where elevator wouldn't go up because of missing waypoint --- code/fgame/g_main.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index 7218e4db..83561eae 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -1357,8 +1357,29 @@ qboolean G_ArchiveLevel(const char *filename, qboolean autosave, qboolean loadin } } + // + // simple archived entities + // + if (!arc.Loading()) { + num = level.m_SimpleArchivedEntities.NumObjects(); + } + arc.ArchiveInteger(&num); + + if (arc.Saving()) { + for (i = 1; i <= num; i++) { + arc.ArchiveObject(level.m_SimpleArchivedEntities.ObjectAt(i)); + } + } else { + for (i = 1; i <= num; i++) { + arc.ReadObject(); + } + } + ArchiveAliases(arc); + // Added in 2.0 + G_ArchiveSmokeSprites(arc); + currentArc = &arc; gi.ArchiveLevel(arc.Loading()); currentArc = NULL; From 4122ee41682ebcf6bc65b241cbc7f15980fb626b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:25:39 +0100 Subject: [PATCH 0198/2040] Fixed RunAndShoot state crash due to NULL moving patrol node (#214) --- code/fgame/actor_runandshoot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor_runandshoot.cpp b/code/fgame/actor_runandshoot.cpp index e8a82958..13088e82 100644 --- a/code/fgame/actor_runandshoot.cpp +++ b/code/fgame/actor_runandshoot.cpp @@ -125,7 +125,7 @@ bool Actor::RunAndShoot_MoveToPatrolCurrentNode(void) { UpdatePatrolCurrentNode(); - if (!m_patrolCurrentNode && m_bPatrolWaitTrigger) { + if (!m_patrolCurrentNode || m_bPatrolWaitTrigger) { IdleLook(); Anim_Idle(); return false; From 7b6a558fe5e82928489738d2669b7dce3d29db48 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:41:57 +0100 Subject: [PATCH 0199/2040] Check for valid turret gun in P_UserAim When the player dies, it gets detached from turret can would cause crash (#216) --- code/fgame/vehicleturret.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/fgame/vehicleturret.cpp b/code/fgame/vehicleturret.cpp index 674e95a6..1f03349d 100644 --- a/code/fgame/vehicleturret.cpp +++ b/code/fgame/vehicleturret.cpp @@ -386,7 +386,9 @@ void VehicleTurretGun::P_UserAim(usercmd_t *ucmd) Entity *slotEnt; slotEnt = pVehicle->QueryTurretSlotEntity(newSlot); - if (slotEnt->IsSubclassOfVehicleTurretGun()) { + // slotEnt check: + // Added in OPM + if (slotEnt && slotEnt->IsSubclassOfVehicleTurretGun()) { VehicleTurretGun *existing; Vector newAng; bool wasThisLocked, wasExistingLocked; From af829772f921950428faa11018ce17dd046c7cf9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:54:59 +0100 Subject: [PATCH 0200/2040] Cleaned up VSS_CalcRepulsionForces and fixed vss index --- code/cgame/cg_volumetricsmoke.cpp | 467 +++++++++++++++--------------- 1 file changed, 234 insertions(+), 233 deletions(-) diff --git a/code/cgame/cg_volumetricsmoke.cpp b/code/cgame/cg_volumetricsmoke.cpp index 33cf3769..ed0f0d57 100644 --- a/code/cgame/cg_volumetricsmoke.cpp +++ b/code/cgame/cg_volumetricsmoke.cpp @@ -42,7 +42,9 @@ const char *cg_vsstypes[] = { "debris" }; -cvssource_t *vss_sorttable[16384]; +#define MAX_VSS_SORTS 16384 + +cvssource_t *vss_sorttable[MAX_VSS_SORTS]; static int lastVSSFrameTime; static constexpr float MAX_VSS_COORDS = 8096.0; @@ -890,251 +892,250 @@ void VSS_CalcRepulsionForces(cvssource_t *pActiveSources) { cvssource_t *pCurrent; cvssource_t *pComp; + qboolean bXUp, bXDown; + qboolean bYUp, bYDown; + qboolean bZDown; + int i; + int iIndex; + int iX, iY, iZ; + int iMinX, iMinY, iMinZ; + int iMaxX, iMaxY, iMaxZ; + float fOfs; + cvssource_t *pSTLatch; pCurrent = pActiveSources->prev; - if (pCurrent != pActiveSources) { - qboolean bXUp, bXDown; - qboolean bYUp, bYDown; - qboolean bZDown; - int i; - int iIndex; - int iX, iY, iZ; - int iMinX, iMinY, iMinZ; - int iMaxX, iMaxY, iMaxZ; - float fOfs; - cvssource_t *pSTLatch; + if (pCurrent == pActiveSources) { + return; + } - memset(vss_sorttable, 0, sizeof(vss_sorttable)); + memset(vss_sorttable, 0, sizeof(vss_sorttable)); - while (pCurrent != pActiveSources) { - VectorClear(pCurrent->repulsion); + for (pCurrent = pActiveSources->prev; pCurrent != pActiveSources; pCurrent = pCurrent->prev) { + VectorClear(pCurrent->repulsion); - iIndex = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5) / 96) % 32; - iIndex |= ((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5) / 96) % 32; - iIndex |= (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5) / 96) % 16) << 10; + iIndex = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5) / 96) % 32; + iIndex |= (((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5) / 96) % 32) << 5; + iIndex |= (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5) / 96) % 16) << 10; - pCurrent->stnext = vss_sorttable[iIndex]; - vss_sorttable[iIndex] = pCurrent; - pCurrent->stindex = iIndex; - pCurrent = pCurrent->prev; + pCurrent->stnext = vss_sorttable[iIndex]; + vss_sorttable[iIndex] = pCurrent; + pCurrent->stindex = iIndex; + } + + for (pCurrent = pActiveSources->prev; pCurrent != pActiveSources; pCurrent = pCurrent->prev) { + if (vss_sorttable[pCurrent->stindex] == pCurrent) { + pSTLatch = (cvssource_t *)-1; + pComp = pCurrent->stnext; + } else { + pSTLatch = 0; + pComp = vss_sorttable[pCurrent->stindex]; } - for (pCurrent = pActiveSources->prev; pCurrent != pActiveSources; pCurrent = pCurrent->prev) { - if (vss_sorttable[pCurrent->stindex] == pCurrent) { - pSTLatch = (cvssource_t *)-1; - pComp = pCurrent->stnext; - } else { - pSTLatch = 0; - pComp = vss_sorttable[pCurrent->stindex]; + while (pComp) { + VSS_AddRepulsion(pCurrent, pComp); + if (!pSTLatch && pComp->stnext == pCurrent) { + pSTLatch = pComp; + pComp = pComp->stnext; } - while (pComp) { + pComp = pComp->stnext; + } + + iX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5) / 96) % 32; + iY = (((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5) / 96) % 32) << 5; + iZ = (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5) / 96) % 16) << 10; + + fOfs = pCurrent->newRadius + 1.49 + 48.0; + iMaxX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5 + fOfs) / 96) % 32; + iMaxY = (((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5 + fOfs) / 96) % 32) << 5; + iMaxZ = (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5 + fOfs) / 96) % 16) << 10; + + iMinX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5 - fOfs) / 96) % 32; + iMinY = (((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5 - fOfs) / 96) % 32) << 5; + iMinZ = (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5 - fOfs) / 96) % 16) << 10; + + bXUp = (iMaxX | (pCurrent->stindex & 0xFFFFFFE0)) != pCurrent->stindex; + bXDown = (iMinX | (pCurrent->stindex & 0xFFFFFFE0)) != pCurrent->stindex; + bYUp = (iMaxY | (pCurrent->stindex & 0xFFFFFC1F)) != pCurrent->stindex; + bYDown = (iMinY | (pCurrent->stindex & 0xFFFFFC1F)) != pCurrent->stindex; + + iIndex = iMinZ | (pCurrent->stindex & 0xFFFFC3FF); + bZDown = iIndex != pCurrent->stindex; + + if (iIndex == pCurrent->stindex) { + iIndex = iMaxY | (pCurrent->stindex & 0xFFFFFC1F); + + i = 9; + } else { + i = 0; + } + + for (; i < (bZDown ? 26 : 17); i++) { + switch (i) { + case 0: + iIndex = iMaxZ | (pCurrent->stindex & 0xFFFFC3FF); + break; + case 1: + iIndex = iMaxX | (iIndex & 0xFFFFFFE0); + if (bXUp) { + break; + } + continue; + case 2: + iIndex = iMaxY | (iIndex & 0xFFFFFC1F); + if (bXUp && bYUp) { + break; + } + continue; + case 3: + iIndex = iMinY | (iIndex & 0xFFFFFC1F); + if (bXUp && bYDown) { + break; + } + continue; + case 4: + iIndex = iMinY | (iIndex & 0xFFFFFFE0); + if (bYDown) { + break; + } + continue; + case 5: + iIndex = iMinX | (iIndex & 0xFFFFFFE0); + if (bXDown && bYDown) { + break; + } + continue; + case 6: + iIndex = iY | (iIndex & 0xFFFFFC1F); + if (bXDown) { + break; + } + continue; + case 7: + iIndex = iMaxY | (iIndex & 0xFFFFFC1F); + if (bXDown && bYUp) { + break; + } + continue; + case 8: + iIndex = iX | (iIndex & 0xFFFFFFE0); + if (bYUp) { + break; + } + continue; + case 9: + iIndex = iZ | (iIndex & 0xFFFFFFC3); + if (bYUp) { + break; + } + continue; + case 10: + iIndex = iMaxX | (iIndex & 0xFFFFFFE0); + if (bXUp && bYUp) { + break; + } + continue; + case 11: + iIndex = iMinX | (iIndex & 0xFFFFFFE0); + if (bXDown && bYUp) { + break; + } + continue; + case 12: + iIndex = iY | (iIndex & 0xFFFFFC1F); + if (bXDown) { + break; + } + continue; + case 13: + iIndex = iMinY | (iIndex & 0xFFFFFC1F); + if (bXDown && bYDown) { + break; + } + continue; + case 14: + iIndex = iX | (iIndex & 0xFFFFFFE0); + if (bYDown) { + break; + } + continue; + case 15: + iIndex = iMaxX | (iIndex & 0xFFFFFFE0); + if (bXUp && bYDown) { + break; + } + continue; + case 16: + iIndex = iY | (iIndex & 0xFFFFFC1F); + if (bXUp) { + break; + } + continue; + case 17: + iIndex = iMinZ | (iIndex & 0xFFFFFCC3); + if (bXUp) { + break; + } + continue; + case 18: + iIndex = iMaxY | (iIndex & 0xFFFFFC1F); + if (bXUp && bYUp) { + break; + } + continue; + case 19: + iIndex = iMinY | (iIndex & 0xFFFFFC1F); + if (bXUp && bYDown) { + break; + } + continue; + case 20: + iIndex = iX | (iIndex & 0xFFFFFFE0); + if (bYDown) { + break; + } + continue; + case 21: + iIndex = iMinX | (iIndex & 0xFFFFFFE0); + if (bXDown && bYDown) { + break; + } + continue; + case 22: + iIndex = iY | (iIndex & 0xFFFFFC1F); + if (bXDown) { + break; + } + continue; + case 23: + iIndex = iMaxY | (iIndex & 0xFFFFFC1F); + if (bXDown && bYUp) { + break; + } + continue; + case 24: + iIndex = iX | (iIndex & 0xFFFFFFE0); + if (bYUp) { + break; + } + continue; + case 25: + iIndex = iY | (iIndex & 0xFFFFFC1F); + break; + default: + assert(0); // This can't happen + break; + } + + for (pComp = vss_sorttable[iIndex]; pComp; pComp = pComp->stnext) { VSS_AddRepulsion(pCurrent, pComp); - if (!pSTLatch && pComp->stnext == pCurrent) { - pSTLatch = pComp; - pComp = pComp->stnext; - } - - pComp = pComp->stnext; } - iX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5) / 96) % 32; - iY = ((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5) / 96) % 32; - iY *= 2; - iZ = ((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5) / 96) % 16; - iZ <<= 10; + } - fOfs = pCurrent->newRadius + 1.49 + 48.0; - iMaxX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5 + fOfs) / 96) % 32; - iMaxY = ((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5 + fOfs) / 96) % 32; - iMaxY *= 2; - iMaxZ = ((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5 + fOfs) / 96) % 16; - iMaxZ <<= 10; - - iMinX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5 - fOfs) / 96) % 32; - iMinY = ((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5 - fOfs) / 96) % 32; - iMinY *= 2; - iMinZ = ((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5 - fOfs) / 96) % 16; - iMinZ <<= 10; - - bXUp = (iMaxX | (pCurrent->stindex & 0xFFFFFFE0)) != pCurrent->stindex; - bXDown = (iMinX | (pCurrent->stindex & 0xFFFFFFE0)) != pCurrent->stindex; - bYUp = (iMaxY | (pCurrent->stindex & 0xFFFFFC1F)) != pCurrent->stindex; - bYDown = (iMinY | (pCurrent->stindex & 0xFFFFFC1F)) != pCurrent->stindex; - - iIndex = iMinZ | (pCurrent->stindex & 0xFFFFFCC3); - bZDown = iIndex != pCurrent->stindex; - - if (iIndex == pCurrent->stindex) { - iIndex = iMaxY | pCurrent->stindex & 0xFFFFFC1F; - i = 9; - } else { - i = 0; - } - - for(; i < (bZDown ? 26 : 17); i++) { - switch (i) { - case 0: - iIndex = iMaxZ | (pCurrent->stindex & 0xFFFFFCC3); - break; - case 1: - iIndex = iMaxX | (iIndex & 0xFFFFFFE0); - if (bXUp) { - break; - } - continue; - case 2: - iIndex = iMaxY | (iIndex & 0xFFFFFC1F); - if (bXUp && bYUp) { - break; - } - continue; - case 3: - iIndex = iMinY | (iIndex & 0xFFFFFC1F); - if (bXUp && bYDown) { - break; - } - continue; - case 4: - iIndex = iMinY | (iIndex & 0xFFFFFFE0); - if (bYDown) { - break; - } - continue; - case 5: - iIndex = iMinX | (iIndex & 0xFFFFFFE0); - if (bXDown && bYDown) { - break; - } - continue; - case 6: - iIndex = iY | (iIndex & 0xFFFFFC1F); - if (bXDown) { - break; - } - continue; - case 7: - iIndex = iMaxY | (iIndex & 0xFFFFFC1F); - if (bXDown && bYUp) { - break; - } - continue; - case 8: - iIndex = iX | (iIndex & 0xFFFFFFE0); - if (bYUp) { - break; - } - continue; - case 9: - iIndex = iZ | (iIndex & 0xFFFFFFC3); - if (bYUp) { - break; - } - continue; - case 10: - iIndex = iMaxX | (iIndex & 0xFFFFFFE0); - if (bXUp && bYUp) { - break; - } - continue; - case 11: - iIndex = iMinX | (iIndex & 0xFFFFFFE0); - if (bXDown && bYUp) { - break; - } - continue; - case 12: - iIndex = iY | (iIndex & 0xFFFFFC1F); - if (bXDown) { - break; - } - continue; - case 13: - iIndex = iMinY | (iIndex & 0xFFFFFC1F); - if (bXDown && bYDown) { - break; - } - continue; - case 14: - iIndex = iX | (iIndex & 0xFFFFFFE0); - if (bYDown) { - break; - } - continue; - case 15: - iIndex = iMaxX | (iIndex & 0xFFFFFFE0); - if (bXUp && bYDown) { - break; - } - continue; - case 16: - iIndex = iY | (iIndex & 0xFFFFFC1F); - if (bXUp) { - break; - } - continue; - case 17: - iIndex = iMinZ | (iIndex & 0xFFFFFCC3); - if (bXUp) { - break; - } - continue; - case 18: - iIndex = iMaxY | (iIndex & 0xFFFFFC1F); - if (bXUp && bYUp) { - break; - } - continue; - case 19: - iIndex = iMinY | (iIndex & 0xFFFFFC1F); - if (bXUp && bYDown) { - break; - } - continue; - case 20: - iIndex = iX | (iIndex & 0xFFFFFFE0); - if (bYDown) { - break; - } - continue; - case 21: - iIndex = iMinX | (iIndex & 0xFFFFFFE0); - if (bXDown && bYDown) { - break; - } - continue; - case 22: - iIndex = iY | (iIndex & 0xFFFFFC1F); - if (bXDown) { - break; - } - continue; - case 23: - iIndex = iMaxY | (iIndex & 0xFFFFFC1F); - if (bXDown && bYUp) { - break; - } - continue; - case 24: - iIndex = iX | (iIndex & 0xFFFFFFE0); - if (bYUp) { - break; - } - continue; - case 25: - iIndex = iY | (iIndex & 0xFFFFFC1F); - break; - } - - for (pComp = vss_sorttable[iIndex]; pComp; pComp = pComp->stnext) { - VSS_AddRepulsion(pCurrent, pComp); - } - } - - if (pSTLatch == (cvssource_t *)-1) { - vss_sorttable[pCurrent->stindex] = pCurrent->stnext; - } else { - pSTLatch->stnext = pCurrent->stnext; - } + if (pSTLatch == (cvssource_t *)-1) { + vss_sorttable[pCurrent->stindex] = pCurrent->stnext; + } else { + pSTLatch->stnext = pCurrent->stnext; } } } From 66fcc2cd14d9268fa04c665d2996ecda650972b6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 19:52:11 +0100 Subject: [PATCH 0201/2040] Cleaned up VSS_AddRepulsion --- code/cgame/cg_volumetricsmoke.cpp | 112 +++++++++++++++--------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/code/cgame/cg_volumetricsmoke.cpp b/code/cgame/cg_volumetricsmoke.cpp index ed0f0d57..05dc4712 100644 --- a/code/cgame/cg_volumetricsmoke.cpp +++ b/code/cgame/cg_volumetricsmoke.cpp @@ -80,56 +80,57 @@ void VSS_AddRepulsion(cvssource_t *pA, cvssource_t *pB) VectorSubtract(pA->newOrigin, pB->newOrigin, vPush); - if (vPush[0] || vPush[1] || vPush[2]) { - fDist = VectorNormalize(vPush); - f = fDist - pB->newRadius; - - if (f > 0.0) { - f *= pA->ooRadius; - if (f > 1.49) { - f = 0.0; - } else { - f = f * (f * 0.0161 + -0.3104) + 1.2887; - } - - if (f < 0.0) { - f = f * 1.1; - } - - fForce = f; - } else { - fForce = 1.0; - } - - f = fDist - pA->newRadius; - if (f > 0.0) { - f *= pB->ooRadius; - if (f > 1.49) { - f = 0.0; - } else { - f = f * (f * 0.0161 + -0.3104) + 1.2887; - } - - if (f < 0.0) { - f = f * 1.1; - } - - fForce += f; - } else { - fForce += 1.0; - } - - if (fForce <= -0.05 && fForce >= 0.05) { - fForce = (pA->newRadius + pB->newRadius) * 0.03 * fForce; - VectorScale(vPush, fForce, vPush); - - VectorAdd(pA->repulsion, vPush, pA->repulsion); - VectorSubtract(pB->repulsion, vPush, pB->repulsion); - } - } else { + if (!vPush[0] && !vPush[1] && !vPush[2]) { VectorSet(vPush, crandom(), crandom(), crandom()); VectorAdd(pA->repulsion, vPush, pA->repulsion); VectorSubtract(pB->repulsion, vPush, pB->repulsion); + return; + } + + fDist = VectorNormalize(vPush); + f = fDist - pB->newRadius; + + if (f > 0.0f) { + f *= pA->ooRadius; + if (f > 1.49f) { + f = 0.0f; + } else { + f = f * (f * 0.0161f + -0.3104f) + 1.2887f; + } + + if (f < 0.0) { + f *= 1.1f; + } + + fForce = f; + } else { + fForce = 1.0; + } + + f = fDist - pA->newRadius; + if (f > 0.0) { + f *= pB->ooRadius; + if (f > 1.49f) { + f = 0.0f; + } else { + f = f * (f * 0.0161f + -0.3104f) + 1.2887f; + } + + if (f < 0.0) { + f *= 1.1f; + } + + fForce += f; + } else { + fForce += 1.0f; + } + + if (fForce <= -0.05f || fForce >= 0.05f) { + fForce = (pA->newRadius + pB->newRadius) * 0.03f * fForce; + VectorScale(vPush, fForce, vPush); + + VectorAdd(pA->repulsion, vPush, pA->repulsion); + VectorSubtract(pB->repulsion, vPush, pB->repulsion); } } @@ -931,14 +932,13 @@ void VSS_CalcRepulsionForces(cvssource_t *pActiveSources) pComp = vss_sorttable[pCurrent->stindex]; } - while (pComp) { + for(; pComp; pComp = pComp->stnext) { VSS_AddRepulsion(pCurrent, pComp); if (!pSTLatch && pComp->stnext == pCurrent) { pSTLatch = pComp; + // skip current pComp = pComp->stnext; } - - pComp = pComp->stnext; } iX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5) / 96) % 32; @@ -946,13 +946,13 @@ void VSS_CalcRepulsionForces(cvssource_t *pActiveSources) iZ = (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5) / 96) % 16) << 10; fOfs = pCurrent->newRadius + 1.49 + 48.0; - iMaxX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5 + fOfs) / 96) % 32; - iMaxY = (((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5 + fOfs) / 96) % 32) << 5; - iMaxZ = (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5 + fOfs) / 96) % 16) << 10; + iMaxX = ((int)floor(pCurrent->newOrigin[0] + fOfs + 8192.0 + 0.5) / 96) % 32; + iMaxY = (((int)floor(pCurrent->newOrigin[1] + fOfs + 8192.0 + 0.5) / 96) % 32) << 5; + iMaxZ = (((int)floor(pCurrent->newOrigin[2] + fOfs + 8192.0 + 0.5) / 96) % 16) << 10; - iMinX = ((int)floor(pCurrent->newOrigin[0] + 8192.0 + 0.5 - fOfs) / 96) % 32; - iMinY = (((int)floor(pCurrent->newOrigin[1] + 8192.0 + 0.5 - fOfs) / 96) % 32) << 5; - iMinZ = (((int)floor(pCurrent->newOrigin[2] + 8192.0 + 0.5 - fOfs) / 96) % 16) << 10; + iMinX = ((int)floor(pCurrent->newOrigin[0] - fOfs + 8192.0 + 0.5) / 96) % 32; + iMinY = (((int)floor(pCurrent->newOrigin[1] - fOfs + 8192.0 + 0.5) / 96) % 32) << 5; + iMinZ = (((int)floor(pCurrent->newOrigin[2] - fOfs + 8192.0 + 0.5) / 96) % 16) << 10; bXUp = (iMaxX | (pCurrent->stindex & 0xFFFFFFE0)) != pCurrent->stindex; bXDown = (iMinX | (pCurrent->stindex & 0xFFFFFFE0)) != pCurrent->stindex; From 6b6e2c947c30328f76158b652511ac7ba64060ed Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 19:53:08 +0100 Subject: [PATCH 0202/2040] Fixed vNorm not being initializing causing crashes on rare occasions This should fix #169 --- code/cgame/cg_volumetricsmoke.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/cgame/cg_volumetricsmoke.cpp b/code/cgame/cg_volumetricsmoke.cpp index 05dc4712..df318139 100644 --- a/code/cgame/cg_volumetricsmoke.cpp +++ b/code/cgame/cg_volumetricsmoke.cpp @@ -337,6 +337,8 @@ qboolean VSS_SourcePhysics(cvssource_t *pSource, float ftime) float fDot; vec3_t vNorm; + VectorCopy(trace.plane.normal, vNorm); + VectorAdd(trace.endpos, trace.plane.normal, pSource->newOrigin); fDot = DotProduct(vNorm, pSource->velocity); VectorMA(pSource->velocity, fDot, vNorm, pSource->velocity); From cbe6d85bcd9de6876e137249f8d865d34b6da95a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:44:55 +0100 Subject: [PATCH 0203/2040] Added multiple cache per entity --- code/tiki/tiki_cache.cpp | 45 +++++++++++++++++++++++++++++----------- code/tiki/tiki_shared.h | 4 ++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/code/tiki/tiki_cache.cpp b/code/tiki/tiki_cache.cpp index 6dea190b..4fbf5aa3 100644 --- a/code/tiki/tiki_cache.cpp +++ b/code/tiki/tiki_cache.cpp @@ -42,7 +42,7 @@ struct pchar { con_map *tikianimcache; con_map *tikicache; -static skeletor_c *skel_entity_cache[1024]; +static skeletor_c *skel_entity_cache[TIKI_MAX_ENTITY_CACHE]; template<> int HashCode(const pchar& key) @@ -300,6 +300,8 @@ static qboolean tiki_started; void *TIKI_GetSkeletor(dtiki_t *tiki, int entnum) { skeletor_c *skel; + int i; + int index; if (entnum == ENTITYNUM_NONE) { if (!tiki->skeletor) { @@ -307,17 +309,34 @@ void *TIKI_GetSkeletor(dtiki_t *tiki, int entnum) } skel = (skeletor_c *)tiki->skeletor; } else { - skel = skel_entity_cache[entnum]; - if (skel) { - if (skel->m_Tiki == tiki) { - return skel_entity_cache[entnum]; + // Added in 2.30 + // Multiple caches per entity + for (i = 0; i < TIKI_MAX_ENTITY_CACHE_PER_ENT; i++) { + index = ((entnum % TIKI_MAX_ENTITIES) * TIKI_MAX_ENTITY_CACHE_PER_ENT) + i; + + skel = skel_entity_cache[index]; + if (!skel) { + break; } + if (skel->m_Tiki == tiki) { + return skel; + } + } + + if (i == TIKI_MAX_ENTITY_CACHE_PER_ENT) { + i = 0; + } + + index = ((entnum % TIKI_MAX_ENTITIES) * TIKI_MAX_ENTITY_CACHE_PER_ENT) + i; + skel = skel_entity_cache[index]; + + if (skel) { delete skel; } skel = new skeletor_c(tiki); - skel_entity_cache[entnum] = skel; + skel_entity_cache[index] = skel; } return skel; @@ -331,15 +350,17 @@ TIKI_DeleteSkeletor static void TIKI_DeleteSkeletor(int entnum) { skeletor_c *skel; + int i; if (entnum == ENTITYNUM_NONE) { return; } - skel = skel_entity_cache[entnum]; - if (skel) { - delete skel; - skel_entity_cache[entnum] = 0; + for (i = 0; i < TIKI_MAX_ENTITY_CACHE_PER_ENT; i++) { + skel = skel_entity_cache[entnum * TIKI_MAX_ENTITY_CACHE_PER_ENT + i]; + if (skel) { + delete skel; + } } } @@ -352,7 +373,7 @@ void TIKI_Begin(void) { int i; - for (i = 0; i < TIKI_MAX_SKELCACHE; i++) { + for (i = 0; i < MAX_GENTITIES; i++) { skel_entity_cache[i] = 0; } @@ -368,7 +389,7 @@ void TIKI_End(void) { int i; - for (i = 0; i < TIKI_MAX_SKELCACHE; i++) { + for (i = 0; i < MAX_GENTITIES; i++) { TIKI_DeleteSkeletor(i); } diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index ed40b76e..763054bc 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -77,6 +77,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define TIKI_MAX_SKELCACHE 1024 #define TIKI_MAX_COMMANDS 128 +#define TIKI_MAX_ENTITIES 2048 +#define TIKI_MAX_ENTITY_CACHE_PER_ENT 2 +#define TIKI_MAX_ENTITY_CACHE (TIKI_MAX_ENTITIES*TIKI_MAX_ENTITY_CACHE_PER_ENT) + // tiki surface flags #define TIKI_SURF_SKIN1 (1 << 0) #define TIKI_SURF_SKIN2 (1 << 1) From 8af5da5fca424b8aed4b7d74fb81b5c1f2fa53fe Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:45:05 +0100 Subject: [PATCH 0204/2040] tiki assert check --- code/server/sv_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 3c2f0c4c..05d4dc1e 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -991,6 +991,7 @@ PF_SetPoseInternal */ void PF_SetPoseInternal( dtiki_t *tiki, int entnum, const frameInfo_t *frameInfo, int *bone_tag, vec4_t *bone_quat, float actionWeight ) { + assert(tiki); TIKI_SetPoseInternal( TIKI_GetSkeletor( tiki, entnum ), frameInfo, bone_tag, bone_quat, actionWeight ); } From b76f9a9a6cf8aa950465b4874530ef4390588881 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:42:34 +0100 Subject: [PATCH 0205/2040] Fixed skel_entity_cache initialization --- code/tiki/tiki_cache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/tiki/tiki_cache.cpp b/code/tiki/tiki_cache.cpp index 4fbf5aa3..05d29b51 100644 --- a/code/tiki/tiki_cache.cpp +++ b/code/tiki/tiki_cache.cpp @@ -373,7 +373,7 @@ void TIKI_Begin(void) { int i; - for (i = 0; i < MAX_GENTITIES; i++) { + for (i = 0; i < TIKI_MAX_ENTITY_CACHE; i++) { skel_entity_cache[i] = 0; } From 8b2b1a9a47cae874ccc863afbcc366560ad967e9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:42:54 +0100 Subject: [PATCH 0206/2040] S_AddLoopingSound: ignore null sfx handle --- code/client/new/snd_main_new.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index 3490119d..c6ba1b66 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -52,6 +52,10 @@ S_AddLoopingSound */ void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags) { + if (!sfxHandle) { + return; + } + // FIXME: unimplemented S_AddLoopingSound(ENTITYNUM_WORLD, origin, velocity, sfxHandle); } From 7945c2ca6633e181fdc73426553a30d7e2d38e2f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:57:02 +0100 Subject: [PATCH 0207/2040] Fixed target's m_Team accidentally being overwritten This causes NPC to look invulnerable (fixes #238) --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index e7344e3d..805dfd90 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -8936,7 +8936,7 @@ void Actor::WeaponSound(int iType, vec3_t sound_origin, float fDistSquared, floa if (pActor->m_Think[THINKLEVEL_IDLE] == THINK_MACHINEGUNNER && pWeapon->aim_target) { if (pWeapon->aim_target->IsSubclassOfSentient()) { Sentient *pTarget = static_cast(pWeapon->aim_target.Pointer()); - if (pTarget->m_Team = m_Team) { + if (pTarget->m_Team == m_Team) { pEnemy = pTarget; } } else if (!m_Team) { From b0c1d791320c1cf4f427b4eeaf6f0119b4e76cdd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:19:24 +0100 Subject: [PATCH 0208/2040] Fixed AI mg42 fire delay --- code/fgame/weapon.h | 12 ++++++------ code/fgame/weapturret.cpp | 16 +++++++++++----- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/code/fgame/weapon.h b/code/fgame/weapon.h index e5f223b9..769f67f7 100644 --- a/code/fgame/weapon.h +++ b/code/fgame/weapon.h @@ -399,12 +399,12 @@ public: virtual void GetMuzzlePosition( vec3_t position, vec3_t vBarrelPos = NULL, vec3_t forward = NULL, vec3_t right = NULL, vec3_t up = NULL ); - qboolean AutoChange(void); - int ClipAmmo(firemode_t mode); - qboolean IsDroppable(void); - float FireDelay(firemode_t mode); - void SetFireDelay(Event *ev); - void SetDMFireDelay(Event *ev); + qboolean AutoChange(void); + int ClipAmmo(firemode_t mode); + qboolean IsDroppable(void); + virtual float FireDelay(firemode_t mode); + virtual void SetFireDelay(Event *ev); + void SetDMFireDelay(Event *ev); weaponstate_t GetState(void); void ForceState(weaponstate_t state); diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index 0a96c220..dfff9acd 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -1266,6 +1266,10 @@ void TurretGun::AI_DoFiring() void TurretGun::AI_ThinkActive() { + if (!g_ai->integer) { + return; + } + AI_DoAiming(); AI_DoFiring(); } @@ -1917,16 +1921,18 @@ void TurretGun::StopWeaponAnim(void) float TurretGun::FireDelay(firemode_t mode) { - if (owner && owner->IsSubclassOfPlayer()) { - return 0.06f; - } else { - return Weapon::FireDelay(mode); - } + return fire_delay[FIRE_PRIMARY]; } void TurretGun::SetFireDelay(Event *ev) { fire_delay[FIRE_PRIMARY] = ev->GetFloat(1); + if (!m_fMaxBurstTime) { + // Added in OPM + // default values if not set + m_fMaxBurstTime = m_fMinBurstTime = 0.001f; + m_fMaxBurstDelay = m_fMinBurstDelay = fire_delay[FIRE_PRIMARY]; + } } void TurretGun::ShowInfo(float fDot, float fDist) From 61f0fc665fef1c34adbd0836f123c5a3e431ab80 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:29:47 +0100 Subject: [PATCH 0209/2040] Fixed MG42 reload anim name --- code/fgame/scriptmaster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/scriptmaster.cpp b/code/fgame/scriptmaster.cpp index 56a1b9d8..c7730709 100644 --- a/code/fgame/scriptmaster.cpp +++ b/code/fgame/scriptmaster.cpp @@ -230,7 +230,7 @@ const char *ScriptMaster::ConstStrings[] = { "anim/shoot.scr", "anim/mg42_shoot.scr", "anim/mg42_idle.scr", - "anim_mg42_reload.scr", + "anim/mg42_reload.scr", "drive", "global/weapon.scr", "global/moveto.scr", From b0180383dfac59d93f194f8842fb8ff3b1d335cc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:37:49 +0100 Subject: [PATCH 0210/2040] Fixed FFA scores This fixes #242 --- code/fgame/dm_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/dm_manager.cpp b/code/fgame/dm_manager.cpp index 6125e0c1..1915b26e 100644 --- a/code/fgame/dm_manager.cpp +++ b/code/fgame/dm_manager.cpp @@ -1871,7 +1871,7 @@ void DM_Manager::BuildTeamInfo_ver6(DM_Team *dmTeam) Com_sprintf(entry, sizeof(entry), "%i %i \"\" \"\" \"\" \"\" ", -1, dmTeam->m_teamnumber); } } else { - Com_sprintf(entry, sizeof(entry), "%i \"\" \"\" \"\" \"\" \"\" ", -1 - dmTeam->m_teamnumber); + Com_sprintf(entry, sizeof(entry), "%i \"\" \"\" \"\" \"\" ", -1 - dmTeam->m_teamnumber); } InsertEntry(entry); From e55f5902d55c5c576b7b3cba497800e269fee5d4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:12:05 +0100 Subject: [PATCH 0211/2040] Avoid using constant values --- code/cgame/cg_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 5c74c473..ab3c46ee 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -154,9 +154,9 @@ void CG_RegisterCvars(void) cg_shadowdebug = cgi.Cvar_Get("cg_shadowdebug", "0", 0); developer = cgi.Cvar_Get("developer", "0", 0); dm_playermodel = cgi.Cvar_Get("dm_playermodel", "american_army", 3); - dm_playergermanmodel = cgi.Cvar_Get("dm_playergermanmodel", "german_wehrmacht_soldier", 3); + dm_playergermanmodel = cgi.Cvar_Get("dm_playergermanmodel", "german_wehrmacht_soldier", CVAR_ARCHIVE | CVAR_USERINFO); cg_forceModel = cgi.Cvar_Get("cg_forceModel", "0", CVAR_ARCHIVE); - cg_animationviewmodel = cgi.Cvar_Get("cg_animationviewmodel", "0", 8); + cg_animationviewmodel = cgi.Cvar_Get("cg_animationviewmodel", "0", CVAR_SYSTEMINFO); cg_hitmessages = cgi.Cvar_Get("cg_hitmessages", "1", CVAR_ARCHIVE); cg_acidtrip = cgi.Cvar_Get("cg_acidtrip", "0", CVAR_CHEAT); cg_hud = cgi.Cvar_Get("cg_hud", "0", 0); From 65d3a51a171485ef45493ffc3e306ea4c00076d7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:12:14 +0100 Subject: [PATCH 0212/2040] Use '\n' instead of 10 --- code/client/cl_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 8d63814e..0e0dbd46 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -1486,7 +1486,7 @@ void CL_SendPureChecksums( void ) { Q_strcat(cMsg, sizeof(cMsg), va("%d ", cl.serverId) ); Q_strcat(cMsg, sizeof(cMsg), pChecksums); for (i = 0; i < 2; i++) { - cMsg[i] += 10; + cMsg[i] += '\n'; } CL_AddReliableCommand( cMsg, qfalse ); } From 416c568c5144d03fd794ef1a67b93daee708fb64 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:13:08 +0100 Subject: [PATCH 0213/2040] Make CVAR_ROM variables appear first in info strings --- code/qcommon/cvar.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/code/qcommon/cvar.c b/code/qcommon/cvar.c index f05ae523..0e79aef2 100644 --- a/code/qcommon/cvar.c +++ b/code/qcommon/cvar.c @@ -1411,9 +1411,16 @@ char *Cvar_InfoString(int bit) info[0] = 0; + // start with read-only variable so they appear first + for (var = cvar_vars; var; var = var->next) + { + if (var->name && (var->flags & bit) && (var->flags & CVAR_ROM)) + Info_SetValueForKey(info, var->name, var->string); + } + for(var = cvar_vars; var; var = var->next) { - if(var->name && (var->flags & bit)) + if (var->name && (var->flags & bit) && !(var->flags & CVAR_ROM)) Info_SetValueForKey (info, var->name, var->string); } @@ -1434,9 +1441,16 @@ char *Cvar_InfoString_Big(int bit) info[0] = 0; + // start with read-only variable so they appear first for (var = cvar_vars; var; var = var->next) { - if(var->name && (var->flags & bit)) + if (var->name && (var->flags & bit) && (var->flags & CVAR_ROM)) + Info_SetValueForKey(info, var->name, var->string); + } + + for (var = cvar_vars; var; var = var->next) + { + if (var->name && (var->flags & bit) && !(var->flags & CVAR_ROM)) Info_SetValueForKey_Big (info, var->name, var->string); } return info; From bb4b10d752c2555d1808b3d08090e01f45f74d29 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:13:24 +0100 Subject: [PATCH 0214/2040] Use result from Cvar_InfoString_Big for CS_SYSTEMINFO --- code/server/sv_init.c | 2 +- code/server/sv_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 1d883a3d..40209cd7 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -854,7 +854,7 @@ void SV_SpawnServer( const char *server, qboolean loadgame, qboolean restart, qb Cvar_Set( "sv_referencedPakNames", p ); // save systeminfo and serverinfo strings - Q_strncpyz( systemInfo, Cvar_InfoString( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); + Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SYSTEMINFO, systemInfo ); diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 3aa43ae3..259e0ea0 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -848,7 +848,7 @@ void SV_Frame( int msec ) { cvar_modifiedFlags &= ~CVAR_SERVERINFO; } if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) { - SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); + SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; } From 7314543c881f89afc3e847ca4998f4b83c767d14 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:17:01 +0100 Subject: [PATCH 0215/2040] Fixed snow bullet hit effect This fixes #246 --- code/cgame/cg_parsemsg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/cgame/cg_parsemsg.cpp b/code/cgame/cg_parsemsg.cpp index 966b041d..f9ff0397 100644 --- a/code/cgame/cg_parsemsg.cpp +++ b/code/cgame/cg_parsemsg.cpp @@ -267,7 +267,7 @@ CG_MakeBulletHole(const vec3_t i_vPos, const vec3_t i_vNorm, int iLarge, trace_t break; case SURF_SNOW: sBulletHole += "snow"; - iEffect = SFX_BHIT_FOLIAGE_LITE; + iEffect = SFX_BHIT_SNOW_LITE; break; case SURF_CARPET: sBulletHole += "carpet"; From 6eb20a3524aacc55fbd7003d363668d1f316f6c4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:59:28 +0100 Subject: [PATCH 0216/2040] Added PostSpawn for ammo This fixed ammo being spawned in the air without falling (fixes #244) --- code/fgame/ammo.cpp | 40 +++++++++++++++++++++++++++++++++++----- code/fgame/ammo.h | 7 ++----- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/code/fgame/ammo.cpp b/code/fgame/ammo.cpp index 8a51a007..a6dc4869 100644 --- a/code/fgame/ammo.cpp +++ b/code/fgame/ammo.cpp @@ -30,13 +30,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "ammo.h" #include "player.h" +#include "g_phys.h" + +Event EV_AmmoEntity_PostSpawn +( + "ammoentity_postspawn", + EV_DEFAULT, + NULL, + NULL, + "Ammo Entity Post Spawn" +); CLASS_DECLARATION(Item, AmmoEntity, NULL) { - {NULL, NULL} + {&EV_AmmoEntity_PostSpawn, &AmmoEntity::EventPostSpawn}, + {NULL, NULL } }; AmmoEntity::AmmoEntity() - { if (LoadingSavegame) { // all data will be setup by the archive function @@ -44,13 +54,14 @@ AmmoEntity::AmmoEntity() } setName("UnknownAmmo"); amount = 0; + + PostEvent(EV_AmmoEntity_PostSpawn, EV_POSTSPAWN); } Item *AmmoEntity::ItemPickup(Entity *other, qboolean add_to_inventory) - { Sentient *player; - Weapon* pWeap; + Weapon *pWeap; if (!other->IsSubclassOfPlayer()) { return NULL; @@ -86,7 +97,11 @@ Item *AmmoEntity::ItemPickup(Entity *other, qboolean add_to_inventory) Unregister(STRING_PICKUP); // Tell the player about the ammo being picked - gi.SendServerCommand(other->edict - g_entities, "print \"" HUD_MESSAGE_YELLOW "%s\"", gi.LV_ConvertString(va("Got %d %s Rounds", amount, item_name.c_str()))); + gi.SendServerCommand( + other->edict - g_entities, + "print \"" HUD_MESSAGE_YELLOW "%s\"", + gi.LV_ConvertString(va("Got %d %s Rounds", amount, item_name.c_str())) + ); // Give the ammo to the player player->GiveAmmo(item_name, amount); @@ -100,6 +115,21 @@ Item *AmmoEntity::ItemPickup(Entity *other, qboolean add_to_inventory) return NULL; // This doesn't create any items } +void AmmoEntity::EventPostSpawn(Event *ev) +{ + vec3_t fullmins; + vec3_t fullmaxs; + + setMoveType(MOVETYPE_TOSS); + if (edict->tiki) { + gi.TIKI_CalculateBounds(edict->tiki, edict->s.scale, fullmins, fullmaxs); + setSize(fullmins, fullmaxs); + link(); + } + + droptofloor(256); +} + // This is the Class that is used to keep track of ammo in the player's inventory. // It is not an entit, just a name and an amount. diff --git a/code/fgame/ammo.h b/code/fgame/ammo.h index eb1a5ad7..3330f4c5 100644 --- a/code/fgame/ammo.h +++ b/code/fgame/ammo.h @@ -22,8 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // ammo.h: Base class for all ammunition for entities derived from the Weapon class. -#ifndef __AMMO_H__ -#define __AMMO_H__ +#pragma once #include "g_local.h" #include "item.h" @@ -35,6 +34,7 @@ public: AmmoEntity(); Item *ItemPickup(Entity *other, qboolean add_to_inventory) override; + void EventPostSpawn(Event *ev); }; class Ammo : public Class @@ -61,7 +61,6 @@ public: }; inline void Ammo::Archive(Archiver& arc) - { Class::Archive(arc); @@ -75,5 +74,3 @@ inline void Ammo::Archive(Archiver& arc) setName(name); } } - -#endif /* ammo.h */ From 9d619938788e804ebd50b05e8fcfe22633a84cdc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:59:41 +0100 Subject: [PATCH 0217/2040] Archive name_index --- code/fgame/ammo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/ammo.h b/code/fgame/ammo.h index 3330f4c5..24cb172c 100644 --- a/code/fgame/ammo.h +++ b/code/fgame/ammo.h @@ -67,6 +67,7 @@ inline void Ammo::Archive(Archiver& arc) arc.ArchiveInteger(&amount); arc.ArchiveInteger(&maxamount); arc.ArchiveString(&name); + arc.ArchiveInteger(&name_index); // // name_index not archived, because it is auto-generated by gi.itemindex // From a86a707e4ab9e8b990f81f6ab9a9b201a74a7a13 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 18:29:16 +0100 Subject: [PATCH 0218/2040] Added more variables to initialize --- code/fgame/scriptslave.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 89157267..0ce2ec93 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -692,14 +692,23 @@ ScriptSlave::ScriptSlave() // this is a normal entity edict->s.eType = ET_GENERAL; + splineTime = 0; + + ignoreangles = false; + ignorevelocity = false; + moving = false; + speed = 100; takedamage = DAMAGE_YES; waypoint = NULL; - NewAngles = localangles; - NewPos = localorigin; traveltime = 0; commandswaiting = false; + splinePath = NULL; + splineangles = false; + m_fFollowRelativeYaw = 0; + + attack_finished = 0; dmg = 2; dmg_means_of_death = MOD_CRUSH; @@ -709,20 +718,16 @@ ScriptSlave::ScriptSlave() edict->s.renderfx = RF_ALWAYSDRAW; } - splinePath = NULL; - m_pCurPath = NULL; - m_iCurNode = 0; - m_fLookAhead = 0; - m_fCurSpeed = 0; - m_fIdealSpeed = 0; - m_fIdealAccel = 0; - m_fIdealDistance = 100; - splineangles = false; - m_fFollowRelativeYaw = 0; - attack_finished = 0; - setSolidType(SOLID_NOT); + m_pCurPath = NULL; + m_iCurNode = 0; + m_fCurSpeed = 0; + m_fLookAhead = 0; + m_fIdealSpeed = 0; + m_fIdealAccel = 0; + m_fIdealDistance = 100; + if (spawnflags & 1) { PostEvent(EV_BecomeNonSolid, EV_POSTSPAWN); } From cf6335d180f40f6d275667831652dcf15681d94e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 18:29:31 +0100 Subject: [PATCH 0219/2040] Fixed VehicleTouched not handling damage properly if there is no driver --- code/fgame/vehicle.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 1d47f275..de064285 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -4879,10 +4879,6 @@ void Vehicle::VehicleTouched(Event *ev) return; } - if (drivable && !driver.ent) { - return; - } - delta = other->origin - last_origin; delta.normalize(); From 8919890dbe62df228db5b31006059c4b116f23eb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 19:59:28 +0100 Subject: [PATCH 0220/2040] Fixed entity collision for vehicles This fixes vehicle not properly handling damage triggers (fixes #223, fixes #240) --- code/fgame/vehicle.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index de064285..ea8aa564 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -4254,8 +4254,8 @@ void Vehicle::MoveVehicle(void) tr.ent->entity->CheckGround(); if (!tr.ent->entity->groundentity - || (tr.ent->entity->groundentity == edict - && (!m_pCollisionEntity || tr.ent->entity != m_pCollisionEntity))) { + || (tr.ent->entity->groundentity != edict + && (!m_pCollisionEntity || tr.ent->entity->groundentity->entity != m_pCollisionEntity))) { Event *event = new Event(EV_Touch); event->AddEntity(this); tr.ent->entity->ProcessEvent(event); @@ -4336,8 +4336,8 @@ void Vehicle::MoveVehicle(void) tr.ent->entity->CheckGround(); if (!tr.ent->entity->groundentity - || (tr.ent->entity->groundentity == edict - && (!m_pCollisionEntity || tr.ent->entity != m_pCollisionEntity))) { + || (tr.ent->entity->groundentity != edict + && (!m_pCollisionEntity || tr.ent->entity->groundentity->entity != m_pCollisionEntity))) { Event *event = new Event(EV_Touch); event->AddEntity(this); tr.ent->entity->ProcessEvent(event); @@ -4421,8 +4421,8 @@ void Vehicle::MoveVehicle(void) tr.ent->entity->CheckGround(); if (!tr.ent->entity->groundentity - || (tr.ent->entity->groundentity == edict - && (!m_pCollisionEntity || tr.ent->entity != m_pCollisionEntity))) { + || (tr.ent->entity->groundentity != edict + && (!m_pCollisionEntity || tr.ent->entity->groundentity->entity != m_pCollisionEntity))) { Event *event = new Event(EV_Touch); event->AddEntity(this); tr.ent->entity->ProcessEvent(event); From ef08f1c8f3e94599364572cd6e879b3aced11cf2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 20:21:53 +0100 Subject: [PATCH 0221/2040] Fixed turret fire issues --- code/fgame/weapturret.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index dfff9acd..c8327663 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -1243,11 +1243,26 @@ void TurretGun::AI_DoAiming() void TurretGun::AI_DoFiring() { + float minBurstTime, maxBurstTime; + float minBurstDelay, maxBurstDelay; + + minBurstTime = m_fMinBurstTime; + maxBurstTime = m_fMaxBurstTime; + minBurstDelay = m_fMinBurstDelay; + maxBurstDelay = m_fMaxBurstDelay; + + if (!maxBurstTime) { + // Added in OPM + // default values if not set + maxBurstTime = minBurstTime = 0.001f; + maxBurstDelay = minBurstDelay = fire_delay[FIRE_PRIMARY]; + } + if (m_iFiring == 1) { - if (m_fMaxBurstTime > 0) { + if (maxBurstTime > 0) { if (m_fFireToggleTime < level.time) { m_iFiring = 4; - m_fFireToggleTime = level.time + m_fMinBurstTime + (m_fMaxBurstTime - m_fMinBurstTime) * random(); + m_fFireToggleTime = level.time + minBurstTime + (maxBurstTime - minBurstTime) * random(); } } else { m_iFiring = 4; @@ -1255,10 +1270,10 @@ void TurretGun::AI_DoFiring() } else if (m_iFiring == 4) { Fire(FIRE_PRIMARY); - if (m_fMaxBurstTime > 0) { + if (maxBurstTime > 0) { if (m_fFireToggleTime < level.time) { m_iFiring = 1; - m_fFireToggleTime = level.time + m_fMinBurstDelay + (m_fMaxBurstDelay - m_fMinBurstDelay) * random(); + m_fFireToggleTime = level.time + minBurstDelay + (maxBurstDelay - minBurstDelay) * random(); } } } @@ -1927,12 +1942,6 @@ float TurretGun::FireDelay(firemode_t mode) void TurretGun::SetFireDelay(Event *ev) { fire_delay[FIRE_PRIMARY] = ev->GetFloat(1); - if (!m_fMaxBurstTime) { - // Added in OPM - // default values if not set - m_fMaxBurstTime = m_fMinBurstTime = 0.001f; - m_fMaxBurstDelay = m_fMinBurstDelay = fire_delay[FIRE_PRIMARY]; - } } void TurretGun::ShowInfo(float fDot, float fDist) From 1a5cac2c6a7449151d7d0f9f517b4cb6f8b823e0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 20:22:47 +0100 Subject: [PATCH 0222/2040] Implemented all parm methods This fixes, #249 and fixes #217 --- code/fgame/parm.cpp | 154 ++++++++++++++++++++++++++++++++------------ code/fgame/parm.h | 42 ++++++------ 2 files changed, 136 insertions(+), 60 deletions(-) diff --git a/code/fgame/parm.cpp b/code/fgame/parm.cpp index 9b90a719..76fd8513 100644 --- a/code/fgame/parm.cpp +++ b/code/fgame/parm.cpp @@ -30,63 +30,135 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Parm parm; -Event EV_Parm_GetOther -( - "other", - EV_DEFAULT, - NULL, - NULL, - "other", - EV_GETTER -); - -Event EV_Parm_GetOwner -( - "owner", - EV_DEFAULT, - NULL, - NULL, - "owner", - EV_GETTER -); - Event EV_Parm_GetPreviousThread ( - "previousthread", - EV_DEFAULT, - NULL, - NULL, - "previousthread", - EV_GETTER + "previousthread", + EV_DEFAULT, + NULL, + NULL, + "previousthread", + EV_GETTER +); +Event EV_Parm_GetOther +( + "other", + EV_DEFAULT, + NULL, + NULL, + "other", + EV_GETTER +); +Event EV_Parm_GetOwner +( + "owner", + EV_DEFAULT, + NULL, + NULL, + "owner", + EV_GETTER +); +Event EV_Parm_Movedone +( + "movedone", + EV_DEFAULT, + NULL, + NULL, + "movedone", + EV_GETTER +); +Event EV_Parm_Movefail +( + "movefail", + EV_DEFAULT, + NULL, + NULL, + "movefail", + EV_GETTER +); +Event EV_Parm_Motionfail +( + "motionfail", + EV_DEFAULT, + NULL, + NULL, + "motionfail", + EV_GETTER +); +Event EV_Parm_Upperfail +( + "upperfail", + EV_DEFAULT, + NULL, + NULL, + "upperfail", + EV_GETTER +); +Event EV_Parm_Sayfail +( + "sayfail", + EV_DEFAULT, + NULL, + NULL, + "sayfail", + EV_GETTER ); -void Parm::Archive( Archiver& arc ) +void Parm::Archive(Archiver& arc) { - Listener::Archive( arc ); + Listener::Archive(arc); - arc.ArchiveSafePointer( &other ); - arc.ArchiveSafePointer( &owner ); + arc.ArchiveSafePointer(&other); + arc.ArchiveSafePointer(&owner); } -void Parm::GetOther( Event *ev ) +void Parm::GetMotionFail(Event *ev) { - ev->AddListener( other ); + ev->AddInteger(motionfail); } -void Parm::GetOwner( Event *ev ) +void Parm::GetMovedone(Event *ev) { - ev->AddListener( owner ); + ev->AddInteger(movedone); } -void Parm::GetPreviousThread( Event *ev ) +void Parm::GetMovefail(Event *ev) { - ev->AddListener( Director.PreviousThread() ); + ev->AddInteger(movefail); } -CLASS_DECLARATION( Listener, Parm, NULL ) +void Parm::GetOther(Event *ev) { - { &EV_Parm_GetOther, &Parm::GetOther }, - { &EV_Parm_GetOwner, &Parm::GetOwner }, - { &EV_Parm_GetPreviousThread, &Parm::GetPreviousThread }, - { NULL, NULL } + ev->AddListener(other); +} + +void Parm::GetOwner(Event *ev) +{ + ev->AddListener(owner); +} + +void Parm::GetPreviousThread(Event *ev) +{ + ev->AddListener(Director.PreviousThread()); +} + +void Parm::GetSayFail(Event *ev) +{ + ev->AddInteger(sayfail); +} + +void Parm::GetUpperFail(Event *ev) +{ + ev->AddInteger(upperfail); +} + +CLASS_DECLARATION(Listener, Parm, NULL) { + {&EV_Parm_GetPreviousThread, &Parm::GetPreviousThread}, + {&EV_Parm_GetOther, &Parm::GetOther }, + {&EV_Parm_GetOwner, &Parm::GetOwner }, + {&EV_Parm_Movedone, &Parm::GetMovedone }, + {&EV_Parm_Movefail, &Parm::GetMovefail }, + {&EV_Parm_Motionfail, &Parm::GetMotionFail }, + {&EV_Parm_Upperfail, &Parm::GetUpperFail }, + {&EV_Parm_Sayfail, &Parm::GetSayFail }, + {NULL, NULL } }; diff --git a/code/fgame/parm.h b/code/fgame/parm.h index b942324d..aa8ae00b 100644 --- a/code/fgame/parm.h +++ b/code/fgame/parm.h @@ -22,34 +22,38 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // parm.h: Event parameters -#ifndef __PARM_H__ -#define __PARM_H__ +#pragma once #include "listener.h" -class Parm : public Listener { +class Parm : public Listener +{ public: - // General trigger variables - SafePtr< Listener > other; - SafePtr< Listener > owner; + // General trigger variables + SafePtr other; + SafePtr owner; - // Failure variables - qboolean movedone; - qboolean movefail; - qboolean motionfail; - qboolean upperfail; - qboolean sayfail; + // Failure variables + qboolean movedone; + qboolean movefail; + qboolean motionfail; + qboolean upperfail; + qboolean sayfail; public: - CLASS_PROTOTYPE( Parm ); + CLASS_PROTOTYPE(Parm); - void Archive( Archiver& arc ) override; + void GetPreviousThread(Event *ev); + void GetOther(Event *ev); + void GetOwner(Event *ev); + void GetPath(Event *ev); + void GetMovedone(Event *ev); + void GetMovefail(Event *ev); + void GetMotionFail(Event *ev); + void GetUpperFail(Event *ev); + void GetSayFail(Event *ev); - void GetOther( Event *ev ); - void GetOwner( Event *ev ); - void GetPreviousThread( Event *ev ); + void Archive(Archiver& arc) override; }; extern Parm parm; - -#endif /* __PARM_H__ */ From cc721a3db630ca95fd870abfce50b504ce095418 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:36:31 +0100 Subject: [PATCH 0223/2040] Lexer fixes for integer This fixes map loading issues (fixes #258) --- code/parser/lex_source.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/parser/lex_source.txt b/code/parser/lex_source.txt index bf8c3094..0cca5359 100644 --- a/code/parser/lex_source.txt +++ b/code/parser/lex_source.txt @@ -312,7 +312,7 @@ varname [a-zA-Z0-9_\"]+ [\r\n]+ { if (prev_yylex != TOKEN_EOL) YYLEX(TOKEN_EOL); } [ \t] { ; } -[0-9]+ { +[0-9^`]+ { char* p = nullptr; yylval.s.val.intValue = std::strtol(yytext, &p, 10); YYLEX(TOKEN_INTEGER); From 7a2735885f99ea5aa5e11a3955e28823a606bf2f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 22:50:36 +0100 Subject: [PATCH 0224/2040] Send information about sentient's team This fixes #259 --- code/fgame/sentient.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index 46535362..a8f6b6d2 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -2515,6 +2515,11 @@ void Sentient::EventGerman(Event *ev) if (bRejoinSquads) { JoinNearbySquads(1024.0f); } + + // Added in 2.0 + // Tell clients about sentient team + edict->s.eFlags &= ~EF_ALLIES; + edict->s.eFlags |= EF_AXIS; } void Sentient::EventAmerican(Event *ev) @@ -2546,6 +2551,11 @@ void Sentient::EventAmerican(Event *ev) pActor->m_csMood = STRING_NERVOUS; pActor->m_csIdleMood = STRING_NERVOUS; } + + // Added in 2.0 + // Tell clients about sentient team + edict->s.eFlags &= ~EF_AXIS; + edict->s.eFlags |= EF_ALLIES; } void Sentient::EventGetTeam(Event *ev) From 35e6435382379a2c6f7a49cae014f07e3709faf2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Feb 2024 23:12:04 +0100 Subject: [PATCH 0225/2040] Reimplemented DropInventoryItems from 2.30 --- code/fgame/sentient.cpp | 140 +++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 73 deletions(-) diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index a8f6b6d2..1f6d6213 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -1962,17 +1962,49 @@ void Sentient::DropInventoryItems(void) int i; Item *item; + if (m_bForceDropHealth) { + giveItem("ITEMS/item_25_healthbox.tik", 25); + } else if (skill->integer != 2 && !level.mbNoDropHealth) { + static cvar_t *ai_health_kar = gi.Cvar_Get("ai_health_kar", "6", CVAR_CHEAT); + static cvar_t *ai_health_mp40 = gi.Cvar_Get("ai_health_mp40points", "2", CVAR_CHEAT); + + Weapon *weapon = GetActiveWeapon(WEAPON_MAIN); + if (weapon) { + if (!Q_stricmp("rifle", Director.GetString(weapon->GetWeaponGroup()))) { + level.mHealthPopCount++; + } else { + level.mHealthPopCount += ai_health_mp40->integer; + } + + if (level.mHealthPopCount >= ai_health_kar->integer) { + giveItem("ITEMS/item_25_healthbox.tik", 25); + level.mHealthPopCount -= ai_health_kar->integer; + } + } + } + // Drop any inventory items num = inventory.NumObjects(); for (i = num; i >= 1; i--) { item = (Item *)G_GetEntity(inventory.ObjectAt(i)); - if (item->isSubclassOf(InventoryItem)) { - if (m_bDontDropWeapons && item->IsSubclassOfWeapon()) { - item->Delete(); - } else { - item->Drop(); - } + // Added in 2.30 + // Force drop the item when specified + if (m_bForceDropWeapon && item->IsSubclassOfWeapon()) { + item->Drop(); + continue; } + + if (!m_bDontDropWeapons && !level.mbNoDropWeapons) { + item->Drop(); + continue; + } + + if (!item->IsSubclassOfWeapon()) { + item->Drop(); + continue; + } + + item->Delete(); } } @@ -2537,7 +2569,6 @@ void Sentient::EventAmerican(Event *ev) DisbandSquadMate(this); } - Unlink(); m_Team = TEAM_AMERICAN; Link(); @@ -2955,26 +2986,27 @@ void Sentient::SetMinViewVariation(const Vector& vVariation) m_vViewVariation.z = Q_min(m_vViewVariation.z, vVariation.z); } -void Sentient::SetHolsteredByCode(bool holstered) { +void Sentient::SetHolsteredByCode(bool holstered) +{ weapons_holstered_by_code = holstered; } -Vehicle* Sentient::GetVehicle() const +Vehicle *Sentient::GetVehicle() const { return m_pVehicle; } -void Sentient::SetVehicle(Vehicle* pVehicle) +void Sentient::SetVehicle(Vehicle *pVehicle) { m_pVehicle = NULL; } -TurretGun* Sentient::GetTurret() const +TurretGun *Sentient::GetTurret() const { return m_pTurret; } -void Sentient::SetTurret(TurretGun* pTurret) +void Sentient::SetTurret(TurretGun *pTurret) { m_pTurret = pTurret; } @@ -2982,15 +3014,15 @@ void Sentient::SetTurret(TurretGun* pTurret) #define GROUND_DISTANCE 8 #define WATER_NO_SPLASH_HEIGHT 16 -void Sentient::EventClientLanding(Event* ev) +void Sentient::EventClientLanding(Event *ev) { - float fVolume = ev->NumArgs() >= 1 ? ev->GetFloat(1) : 1; - int iEquipment = ev->NumArgs() >= 2 ? ev->GetInteger(2) : 1; + float fVolume = ev->NumArgs() >= 1 ? ev->GetFloat(1) : 1; + int iEquipment = ev->NumArgs() >= 2 ? ev->GetInteger(2) : 1; LandingSound(fVolume, iEquipment); } -void Sentient::FootstepMain(trace_t* trace, int iRunning, int iEquipment) +void Sentient::FootstepMain(trace_t *trace, int iRunning, int iEquipment) { int contents; int surftype; @@ -3010,12 +3042,10 @@ void Sentient::FootstepMain(trace_t* trace, int iRunning, int iEquipment) contents = gi.pointcontents(midlegs, -1); if (contents & MASK_WATER) { sSoundName += "wade"; - } - else { + } else { sSoundName += "puddle"; } - } - else { + } else { surftype = trace->surfaceFlags & MASK_SURF_TYPE; switch (surftype) { case SURF_FOLIAGE: @@ -3075,8 +3105,7 @@ void Sentient::FootstepMain(trace_t* trace, int iRunning, int iEquipment) } else { fVolume = 1.0; } - } - else { + } else { fVolume = 0.25; } @@ -3092,7 +3121,7 @@ void Sentient::FootstepMain(trace_t* trace, int iRunning, int iEquipment) } } -void Sentient::Footstep(const char* szTagName, int iRunning, int iEquipment) +void Sentient::Footstep(const char *szTagName, int iRunning, int iEquipment) { int i; int iTagNum; @@ -3125,8 +3154,7 @@ void Sentient::Footstep(const char* szTagName, int iRunning, int iEquipment) VectorSet(vMins, -2, -2, -8); VectorSet(vMaxs, 2, 2, 8); - } - else { + } else { VectorSet(vMins, -4, -4, 0); VectorSet(vMaxs, 4, 4, 2); @@ -3137,28 +3165,9 @@ void Sentient::Footstep(const char* szTagName, int iRunning, int iEquipment) } if (IsSubclassOfPlayer()) { - trace = G_Trace( - vStart, - vMins, - vMaxs, - vEnd, - edict, - MASK_PLAYERSOLID, - qtrue, - "Player Footsteps" - ); - } - else { - trace = G_Trace( - vStart, - vMins, - vMaxs, - vEnd, - edict, - MASK_MONSTERSOLID, - qfalse, - "Monster Footsteps" - ); + trace = G_Trace(vStart, vMins, vMaxs, vEnd, edict, MASK_PLAYERSOLID, qtrue, "Player Footsteps"); + } else { + trace = G_Trace(vStart, vMins, vMaxs, vEnd, edict, MASK_MONSTERSOLID, qfalse, "Monster Footsteps"); } if (trace.fraction == 1.0f) { @@ -3170,14 +3179,14 @@ void Sentient::Footstep(const char* szTagName, int iRunning, int iEquipment) void Sentient::LandingSound(float volume, int iEquipment) { - int contents; - int surftype; - vec3_t vStart, vEnd; - vec3_t midlegs; - str sSoundName; - trace_t trace; - static vec3_t g_vFootstepMins = { -4, -4, 0 }; - static vec3_t g_vFootstepMaxs = { 4, 4, 2 }; + int contents; + int surftype; + vec3_t vStart, vEnd; + vec3_t midlegs; + str sSoundName; + trace_t trace; + static vec3_t g_vFootstepMins = {-4, -4, 0}; + static vec3_t g_vFootstepMaxs = {4, 4, 2}; if (this->iNextLandTime > level.inttime) { this->iNextLandTime = level.inttime + 200; @@ -3192,26 +3201,11 @@ void Sentient::LandingSound(float volume, int iEquipment) vEnd[2] -= 64.0; if (IsSubclassOfPlayer()) { - trace = G_Trace( - vStart, - g_vFootstepMins, - g_vFootstepMaxs, - vEnd, - edict, - MASK_PLAYERSOLID, - qtrue, - "Player Footsteps" - ); + trace = + G_Trace(vStart, g_vFootstepMins, g_vFootstepMaxs, vEnd, edict, MASK_PLAYERSOLID, qtrue, "Player Footsteps"); } else { trace = G_Trace( - vStart, - g_vFootstepMins, - g_vFootstepMaxs, - vEnd, - edict, - MASK_MONSTERSOLID, - qfalse, - "Monster Footsteps" + vStart, g_vFootstepMins, g_vFootstepMaxs, vEnd, edict, MASK_MONSTERSOLID, qfalse, "Monster Footsteps" ); } From a67dbff603eac7fc89354897dfc8776133edcc4f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 21:12:23 +0100 Subject: [PATCH 0226/2040] Reset state to STAND when the player has no physics --- code/fgame/player.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index d80e454a..8fa3d7e5 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -9979,6 +9979,10 @@ void Player::EventGetCurrentDMWeaponType(Event *ev) void Player::PhysicsOff(Event *ev) { + // Added in 2.0 + // Reset the state to STAND before disabling physics + EvaluateState(statemap_Torso->FindState("STAND"), statemap_Legs->FindState("STAND")); + flags |= FL_IMMOBILE; } From efaea69c09e23399b76647b8f34543520bb2acca Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 21:12:38 +0100 Subject: [PATCH 0227/2040] Don't evaluate state when immobile --- code/fgame/player.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 8fa3d7e5..3a908b32 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -5246,6 +5246,11 @@ void Player::EvaluateState(State *forceTorso, State *forceLegs) return; } + if (flags & FL_IMMOBILE) { + // Don't evaluate state when immobile + return; + } + // Evaluate the current state. // When the state changes, we reevaluate the state so that if the // conditions aren't met in the new state, we don't play one frame of From 0f1de72ae64b6eb3af0b937a4024e64245a22bb7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 22:51:08 +0100 Subject: [PATCH 0228/2040] Initialize the ground entity number --- code/fgame/player.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 3a908b32..6ff7c0a7 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -3670,6 +3670,10 @@ void Player::SetMoveInfo(pmove_t *pm, usercmd_t *ucmd) } pm->protocol = g_protocol; + + // Added in OPM + // Initialize the ground entity + pm->ps->groundEntityNum = ENTITYNUM_NONE; } pmtype_t Player::GetMovePlayerMoveType(void) From d2aa26248fef46cafb9a8036db25b8e563499dd7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:01:19 +0100 Subject: [PATCH 0229/2040] Don't allow ducking when physics are off This fixes #251 --- code/fgame/player_conditionals.cpp | 106 +++++++++++------------------ 1 file changed, 40 insertions(+), 66 deletions(-) diff --git a/code/fgame/player_conditionals.cpp b/code/fgame/player_conditionals.cpp index c0b59831..e5043e33 100644 --- a/code/fgame/player_conditionals.cpp +++ b/code/fgame/player_conditionals.cpp @@ -63,7 +63,6 @@ qboolean Player::CondTrue(Conditional& condition) } qboolean Player::CondChance(Conditional& condition) - { float percent_chance; @@ -73,7 +72,6 @@ qboolean Player::CondChance(Conditional& condition) } qboolean Player::CondHealth(Conditional& condition) - { return health < atoi(condition.getParm(1)); } @@ -96,7 +94,6 @@ qboolean Player::CondBlocked(Conditional& condition) } qboolean Player::CondPain(Conditional& condition) - { return (pain != 0 || knockdown != 0); } @@ -112,13 +109,11 @@ qboolean Player::CondOnGround(Conditional& condition) } qboolean Player::CondHasWeapon(Conditional& condition) - { return WeaponsOut(); } qboolean Player::CondNewWeapon(Conditional& condition) - { Weapon *weapon; @@ -144,7 +139,6 @@ qboolean Player::CondImmediateSwitch(Conditional& condition) // Check to see if a weapon has been raised qboolean Player::CondUseWeapon(Conditional& condition) - { const char *weaponName; const char *parm; @@ -507,7 +501,6 @@ qboolean Player::CondPutAwayMain(Conditional& condition) // Check to see if any of the active weapons need to be put away qboolean Player::CondPutAwayOffHand(Conditional& condition) - { Weapon *weapon = GetActiveWeapon(WEAPON_OFFHAND); @@ -516,7 +509,6 @@ qboolean Player::CondPutAwayOffHand(Conditional& condition) // Checks to see if any weapon is active in the specified hand qboolean Player::CondAnyWeaponActive(Conditional& condition) - { weaponhand_t hand; Weapon *weap; @@ -532,7 +524,6 @@ qboolean Player::CondAnyWeaponActive(Conditional& condition) } qboolean Player::CondAttackBlocked(Conditional& condition) - { if (attack_blocked) { attack_blocked = qfalse; @@ -618,14 +609,12 @@ qboolean Player::CondMaxChargeTime(Conditional& condition) } qboolean Player::CondBlockDelay(Conditional& condition) - { float t = atof(condition.getParm(1)); return (level.time > (attack_blocked_time + t)); } qboolean Player::CondMuzzleClear(Conditional& condition) - { weaponhand_t hand; @@ -641,7 +630,6 @@ qboolean Player::CondMuzzleClear(Conditional& condition) // Checks to see if any weapon is active in the specified hand qboolean Player::CondWeaponHasAmmo(Conditional& condition) - { weaponhand_t hand; Weapon *weap; @@ -779,24 +767,35 @@ qboolean Player::CondStrafeLeft(Conditional& condition) } qboolean Player::CondStrafeRight(Conditional& condition) - { return last_ucmd.rightmove > 0; } qboolean Player::CondJump(Conditional& condition) - { + if (client->ps.pm_flags & PMF_NO_MOVE) { + return false; + } + return last_ucmd.upmove > 0; } qboolean Player::CondCrouch(Conditional& condition) { + // Added in 2.0 + // Don't crouch if the player is not moving + if (client->ps.pm_flags & PMF_NO_MOVE) { + // Added in 2.30 + // Allow ducking if specified + if (!m_pGlueMaster || !m_bGlueDuckable) { + return viewheight != DEFAULT_VIEWHEIGHT; + } + } + return (last_ucmd.upmove) < 0; } qboolean Player::CondJumpFlip(Conditional& condition) - { return velocity.z < (sv_gravity->value * 0.5f); } @@ -813,6 +812,8 @@ qboolean Player::CondAnimDoneTorso(Conditional& condition) qboolean Player::CondAttackPrimary(Conditional& condition) { + Weapon* weapon; + if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) { return false; } @@ -821,21 +822,19 @@ qboolean Player::CondAttackPrimary(Conditional& condition) return false; } - if (last_ucmd.buttons & BUTTON_ATTACKLEFT) { - Weapon *weapon; - - last_attack_button = BUTTON_ATTACKLEFT; - - weapon = GetActiveWeapon(WEAPON_MAIN); - if (weapon) { - return true; - } - - // No ammo - return false; - } else { + if (!(last_ucmd.buttons & BUTTON_ATTACKLEFT)) { return false; } + + last_attack_button = BUTTON_ATTACKLEFT; + + weapon = GetActiveWeapon(WEAPON_MAIN); + if (weapon) { + return true; + } + + // No ammo + return false; } qboolean Player::CondAttackButtonPrimary(Conditional& condition) @@ -853,6 +852,8 @@ qboolean Player::CondAttackButtonPrimary(Conditional& condition) qboolean Player::CondAttackSecondary(Conditional& condition) { + Weapon* weapon; + if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) { return false; } @@ -861,21 +862,19 @@ qboolean Player::CondAttackSecondary(Conditional& condition) return false; } - if (last_ucmd.buttons & BUTTON_ATTACKRIGHT) { - Weapon *weapon; - - last_attack_button = BUTTON_ATTACKRIGHT; - - weapon = GetActiveWeapon(WEAPON_MAIN); - if (weapon) { - return true; - } - - // No ammo - return false; - } else { + if (!(last_ucmd.buttons & BUTTON_ATTACKRIGHT)) { return false; } + + last_attack_button = BUTTON_ATTACKRIGHT; + + weapon = GetActiveWeapon(WEAPON_MAIN); + if (weapon) { + return true; + } + + // No ammo + return false; } qboolean Player::CondAttackButtonSecondary(Conditional& condition) @@ -935,13 +934,11 @@ qboolean Player::CondRun(Conditional& condition) } qboolean Player::CondUse(Conditional& condition) - { return (last_ucmd.buttons & BUTTON_USE) != 0; } qboolean Player::CondCanTurn(Conditional& condition) - { float yaw; Vector oldang(v_angle); @@ -1042,7 +1039,6 @@ qboolean Player::CondHasVelocity(Conditional& condition) } qboolean Player::Cond22DegreeSlope(Conditional& condition) - { if (client->ps.walking && client->ps.groundPlane && (client->ps.groundTrace.plane.normal[2] < SLOPE_22_MAX) && (client->ps.groundTrace.plane.normal[2] >= SLOPE_22_MIN)) { @@ -1053,7 +1049,6 @@ qboolean Player::Cond22DegreeSlope(Conditional& condition) } qboolean Player::Cond45DegreeSlope(Conditional& condition) - { if (client->ps.walking && client->ps.groundPlane && (client->ps.groundTrace.plane.normal[2] < SLOPE_45_MAX) && (client->ps.groundTrace.plane.normal[2] >= SLOPE_45_MIN)) { @@ -1064,7 +1059,6 @@ qboolean Player::Cond45DegreeSlope(Conditional& condition) } qboolean Player::CondRightLegHigh(Conditional& condition) - { float groundyaw; float yawdelta; @@ -1078,7 +1072,6 @@ qboolean Player::CondRightLegHigh(Conditional& condition) } qboolean Player::CondLeftLegHigh(Conditional& condition) - { float groundyaw; float yawdelta; @@ -1092,7 +1085,6 @@ qboolean Player::CondLeftLegHigh(Conditional& condition) } qboolean Player::CondFacingUpSlope(Conditional& condition) - { float groundyaw; float yawdelta; @@ -1106,7 +1098,6 @@ qboolean Player::CondFacingUpSlope(Conditional& condition) } qboolean Player::CondFacingDownSlope(Conditional& condition) - { float groundyaw; float yawdelta; @@ -1120,13 +1111,11 @@ qboolean Player::CondFacingDownSlope(Conditional& condition) } qboolean Player::CondFalling(Conditional& condition) - { return falling; } qboolean Player::CondGroundEntity(Conditional& condition) - { return (groundentity != NULL); } @@ -1147,14 +1136,12 @@ qboolean Player::CondCanFall(Conditional& condition) } qboolean Player::CondAtDoor(Conditional& condition) - { // Check if the player is at a door return (atobject && atobject->isSubclassOf(Door)); } qboolean Player::CondAtUseAnim(Conditional& condition) - { // Check if the player is at a useanim if (atobject && atobject->isSubclassOf(UseAnim)) { @@ -1165,7 +1152,6 @@ qboolean Player::CondAtUseAnim(Conditional& condition) } qboolean Player::CondTouchUseAnim(Conditional& condition) - { if (toucheduseanim) { return ((UseAnim *)(Entity *)toucheduseanim)->canBeUsed(this); @@ -1175,13 +1161,11 @@ qboolean Player::CondTouchUseAnim(Conditional& condition) } qboolean Player::CondUseAnimFinished(Conditional& condition) - { return (useanim_numloops <= 0); } qboolean Player::CondAtUseObject(Conditional& condition) - { // Check if the player is at a useanim if (atobject && atobject->isSubclassOf(UseObject)) { @@ -1192,7 +1176,6 @@ qboolean Player::CondAtUseObject(Conditional& condition) } qboolean Player::CondLoopUseObject(Conditional& condition) - { // Check if the player is at a useanim if (useitem_in_use && useitem_in_use->isSubclassOf(UseObject)) { @@ -1203,13 +1186,11 @@ qboolean Player::CondLoopUseObject(Conditional& condition) } qboolean Player::CondDead(Conditional& condition) - { return (deadflag); } qboolean Player::CondKnockDown(Conditional& condition) - { if (knockdown) { knockdown = false; @@ -1294,7 +1275,6 @@ qboolean Player::CondPainLocation(Conditional& condition) } qboolean Player::CondPainThreshold(Conditional& condition) - { float threshold = atof(condition.getParm(1)); @@ -1307,7 +1287,6 @@ qboolean Player::CondPainThreshold(Conditional& condition) } qboolean Player::CondLegsState(Conditional& condition) - { if (currentState_Legs) { str current = currentState_Legs->getName(); @@ -1322,7 +1301,6 @@ qboolean Player::CondLegsState(Conditional& condition) } qboolean Player::CondTorsoState(Conditional& condition) - { if (currentState_Torso) { str current = currentState_Torso->getName(); @@ -1337,7 +1315,6 @@ qboolean Player::CondTorsoState(Conditional& condition) } qboolean Player::CondStateName(Conditional& condition) - { str part = condition.getParm(1); str statename = condition.getParm(2); @@ -1352,7 +1329,6 @@ qboolean Player::CondStateName(Conditional& condition) } qboolean Player::CondPush(Conditional& condition) - { // Check if the player is at a pushobject if (atobject && atobject->isSubclassOf(PushObject) && (atobject_dist < (PUSH_OBJECT_DISTANCE + 15.0f))) { @@ -1366,7 +1342,6 @@ qboolean Player::CondPush(Conditional& condition) } qboolean Player::CondPull(Conditional& condition) - { // Check if the player is at a pushobject if (atobject && atobject->isSubclassOf(PushObject) && (atobject_dist < (PUSH_OBJECT_DISTANCE + 15.0f))) { @@ -1511,7 +1486,6 @@ qboolean Player::CondLookingUp(Conditional& condition) } qboolean Player::CondCanStand(Conditional& condition) - { Vector newmins(mins); Vector newmaxs(maxs); From e8a48184b923a95dc379b0545cc761c28e8967a4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:09:29 +0100 Subject: [PATCH 0230/2040] Set the ground entity number to the glue master --- code/fgame/player.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 6ff7c0a7..45c9aa60 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -3574,6 +3574,10 @@ void Player::GetMoveInfo(pmove_t *pm) if (groundentity->entity && groundentity->entity != this && groundentity->entity->velocity[2] != 0) { pm->ps->pm_flags |= PMF_NO_PREDICTION; } + } else if (m_pGlueMaster) { + // Added in OPM + // Use the glue master for the ground entity to make the viewmodel will stay still + pm->ps->groundEntityNum = m_pGlueMaster->entnum; } velocity = Vector(pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); From a0cb46d4a1d957c6a79793d22c1dbde4d22a15fc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:09:57 +0100 Subject: [PATCH 0231/2040] Formatting --- code/fgame/player.cpp | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 45c9aa60..88451905 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -2304,7 +2304,6 @@ void Player::InitEdict(void) } void Player::InitSound(void) - { // // reset the music @@ -2390,7 +2389,6 @@ void Player::InitState(void) } void Player::InitHealth(void) - { static cvar_t *pMaxHealth = gi.Cvar_Get("g_maxplayerhealth", "250", 0); static cvar_t *pDMHealth = gi.Cvar_Get("g_playerdmhealth", "100", 0); @@ -2562,7 +2560,6 @@ void Player::InitPhysics(void) } void Player::InitPowerups(void) - { // powerups poweruptimer = 0; @@ -2667,7 +2664,6 @@ void Player::ChooseSpawnPoint(void) } void Player::EndLevel(Event *ev) - { InitPowerups(); if (health > max_health) { @@ -2725,7 +2721,6 @@ void Player::Respawn(Event *ev) } void Player::SetDeltaAngles(void) - { int i; @@ -3751,7 +3746,6 @@ qboolean Player::AnimMove(Vector& move, Vector *endpos) } qboolean Player::TestMove(Vector& move, Vector *endpos) - { trace_t trace; Vector pos(origin + move); @@ -3804,7 +3798,6 @@ qboolean Player::TestMove(Vector& move, Vector *endpos) } float Player::TestMoveDist(Vector& move) - { Vector endpos; @@ -3890,7 +3883,6 @@ qboolean Player::CheckMove(Vector& move, Vector *endpos) } float Player::CheckMoveDist(Vector& move) - { Vector endpos; @@ -4988,7 +4980,6 @@ void Player::ResetState(Event *ev) } void Player::StartPush(void) - { trace_t trace; Vector end(origin + yaw_forward * 64.0f); @@ -5004,7 +4995,6 @@ void Player::StartPush(void) } void Player::StartClimbLadder(void) - { trace_t trace; Vector end(origin + yaw_forward * 20.0f); @@ -5081,13 +5071,11 @@ void Player::StartUseAnim(void) } void Player::StartLoopUseAnim(void) - { useanim_numloops--; } void Player::FinishUseAnim(Event *ev) - { UseAnim *ua; @@ -5101,7 +5089,6 @@ void Player::FinishUseAnim(Event *ev) } void Player::SetupUseObject(void) - { UseObject *uo; Vector neworg; @@ -5151,7 +5138,6 @@ void Player::SetupUseObject(void) } void Player::StartUseObject(Event *ev) - { UseObject *uo; @@ -5164,7 +5150,6 @@ void Player::StartUseObject(Event *ev) } void Player::FinishUseObject(Event *ev) - { UseObject *uo; @@ -5178,7 +5163,6 @@ void Player::FinishUseObject(Event *ev) } void Player::Turn(Event *ev) - { float yaw; Vector oldang(v_angle); @@ -5202,7 +5186,6 @@ void Player::Turn(Event *ev) } void Player::TurnUpdate(Event *ev) - { float yaw; float timeleft; @@ -5231,7 +5214,6 @@ void Player::TurnUpdate(Event *ev) } void Player::TurnLegs(Event *ev) - { float yaw; @@ -5611,13 +5593,11 @@ void Player::DropCurrentWeapon(Event *ev) } void Player::GiveWeaponCheat(Event *ev) - { giveItem(ev->GetString(1)); } void Player::GiveCheat(Event *ev) - { str name; @@ -5806,7 +5786,6 @@ void Player::NoclipCheat(Event *ev) } void Player::GameVersion(Event *ev) - { gi.SendServerCommand(edict - g_entities, "print \"%s : %s\n\"", GAMEVERSION, __DATE__); } @@ -5865,7 +5844,6 @@ CalcRoll =============== */ float Player::CalcRoll(void) - { float sign; float side; @@ -5976,7 +5954,6 @@ AddBlend ============= */ void Player::AddBlend(float r, float g, float b, float a) - { float a2; float a3; @@ -6003,7 +5980,6 @@ CalcBlend ============= */ void Player::CalcBlend(void) - { int contents; Vector vieworg; @@ -6763,7 +6739,6 @@ void Player::SetupView(void) } Vector Player::GetAngleToTarget(Entity *ent, str tag, float yawclamp, float pitchclamp, Vector baseangles) - { assert(ent); @@ -6808,7 +6783,6 @@ Vector Player::GetAngleToTarget(Entity *ent, str tag, float yawclamp, float pitc } void Player::DebugWeaponTags(int controller_tag, Weapon *weapon, str weapon_tagname) - { int i; orientation_t bone_or, tag_weapon_or, barrel_or, final_barrel_or; @@ -7506,14 +7480,12 @@ void Player::UpdateMusic(void) } void Player::SetReverb(int type, float level) - { reverb_type = type; reverb_level = level; } void Player::SetReverb(str type, float level) - { reverb_type = EAXMode_NameToNum(type); reverb_level = level; @@ -7591,7 +7563,6 @@ void Player::EndFrame(void) } void Player::GotKill(Event *ev) - { /* Entity *victim; @@ -7614,7 +7585,6 @@ void Player::GotKill(Event *ev) } void Player::SetPowerupTimer(Event *ev) - { Event *event; @@ -7625,7 +7595,6 @@ void Player::SetPowerupTimer(Event *ev) } void Player::UpdatePowerupTimer(Event *ev) - { poweruptimer -= 1; if (poweruptimer > 0) { @@ -7663,7 +7632,6 @@ void Player::ChangeMusic(const char *current, const char *fallback, qboolean for } void Player::ChangeMusicVolume(float volume, float fade_time) - { music_volume_fade_time = fade_time; music_saved_volume = music_current_volume; @@ -7671,7 +7639,6 @@ void Player::ChangeMusicVolume(float volume, float fade_time) } void Player::RestoreMusicVolume(float fade_time) - { music_volume_fade_time = fade_time; music_current_volume = music_saved_volume; @@ -7688,7 +7655,6 @@ void Player::addOrigin(Vector org) } void Player::Jump(Event *ev) - { float maxheight; @@ -7750,7 +7716,6 @@ void Player::SetTargetViewAngles(Vector angles) } void Player::DumpState(Event *ev) - { gi.DPrintf( "Legs: %s Torso: %s\n", currentState_Legs ? currentState_Legs->getName() : "NULL", currentState_Torso->getName() @@ -7904,7 +7869,6 @@ void Player::Holster(Event *ev) } void Player::WatchActor(Event *ev) - { if (camera || currentState_Torso->getCameraType() != CAMERA_BEHIND) { return; @@ -7914,7 +7878,6 @@ void Player::WatchActor(Event *ev) } void Player::StopWatchingActor(Event *ev) - { Actor *old_actor; @@ -7937,7 +7900,6 @@ void Player::setAngles(Vector ang) } painDirection_t Player::Pain_string_to_int(str pain) - { if (!pain.icmp(pain, "Front")) { return PAIN_FRONT; @@ -11203,7 +11165,6 @@ void Player::EventSetPerferredWeapon(Event *ev) } void Player::SetMouthAngle(Event *ev) - { int tag_num; float angle_percent; From 35e9f9982cae8dc2f759b72acad62d27f7bb1d75 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:19:59 +0100 Subject: [PATCH 0232/2040] Preallocate arguments for sp/dm commands --- code/fgame/entity.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 3b9156dc..711eaa05 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -6084,7 +6084,7 @@ void Entity::EventGetRotatedBbox(Event *ev) void Entity::EventSinglePlayerCommand(Event *ev) { if (g_gametype->integer == GT_SINGLE_PLAYER && !g_realismmode->integer) { - Event *newev = new Event(ev->GetToken(1)); + Event *newev = new Event(ev->GetToken(1), ev->NumArgs() - 1); for (int i = 2; i <= ev->NumArgs(); i++) { newev->AddToken(ev->GetToken(i)); @@ -6097,7 +6097,7 @@ void Entity::EventSinglePlayerCommand(Event *ev) void Entity::EventMultiPlayerCommand(Event *ev) { if (g_gametype->integer != GT_SINGLE_PLAYER && !g_realismmode->integer) { - Event *newev = new Event(ev->GetToken(1)); + Event *newev = new Event(ev->GetToken(1), ev->NumArgs() - 1); for (int i = 2; i <= ev->NumArgs(); i++) { newev->AddToken(ev->GetToken(i)); @@ -6110,7 +6110,7 @@ void Entity::EventMultiPlayerCommand(Event *ev) void Entity::EventRealismModeCommand(Event *ev) { if (g_realismmode->integer) { - Event *newev = new Event(ev->GetToken(1)); + Event *newev = new Event(ev->GetToken(1), ev->NumArgs() - 1); for (int i = 2; i <= ev->NumArgs(); i++) { newev->AddToken(ev->GetToken(i)); @@ -6122,8 +6122,8 @@ void Entity::EventRealismModeCommand(Event *ev) void Entity::EventSPRealismModeCommand(Event *ev) { - if (g_realismmode->integer && g_gametype->integer == GT_SINGLE_PLAYER) { - Event *newev = new Event(ev->GetToken(1)); + if (g_gametype->integer == GT_SINGLE_PLAYER && g_realismmode->integer) { + Event *newev = new Event(ev->GetToken(1), ev->NumArgs() - 1); for (int i = 2; i <= ev->NumArgs(); i++) { newev->AddToken(ev->GetToken(i)); @@ -6135,8 +6135,8 @@ void Entity::EventSPRealismModeCommand(Event *ev) void Entity::EventDMRealismModeCommand(Event *ev) { - if (g_realismmode->integer && g_gametype->integer != GT_SINGLE_PLAYER) { - Event *newev = new Event(ev->GetToken(1)); + if (g_gametype->integer != GT_SINGLE_PLAYER && g_realismmode->integer) { + Event *newev = new Event(ev->GetToken(1), ev->NumArgs() - 1); for (int i = 2; i <= ev->NumArgs(); i++) { newev->AddToken(ev->GetToken(i)); From f229c1c5a82a05103ca4e9a949d852c0d84d4d6f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:21:44 +0100 Subject: [PATCH 0233/2040] Fixed player health in SP --- code/fgame/player.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 88451905..bcd25456 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -2399,23 +2399,17 @@ void Player::InitHealth(void) return; } - if (g_gametype->integer != GT_SINGLE_PLAYER) { - if (pDMHealth->integer > 0) { - max_health = pDMHealth->integer; - } else { - max_health = 100.f; - } - - health = max_health; - } else if (!g_realismmode->integer) { + if (g_gametype->integer == GT_SINGLE_PLAYER && !g_realismmode->integer) { max_health = pMaxHealth->integer; - health = max_health; + } else if (g_gametype->integer != GT_SINGLE_PLAYER && pDMHealth->integer > 0) { + max_health = pDMHealth->integer; } else { // reset the health values - health = 100; - max_health = health; + max_health = 100; } + health = max_health; + // 2.0: // Make sure to clear the heal rate and the dead flag when respawning // From 593982d58649125774bb401063817a7fe138f982 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:53:18 +0100 Subject: [PATCH 0234/2040] Added assertion test --- code/renderer/tr_terrain.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 7ed98a69..80c4bb01 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -424,6 +424,8 @@ static void R_ForceSplit(terraInt iTri) terraTri_t* pBase = &g_pTris[iBase]; if (iBase && pBase->lod != pTri->lod) { + assert(g_pTris[pBase->iBase].iBase != iTri); + R_ForceSplit(iBase); iBase = pTri->iBase; pBase = &g_pTris[iBase]; From 9960884e3c8890383e034a7b6144cbef569f8cc4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:53:27 +0100 Subject: [PATCH 0235/2040] Initialize watchFadeTime --- code/fgame/camera.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/camera.cpp b/code/fgame/camera.cpp index 1f118927..c54b51d8 100644 --- a/code/fgame/camera.cpp +++ b/code/fgame/camera.cpp @@ -725,6 +725,7 @@ Camera::Camera() fadeTime = 2.0f; fovFadeTime = 1.0f; followFadeTime = 1.0f; + watchFadeTime = 1.0f; m_bShowquakes = false; setSolidType(SOLID_NOT); From 64604b5c44646920307e334c0ab5af654affeefe Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Feb 2024 18:43:42 +0100 Subject: [PATCH 0236/2040] Disable non-pvs sound in single-player This fixes #267 where configstrings are full --- code/fgame/entity.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 711eaa05..655c3fc4 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -6308,6 +6308,11 @@ void Entity::PlayNonPvsSound(const str& soundName, float volume) AliasListNode_t* ret; str name; + if (g_gametype->integer == GT_SINGLE_PLAYER) { + // Ignore in single-player + return; + } + if (edict->r.num_nonpvs_sounds >= MAX_NONPVS_SOUNDS) { return; } From 57870103a66ce7876d3b263c890feee01d6c5da0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Feb 2024 18:54:42 +0100 Subject: [PATCH 0237/2040] Fixed TriggerVehicle not responding to VehicleCollisionEntity --- code/fgame/trigger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/trigger.cpp b/code/fgame/trigger.cpp index a62fde94..1c504090 100644 --- a/code/fgame/trigger.cpp +++ b/code/fgame/trigger.cpp @@ -839,7 +839,7 @@ CLASS_DECLARATION(Trigger, TriggerVehicle, "trigger_vehicle") { qboolean TriggerVehicle::respondTo(Entity *other) { - if ((other->IsSubclassOfVehicle()) || isSubclassOf(VehicleCollisionEntity)) { + if ((other->IsSubclassOfVehicle()) || other->isSubclassOf(VehicleCollisionEntity)) { return qtrue; } else { return qfalse; From 2d6ac6f0be433932287ab0a7e1bb5037c4f339ef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Feb 2024 19:15:41 +0100 Subject: [PATCH 0238/2040] Fixed weapon melee AI broadcast --- code/fgame/weapon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index 98a37e51..cc26ed6e 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -2004,7 +2004,7 @@ void Weapon::Shoot(Event *ev) break; } - if (!quiet[firemodeindex]) { + if (!quiet[mode]) { if (next_noise_time <= level.time) { BroadcastAIEvent(AI_EVENT_WEAPON_FIRE); next_noise_time = level.time + 1; From 73c9e6f1d89ad4dd02a78a7d72f3c87b3006ad7a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Feb 2024 19:16:07 +0100 Subject: [PATCH 0239/2040] Ignore disabled ennemies --- code/fgame/actorenemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actorenemy.cpp b/code/fgame/actorenemy.cpp index 5c83595f..cb463d68 100644 --- a/code/fgame/actorenemy.cpp +++ b/code/fgame/actorenemy.cpp @@ -353,7 +353,7 @@ void ActorEnemySet::CheckEnemies(Actor *pSelf) pActorEnemy = &m_Enemies[i - 1]; if (!pActorEnemy->GetEnemy() || pActorEnemy->GetEnemy()->m_Team == pSelf->m_Team || pActorEnemy->GetEnemy()->IsDead() || level.inttime > pActorEnemy->m_iAddTime + 10000 - || pActorEnemy->GetEnemy()->m_iThreatBias == THREATBIAS_IGNOREME) { + || pActorEnemy->GetEnemy()->m_iThreatBias == THREATBIAS_IGNOREME || pActorEnemy->GetEnemy()->IsDisabled()) { m_Enemies.RemoveObjectAt(i); } else { i++; From c391605f616e6080ff887a7b881a74446401bc81 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Feb 2024 20:10:02 +0100 Subject: [PATCH 0240/2040] Fixed AI attacking the disguised player This fixes #203 --- code/fgame/actor_disguise_salute.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor_disguise_salute.cpp b/code/fgame/actor_disguise_salute.cpp index d55235ba..c1b0f62a 100644 --- a/code/fgame/actor_disguise_salute.cpp +++ b/code/fgame/actor_disguise_salute.cpp @@ -51,7 +51,7 @@ void Actor::Begin_DisguiseSalute(void) SetDesiredYawDest(m_Enemy->origin); SetDesiredLookDir(m_Enemy->origin - origin); - DesiredAnimation(ANIM_MODE_NORMAL, STRING_ANIM_DISGUISE_PAPERS_SCR); + DesiredAnimation(ANIM_MODE_NORMAL, STRING_ANIM_DISGUISE_SALUTE_SCR); } else { SetThinkState(THINKSTATE_ATTACK, THINKLEVEL_IDLE); } @@ -85,7 +85,12 @@ void Actor::Think_DisguiseSalute(void) return; } - if ((!EnemyIsDisguised() && !(m_Enemy->flags & FL_NOTARGET)) || level.m_bAlarm != qtrue) { + if (!EnemyIsDisguised() && !(m_Enemy->flags & FL_NOTARGET)) { + SetThinkState(THINKSTATE_ATTACK, THINKLEVEL_IDLE); + return; + } + + if (level.m_bAlarm == qtrue) { SetThinkState(THINKSTATE_ATTACK, THINKLEVEL_IDLE); return; } From e5275c0f055eda873bb5a3ee9a27414a77781a79 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Feb 2024 21:26:08 +0100 Subject: [PATCH 0241/2040] Fixed MASK_TRANSITION being wrong --- code/fgame/bg_public.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 5d14c9a5..3fce4de4 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -663,7 +663,7 @@ movement on the server game. #define MASK_CANSEE_NOENTS (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) #define MASK_CLICKITEM (MASK_SOLID | CONTENTS_UNKNOWN3) #define MASK_ITEM (CONTENTS_SOLID | CONTENTS_TRIGGER | CONTENTS_PLAYERCLIP | CONTENTS_FENCE) -#define MASK_TRANSITION (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) +#define MASK_TRANSITION (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) #define MASK_TARGETPATH \ (CONTENTS_SOLID | CONTENTS_TRIGGER | CONTENTS_MONSTERCLIP | CONTENTS_FENCE | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) #define MASK_ACTORPATH (CONTENTS_SOLID | CONTENTS_FENCE | CONTENTS_MONSTERCLIP | CONTENTS_TRIGGER) From 49a7a1f8ffee54d7f0ec015b04ca91df94ac43ef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:53:17 +0100 Subject: [PATCH 0242/2040] minimum visibility is 0.999 and not 1.0 --- code/fgame/actorenemy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/actorenemy.cpp b/code/fgame/actorenemy.cpp index cb463d68..f99020b4 100644 --- a/code/fgame/actorenemy.cpp +++ b/code/fgame/actorenemy.cpp @@ -389,7 +389,7 @@ void ActorEnemySet::CheckEnemies(Actor *pSelf) "ent #%3i: enemy #%i: awareness = %5.1f%%, threat = %i\n", pSelf->entnum, pActorEnemy->GetEnemy()->entnum, - (int)(fVisibility * 100.0), + (fVisibility * 100.0), 0 ); } @@ -420,7 +420,7 @@ void ActorEnemySet::CheckEnemies(Actor *pSelf) m_iCurrentThreat = 0; fRangeSquared = 1e37f; - if (m_fCurrentVisibility >= 1) { + if (m_fCurrentVisibility >= 0.999f) { iThreat = 0; for (i = 1; i <= m_Enemies.NumObjects(); i++) { From e32222884d59e37cb8ca9d8b4ddab6953be66b5d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:53:38 +0100 Subject: [PATCH 0243/2040] Fixed DisguiseSalute never finishing animation --- code/fgame/actor_disguise_salute.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/actor_disguise_salute.cpp b/code/fgame/actor_disguise_salute.cpp index c1b0f62a..75aa6041 100644 --- a/code/fgame/actor_disguise_salute.cpp +++ b/code/fgame/actor_disguise_salute.cpp @@ -31,6 +31,7 @@ void Actor::InitDisguiseSalute(GlobalFuncs_t *func) func->EndState = &Actor::End_DisguiseSalute; func->ResumeState = &Actor::Resume_DisguiseSalute; func->SuspendState = &Actor::Suspend_DisguiseSalute; + func->FinishedAnimation = &Actor::FinishedAnimation_DisguiseSalute; func->PassesTransitionConditions = &Actor::PassesTransitionConditions_Disguise; func->IsState = &Actor::IsDisguiseState; } From a6c1cbfd5041c3c1d3224c2a145451cee55c903d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 16:34:31 +0100 Subject: [PATCH 0244/2040] Added MASK_USE --- code/fgame/bg_public.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 3fce4de4..0824473c 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -661,6 +661,7 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 \ | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY) #define MASK_CANSEE_NOENTS (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP) +#define MASK_USE (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_BODY | CONTENTS_TRIGGER) #define MASK_CLICKITEM (MASK_SOLID | CONTENTS_UNKNOWN3) #define MASK_ITEM (CONTENTS_SOLID | CONTENTS_TRIGGER | CONTENTS_PLAYERCLIP | CONTENTS_FENCE) #define MASK_TRANSITION (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FENCE | CONTENTS_WEAPONCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BBOX) From 58d0e43f78615e3262eb199a103431d948a9be79 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:37:38 +0100 Subject: [PATCH 0245/2040] Use MASK_USE instead of MASK_SOLID --- code/fgame/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index bcd25456..57da2398 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -12441,7 +12441,7 @@ int Player::getUseableEntities(int *touch, int maxcount, bool requiresLookAt) end[2] = start[2] + (offset[2] * 88.f); } - trace = G_Trace(start, min, max, end, this, MASK_SOLID, false, "Player::getUseableEntity"); + trace = G_Trace(start, min, max, end, this, MASK_USE, false, "Player::getUseableEntity"); offset = trace.endpos; From e27ac45f44bffcb51fadc1d92529665609f3b354 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:08:21 +0100 Subject: [PATCH 0246/2040] Don't load TGA without alpha for collision --- code/qcommon/cm_fencemask.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/code/qcommon/cm_fencemask.c b/code/qcommon/cm_fencemask.c index a32291ac..70747b69 100644 --- a/code/qcommon/cm_fencemask.c +++ b/code/qcommon/cm_fencemask.c @@ -123,10 +123,14 @@ qboolean CM_LoadTGA( const char *name, byte **pic, int *width, int *height ) if(targa_header.colormap_type!=0) Com_Error (ERR_DROP, "LoadTGA: colormaps not supported\n"); - if (targa_header.colormap_type !=0 - || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) - Com_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + if (targa_header.pixel_size != 32) { + if (targa_header.pixel_size != 24 && targa_header.image_type != 3) { + Com_Error(ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + } + FS_FreeFile(buffer); + return qfalse; + } columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; From 4f868d9585fa66e1ab00904f72a1fde8d4b50582 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:19:38 +0100 Subject: [PATCH 0247/2040] Fixed a collision bug with fence masks --- code/qcommon/cm_trace.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/code/qcommon/cm_trace.c b/code/qcommon/cm_trace.c index 7122f200..d7238063 100644 --- a/code/qcommon/cm_trace.c +++ b/code/qcommon/cm_trace.c @@ -753,17 +753,17 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { return; } } - } - if( ( leaveFrac2 < 1.0 ) && ( leadside2->surfaceFlags & SURF_BACKSIDE ) ) { - if( leaveFrac2 < tw->trace.fraction ) { - if( CM_TraceThroughFence( tw, brush, leadside2, leaveFrac ) ) { - tw->trace.fraction = leaveFrac2; - tw->trace.plane = *clipplane2; - tw->trace.surfaceFlags = leadside2->surfaceFlags; - tw->trace.shaderNum = leadside2->shaderNum; - tw->trace.contents = brush->contents; - return; + if( ( leaveFrac2 < 1.0 ) && ( leadside2->surfaceFlags & SURF_BACKSIDE ) ) { + if( leaveFrac2 < tw->trace.fraction ) { + if( CM_TraceThroughFence( tw, brush, leadside2, leaveFrac ) ) { + tw->trace.fraction = leaveFrac2; + tw->trace.plane = *clipplane2; + tw->trace.surfaceFlags = leadside2->surfaceFlags; + tw->trace.shaderNum = leadside2->shaderNum; + tw->trace.contents = brush->contents; + return; + } } } } @@ -1754,12 +1754,12 @@ qboolean CM_SightTraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) return qfalse; } } - } - if( ( leaveFrac2 < 1.0 ) && ( leadside2->surfaceFlags & SURF_BACKSIDE ) ) { - if( leaveFrac2 < tw->trace.fraction ) { - if( CM_TraceThroughFence( tw, brush, leadside2, leaveFrac ) ) { - return qfalse; + if( ( leaveFrac2 < 1.0 ) && ( leadside2->surfaceFlags & SURF_BACKSIDE ) ) { + if( leaveFrac2 < tw->trace.fraction ) { + if( CM_TraceThroughFence( tw, brush, leadside2, leaveFrac ) ) { + return qfalse; + } } } } From d8b9abe7f52076b90d102934b1a254f501f20f27 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:21:12 +0100 Subject: [PATCH 0248/2040] Fixed call to GunTarget() It was specifying the position in the boolean parameter which lead to wrong results --- code/fgame/vehicleturret.cpp | 2 +- code/fgame/weapturret.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/vehicleturret.cpp b/code/fgame/vehicleturret.cpp index 1f03349d..5e58c1c9 100644 --- a/code/fgame/vehicleturret.cpp +++ b/code/fgame/vehicleturret.cpp @@ -1104,7 +1104,7 @@ void VehicleTurretGun::GetMuzzlePosition(vec3_t position, vec3_t vBarrelPos, vec VectorCopy(position, vBarrelPos); } - delta = viewer->GunTarget(position) - position; + delta = viewer->GunTarget(false, position) - position; aim_angles = delta.toAngles(); if (IsSubclassOfVehicleTurretGun()) { diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index c8327663..96685089 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -2111,7 +2111,7 @@ void TurretGun::GetMuzzlePosition(vec3_t position, vec3_t vBarrelPos, vec3_t for VectorCopy(position, vBarrelPos); } - delta = viewer->GunTarget(position) - position; + delta = viewer->GunTarget(false, position) - position; aim_angles = delta.toAngles(); if (IsSubclassOfVehicleTurretGun()) { From d972c85fba7b7b299a60739996db374eb471d9e9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:33:52 +0100 Subject: [PATCH 0249/2040] Formatted debuglines source file --- code/fgame/debuglines.cpp | 1312 ++++++++++++++++--------------------- code/fgame/debuglines.h | 5 +- 2 files changed, 565 insertions(+), 752 deletions(-) diff --git a/code/fgame/debuglines.cpp b/code/fgame/debuglines.cpp index 7aa7dfa2..16a4023d 100644 --- a/code/fgame/debuglines.cpp +++ b/code/fgame/debuglines.cpp @@ -21,371 +21,279 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // debuglines.cpp: -// +// #include "debuglines.h" #include "game.h" #define NUM_CIRCLE_SEGMENTS 24 -debugline_t *DebugLines = NULL; -debugstring_t *DebugStrings = NULL; -Vector currentVertex( 0, 0, 0 ); -Vector vertColor( 1, 1, 1 ); -float vertAlpha = 1; -float vertexIndex = 0; -float linewidth = 1; +debugline_t *DebugLines = NULL; +debugstring_t *DebugStrings = NULL; +Vector currentVertex(0, 0, 0); +Vector vertColor(1, 1, 1); +float vertAlpha = 1; +float vertexIndex = 0; +float linewidth = 1; unsigned short lineStippleFactor = 1; -unsigned short linePattern = 0xffff; -int g_iFirstLine; -int g_iCurrFrameLineCounter; -int g_iFrameLineCount[ 100 ]; +unsigned short linePattern = 0xffff; +int g_iFirstLine; +int g_iCurrFrameLineCounter; +int g_iFrameLineCount[100]; -void G_InitDebugLines - ( - void - ) +void G_InitDebugLines(void) { - if( g_numdebuglinedelays->integer <= 0 ) - { - *gi.DebugLines = DebugLines; - *gi.numDebugLines = 0; - g_iFirstLine = 0; + if (g_numdebuglinedelays->integer <= 0) { + *gi.DebugLines = DebugLines; + *gi.numDebugLines = 0; + g_iFirstLine = 0; - for( int i = 0; i < 100; i++ ) - { - g_iFrameLineCount[ i ] = 0; - } + for (int i = 0; i < 100; i++) { + g_iFrameLineCount[i] = 0; + } - g_iCurrFrameLineCounter = 0; - } - else - { - int iNumDelays = g_numdebuglinedelays->integer; - int iCount; + g_iCurrFrameLineCounter = 0; + } else { + int iNumDelays = g_numdebuglinedelays->integer; + int iCount; - if( iNumDelays > 99 ) - iNumDelays = 99; + if (iNumDelays > 99) { + iNumDelays = 99; + } - iCount = g_iFrameLineCount[ ( g_iCurrFrameLineCounter - iNumDelays + 100 ) % 100 ]; - if( iCount ) - { - g_iFirstLine += iCount; - *gi.numDebugLines -= iCount; - g_iFrameLineCount[ ( g_iCurrFrameLineCounter - iNumDelays + 100 ) % 100 ] = 0; - } + iCount = g_iFrameLineCount[(g_iCurrFrameLineCounter - iNumDelays + 100) % 100]; + if (iCount) { + g_iFirstLine += iCount; + *gi.numDebugLines -= iCount; + g_iFrameLineCount[(g_iCurrFrameLineCounter - iNumDelays + 100) % 100] = 0; + } - g_iCurrFrameLineCounter = ( g_iCurrFrameLineCounter + 1 ) % 100; - *gi.DebugLines = &DebugLines[ g_iFirstLine ]; - } + g_iCurrFrameLineCounter = (g_iCurrFrameLineCounter + 1) % 100; + *gi.DebugLines = &DebugLines[g_iFirstLine]; + } - currentVertex = vec_zero; - vertColor = Vector( 1, 1, 1 ); - vertAlpha = 1; - vertexIndex = 0; + currentVertex = vec_zero; + vertColor = Vector(1, 1, 1); + vertAlpha = 1; + vertexIndex = 0; - linewidth = 1; - lineStippleFactor = 1; - linePattern = 0xffff; + linewidth = 1; + lineStippleFactor = 1; + linePattern = 0xffff; } -void G_InitDebugStrings - ( - void - ) +void G_InitDebugStrings(void) { - *gi.DebugStrings = DebugStrings; - *gi.numDebugStrings = 0; + *gi.DebugStrings = DebugStrings; + *gi.numDebugStrings = 0; } -void G_AllocDebugLines - ( - void - ) +void G_AllocDebugLines(void) { - // we do a malloc here so that we don't interfere with the game's memory footprint - DebugLines = ( debugline_t * )malloc( ( int )g_numdebuglines->integer * sizeof( debugline_t ) ); + // we do a malloc here so that we don't interfere with the game's memory footprint + DebugLines = (debugline_t *)malloc((int)g_numdebuglines->integer * sizeof(debugline_t)); - G_InitDebugLines(); + G_InitDebugLines(); - for( int i = 0; i < 100; i++ ) - { - g_iFrameLineCount[ i ] = 0; - } + for (int i = 0; i < 100; i++) { + g_iFrameLineCount[i] = 0; + } - g_iCurrFrameLineCounter = 0; + g_iCurrFrameLineCounter = 0; } -void G_AllocDebugStrings - ( - void - ) +void G_AllocDebugStrings(void) { - DebugStrings = ( debugstring_t * )malloc( ( int )g_numdebugstrings->integer * sizeof( debugstring_t ) ); + DebugStrings = (debugstring_t *)malloc((int)g_numdebugstrings->integer * sizeof(debugstring_t)); - G_InitDebugStrings(); + G_InitDebugStrings(); } -void G_DeAllocDebugLines - ( - void - ) +void G_DeAllocDebugLines(void) { - if( DebugLines ) - { - // we do a free here, because we used malloc above - free( DebugLines ); - DebugLines = NULL; - *gi.DebugLines = DebugLines; - *gi.numDebugLines = 0; - } + if (DebugLines) { + // we do a free here, because we used malloc above + free(DebugLines); + DebugLines = NULL; + *gi.DebugLines = DebugLines; + *gi.numDebugLines = 0; + } } -void G_ShiftDebugLines - ( - void - ) +void G_ShiftDebugLines(void) { - int iNewPos; - int iOldPos; + int iNewPos; + int iOldPos; - for( iNewPos = 0; iNewPos < *gi.numDebugLines && iNewPos < g_numdebuglines->integer; iNewPos++ ) - { - iOldPos = g_iFirstLine + iNewPos; + for (iNewPos = 0; iNewPos < *gi.numDebugLines && iNewPos < g_numdebuglines->integer; iNewPos++) { + iOldPos = g_iFirstLine + iNewPos; - DebugLines[ iNewPos ] = DebugLines[ iOldPos ]; - } + DebugLines[iNewPos] = DebugLines[iOldPos]; + } - g_iFirstLine = 0; - *gi.DebugLines = DebugLines; + g_iFirstLine = 0; + *gi.DebugLines = DebugLines; } -void G_DeAllocDebugStrings - ( - void - ) +void G_DeAllocDebugStrings(void) { - if( DebugStrings ) - { - // we do a free here, because we used malloc above - free( DebugStrings ); - DebugStrings = NULL; - *gi.DebugStrings = DebugStrings; - *gi.numDebugStrings = 0; - } + if (DebugStrings) { + // we do a free here, because we used malloc above + free(DebugStrings); + DebugStrings = NULL; + *gi.DebugStrings = DebugStrings; + *gi.numDebugStrings = 0; + } } -void G_DebugLine - ( - Vector start, - Vector end, - float r, - float g, - float b, - float alpha - ) +void G_DebugLine(Vector start, Vector end, float r, float g, float b, float alpha) { - debugline_t *line; - static int printTime = 0; + debugline_t *line; + static int printTime = 0; - if( !g_numdebuglines->integer ) - { - return; - } + if (!g_numdebuglines->integer) { + return; + } - if( *gi.numDebugLines >= g_numdebuglines->integer ) - { - if( level.svsTime >= printTime ) - { - printTime = level.svsTime + 5000; - gi.DPrintf( "G_DebugLine: Exceeded MAX_DEBUG_LINES\n" ); - } + if (*gi.numDebugLines >= g_numdebuglines->integer) { + if (level.svsTime >= printTime) { + printTime = level.svsTime + 5000; + gi.DPrintf("G_DebugLine: Exceeded MAX_DEBUG_LINES\n"); + } - return; - } + return; + } - if( g_numdebuglinedelays->integer > 0 && g_iFirstLine > 0 && g_iFirstLine + *gi.numDebugLines + 1 >= g_numdebuglines->integer ) - { - G_ShiftDebugLines(); - } + if (g_numdebuglinedelays->integer > 0 && g_iFirstLine > 0 + && g_iFirstLine + *gi.numDebugLines + 1 >= g_numdebuglines->integer) { + G_ShiftDebugLines(); + } - line = &DebugLines[ *gi.numDebugLines ]; - ( *gi.numDebugLines )++; - g_iFrameLineCount[ g_iCurrFrameLineCounter ]++; + line = &DebugLines[*gi.numDebugLines]; + (*gi.numDebugLines)++; + g_iFrameLineCount[g_iCurrFrameLineCounter]++; - VectorCopy( start, line->start ); - VectorCopy( end, line->end ); - VectorSet( line->color, r, g, b ); - line->alpha = alpha; + VectorCopy(start, line->start); + VectorCopy(end, line->end); + VectorSet(line->color, r, g, b); + line->alpha = alpha; - line->width = linewidth; - line->factor = lineStippleFactor; - line->pattern = linePattern; + line->width = linewidth; + line->factor = lineStippleFactor; + line->pattern = linePattern; } -void G_LineStipple - ( - int factor, - unsigned short pattern - ) +void G_LineStipple(int factor, unsigned short pattern) +{ + lineStippleFactor = factor; + linePattern = pattern; +} - { - lineStippleFactor = factor; - linePattern = pattern; - } +void G_LineWidth(float width) +{ + linewidth = width; +} -void G_LineWidth - ( - float width - ) - - { - linewidth = width; - } +void G_Color3f(float r, float g, float b) +{ + vertColor = Vector(r, g, b); +} -void G_Color3f - ( - float r, - float g, - float b - ) +void G_Color3v(Vector color) +{ + vertColor = color; +} - { - vertColor = Vector( r, g, b ); - } +void G_Color4f(float r, float g, float b, float alpha) +{ + vertColor = Vector(r, g, b); + vertAlpha = alpha; +} -void G_Color3v - ( - Vector color - ) +void G_Color3vf(Vector color, float alpha) +{ + vertColor = color; + vertAlpha = alpha; +} - { - vertColor = color; - } +void G_BeginLine(void) +{ + currentVertex = vec_zero; + vertexIndex = 0; +} -void G_Color4f - ( - float r, - float g, - float b, - float alpha - ) +void G_Vertex(Vector v) +{ + vertexIndex++; + if (vertexIndex > 1) { + G_DebugLine(currentVertex, v, vertColor[0], vertColor[1], vertColor[2], vertAlpha); + } + currentVertex = v; +} - { - vertColor = Vector( r, g, b ); - vertAlpha = alpha; - } +void G_EndLine(void) +{ + currentVertex = vec_zero; + vertexIndex = 0; +} -void G_Color3vf - ( - Vector color, - float alpha - ) +void G_DebugBBox(Vector org, Vector mins, Vector maxs, float r, float g, float b, float alpha) +{ + int i; + Vector points[8]; - { - vertColor = color; - vertAlpha = alpha; - } - -void G_BeginLine - ( - void - ) - - { - currentVertex = vec_zero; - vertexIndex = 0; - } - -void G_Vertex - ( - Vector v - ) - - { - vertexIndex++; - if ( vertexIndex > 1 ) - { - G_DebugLine( currentVertex, v, vertColor[ 0 ], vertColor[ 1 ], vertColor[ 2 ], vertAlpha ); - } - currentVertex = v; - } - -void G_EndLine - ( - void - ) - - { - currentVertex = vec_zero; - vertexIndex = 0; - } - -void G_DebugBBox - ( - Vector org, - Vector mins, - Vector maxs, - float r, - float g, - float b, - float alpha - ) - { - int i; - Vector points[8]; - - /* + /* ** compute a full bounding box */ - for ( i = 0; i < 8; i++ ) - { - Vector tmp; + for (i = 0; i < 8; i++) { + Vector tmp; - if ( i & 1 ) - tmp[0] = org[0] + mins[0]; - else - tmp[0] = org[0] + maxs[0]; + if (i & 1) { + tmp[0] = org[0] + mins[0]; + } else { + tmp[0] = org[0] + maxs[0]; + } - if ( i & 2 ) - tmp[1] = org[1] + mins[1]; - else - tmp[1] = org[1] + maxs[1]; + if (i & 2) { + tmp[1] = org[1] + mins[1]; + } else { + tmp[1] = org[1] + maxs[1]; + } - if ( i & 4 ) - tmp[2] = org[2] + mins[2]; - else - tmp[2] = org[2] + maxs[2]; + if (i & 4) { + tmp[2] = org[2] + mins[2]; + } else { + tmp[2] = org[2] + maxs[2]; + } - points[i] = tmp; - } + points[i] = tmp; + } - G_Color4f( r, g, b, alpha ); + G_Color4f(r, g, b, alpha); - G_BeginLine(); - G_Vertex( points[0] ); - G_Vertex( points[1] ); - G_Vertex( points[3] ); - G_Vertex( points[2] ); - G_Vertex( points[0] ); - G_EndLine(); + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[1]); + G_Vertex(points[3]); + G_Vertex(points[2]); + G_Vertex(points[0]); + G_EndLine(); - G_BeginLine(); - G_Vertex( points[4] ); - G_Vertex( points[5] ); - G_Vertex( points[7] ); - G_Vertex( points[6] ); - G_Vertex( points[4] ); - G_EndLine(); + G_BeginLine(); + G_Vertex(points[4]); + G_Vertex(points[5]); + G_Vertex(points[7]); + G_Vertex(points[6]); + G_Vertex(points[4]); + G_EndLine(); - for ( i = 0; i < 4; i++ ) - { - G_BeginLine(); - G_Vertex( points[i] ); - G_Vertex( points[4 + i] ); - G_EndLine(); - } - } + for (i = 0; i < 4; i++) { + G_BeginLine(); + G_Vertex(points[i]); + G_Vertex(points[4 + i]); + G_EndLine(); + } +} // // LED style digits @@ -401,500 +309,408 @@ void G_DebugBBox // ****3*** 12** // 11 -static int Numbers[ 12 ][ 8 ] = - { - { 1, 3, 4, 5, 6, 7, 0, 0 }, // 0 - { 4, 5, 0, 0, 0, 0, 0, 0 }, // 1 - { 1, 4, 2, 7, 3, 0, 0, 0 }, // 2 - { 1, 4, 2, 5, 3, 0, 0, 0 }, // 3 - { 6, 4, 2, 5, 0, 0, 0, 0 }, // 4 - { 1, 6, 2, 5, 3, 0, 0, 0 }, // 5 - { 1, 6, 2, 5, 7, 3, 0, 0 }, // 6 - { 1, 8, 0, 0, 0, 0, 0, 0 }, // 7 - { 1, 2, 3, 4, 5, 6, 7, 0 }, // 8 - { 1, 6, 4, 2, 5, 3, 0, 0 }, // 9 - { 9, 10, 11, 12, 0, 0, 0, 0 }, // . - { 2, 0, 0, 0, 0, 0, 0, 0 }, // - - }; +static int Numbers[12][8] = { + {1, 3, 4, 5, 6, 7, 0, 0}, // 0 + {4, 5, 0, 0, 0, 0, 0, 0}, // 1 + {1, 4, 2, 7, 3, 0, 0, 0}, // 2 + {1, 4, 2, 5, 3, 0, 0, 0}, // 3 + {6, 4, 2, 5, 0, 0, 0, 0}, // 4 + {1, 6, 2, 5, 3, 0, 0, 0}, // 5 + {1, 6, 2, 5, 7, 3, 0, 0}, // 6 + {1, 8, 0, 0, 0, 0, 0, 0}, // 7 + {1, 2, 3, 4, 5, 6, 7, 0}, // 8 + {1, 6, 4, 2, 5, 3, 0, 0}, // 9 + {9, 10, 11, 12, 0, 0, 0, 0}, // . + {2, 0, 0, 0, 0, 0, 0, 0}, // - +}; -static float Lines[ 13 ][ 4 ] = - { - { 0, 0, 0, 0 }, // Unused - { -4, 8, 4, 8 }, // 1 - { -4, 4, 4, 4 }, // 2 - { -4, 0, 4, 0 }, // 3 - { 4, 8, 4, 4 }, // 4 - { 4, 4, 4, 0 }, // 5 - { -4, 8, -4, 4 }, // 6 - { -4, 4, -4, 0 }, // 7 - { 4, 8, -4, 0 }, // 8 +static float Lines[13][4] = { + {0, 0, 0, 0}, // Unused + {-4, 8, 4, 8}, // 1 + {-4, 4, 4, 4}, // 2 + {-4, 0, 4, 0}, // 3 + {4, 8, 4, 4}, // 4 + {4, 4, 4, 0}, // 5 + {-4, 8, -4, 4}, // 6 + {-4, 4, -4, 0}, // 7 + {4, 8, -4, 0}, // 8 - { -1, 2, 1, 2 }, // 9 - { 1, 2, 1, 0 }, // 10 - { -1, 0, 1, 0 }, // 11 - { -1, 0, -1, 2 }, // 12 - }; + {-1, 2, 1, 2}, // 9 + {1, 2, 1, 0}, // 10 + {-1, 0, 1, 0}, // 11 + {-1, 0, -1, 2}, // 12 +}; -void G_DrawDebugNumber - ( - Vector org, - float number, - float scale, - float r, - float g, - float b, - int precision - ) +void G_DrawDebugNumber(Vector org, float number, float scale, float r, float g, float b, int precision) { - int i; - int j; - int l; - int num; - Vector up; - Vector left; - Vector pos; - Vector start; - Vector ang; - str text; - Vector delta; - char format[ 20 ]; + int i; + int j; + int l; + int num; + Vector up; + Vector left; + Vector pos; + Vector start; + Vector ang; + str text; + Vector delta; + char format[20]; - // only draw entity numbers within a certain radius - delta = Vector( g_entities[ 0 ].s.origin ) - org; - if( ( delta * delta ) > ( 1000 * 1000 ) ) - { - return; - } + // only draw entity numbers within a certain radius + delta = Vector(g_entities[0].s.origin) - org; + if ((delta * delta) > (1000 * 1000)) { + return; + } - G_Color4f( r, g, b, 1.0 ); + G_Color4f(r, g, b, 1.0); - ang = game.clients[ 0 ].ps.viewangles; - ang.AngleVectorsLeft( NULL, &left, &up ); + ang = game.clients[0].ps.viewangles; + ang.AngleVectorsLeft(NULL, &left, &up); - up *= scale; - left *= scale; + up *= scale; + left *= scale; - if( precision > 0 ) - { - sprintf( format, "%%.%df", precision ); - text = va( format, number ); - } - else - { - text = va( "%d", ( int )number ); - } + if (precision > 0) { + sprintf(format, "%%.%df", precision); + text = va(format, number); + } else { + text = va("%d", (int)number); + } - start = org + ( text.length() - 1 ) * 5 * left; + start = org + (text.length() - 1) * 5 * left; - for( i = 0; i < text.length(); i++ ) - { - if( text[ i ] == '.' ) - { - num = 10; - } - else if( text[ i ] == '-' ) - { - num = 11; - } - else - { - num = text[ i ] - '0'; - } + for (i = 0; i < text.length(); i++) { + if (text[i] == '.') { + num = 10; + } else if (text[i] == '-') { + num = 11; + } else { + num = text[i] - '0'; + } - for( j = 0; j < 8; j++ ) - { - l = Numbers[ num ][ j ]; - if( l == 0 ) - { - break; - } + for (j = 0; j < 8; j++) { + l = Numbers[num][j]; + if (l == 0) { + break; + } - G_BeginLine(); + G_BeginLine(); - pos = start - Lines[ l ][ 0 ] * left + Lines[ l ][ 1 ] * up; - G_Vertex( pos ); + pos = start - Lines[l][0] * left + Lines[l][1] * up; + G_Vertex(pos); - pos = start - Lines[ l ][ 2 ] * left + Lines[ l ][ 3 ] * up; - G_Vertex( pos ); + pos = start - Lines[l][2] * left + Lines[l][3] * up; + G_Vertex(pos); - G_EndLine(); - } + G_EndLine(); + } - start -= 10 * left; - } + start -= 10 * left; + } } -void G_DebugCircle - ( - float *org, - float radius, - float r, - float g, - float b, - float alpha, - qboolean horizontal - ) - { - int i; - float ang; - Vector angles; - Vector forward; - Vector left; - Vector pos; - Vector delta; - - // only draw circles within a certain radius - delta = Vector( g_entities[ 0 ].s.origin ) - org; - if ( ( delta * delta ) > ( ( 1000 + radius ) * ( 1000 + radius ) ) ) - { - return; - } - - G_Color4f( r, g, b, alpha ); - - if ( horizontal ) - { - forward = "1 0 0"; - left = "0 -1 0"; - } - else - { - angles = game.clients[ 0 ].ps.viewangles; - angles.AngleVectors( NULL, &left, &forward ); - } - - G_BeginLine(); - for( i = 0; i <= NUM_CIRCLE_SEGMENTS; i++ ) - { - ang = DEG2RAD( i * 360 / NUM_CIRCLE_SEGMENTS ); - pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); - G_Vertex( pos ); - } - G_EndLine(); - } - -void G_DebugOrientedCircle - ( - Vector org, - float radius, - float r, - float g, - float b, - float alpha, - Vector angles - ) - { - int i; - float ang; - Vector forward; - Vector left; - Vector pos; - Vector delta; - - // only draw circles within a certain radius - delta = Vector( g_entities[ 0 ].s.origin ) - org; - if ( ( delta * delta ) > ( ( 1000 + radius ) * ( 1000 + radius ) ) ) - { - return; - } - - G_Color4f( r, g, b, alpha ); - - angles.AngleVectors( NULL, &left, &forward ); - - G_BeginLine(); - for( i = 0; i <= NUM_CIRCLE_SEGMENTS; i++ ) - { - ang = DEG2RAD( i * 360 / NUM_CIRCLE_SEGMENTS ); - pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); - G_Vertex( pos ); - } - G_EndLine(); - - // - // Draw the cross sign - // - G_BeginLine(); - ang = DEG2RAD( 45 * 360 / NUM_CIRCLE_SEGMENTS ); - pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); - G_Vertex( pos ); - ang = DEG2RAD( 225 * 360 / NUM_CIRCLE_SEGMENTS ); - pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); - G_Vertex( pos ); - - G_BeginLine(); - ang = DEG2RAD( 315 * 360 / NUM_CIRCLE_SEGMENTS ); - pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); - G_Vertex( pos ); - ang = DEG2RAD( 135 * 360 / NUM_CIRCLE_SEGMENTS ); - pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); - G_Vertex( pos ); - } - -void G_DebugPyramid - ( - Vector org, - float radius, - float r, - float g, - float b, - float alpha - ) - { - Vector delta; - Vector points[ 4 ]; - - // only draw pyramids within a certain radius - delta = Vector( g_entities[ 0 ].s.origin ) - org; - if ( ( delta * delta ) > ( ( 1000 + radius ) * ( 1000 + radius ) ) ) - { - return; - } - - G_Color4f( r, g, b, alpha ); - - points[ 0 ] = org; - points[ 0 ].z += radius; - - points[ 1 ] = org; - points[ 1 ].z -= radius; - points[ 2 ] = points[ 1 ]; - points[ 3 ] = points[ 1 ]; - - points[ 1 ].x += cos( DEG2RAD( 0 ) ) * radius; - points[ 1 ].y += sin( DEG2RAD( 0 ) ) * radius; - points[ 2 ].x += cos( DEG2RAD( 120 ) ) * radius; - points[ 2 ].y += sin( DEG2RAD( 120 ) ) * radius; - points[ 3 ].x += cos( DEG2RAD( 240 ) ) * radius; - points[ 3 ].y += sin( DEG2RAD( 240 ) ) * radius; - - G_BeginLine(); - G_Vertex( points[ 0 ] ); - G_Vertex( points[ 1 ] ); - G_Vertex( points[ 2 ] ); - G_Vertex( points[ 0 ] ); - G_EndLine(); - - G_BeginLine(); - G_Vertex( points[ 0 ] ); - G_Vertex( points[ 2 ] ); - G_Vertex( points[ 3 ] ); - G_Vertex( points[ 0 ] ); - G_EndLine(); - - G_BeginLine(); - G_Vertex( points[ 0 ] ); - G_Vertex( points[ 3 ] ); - G_Vertex( points[ 1 ] ); - G_Vertex( points[ 0 ] ); - G_EndLine(); - - G_BeginLine(); - G_Vertex( points[ 1 ] ); - G_Vertex( points[ 2 ] ); - G_Vertex( points[ 3 ] ); - G_Vertex( points[ 1 ] ); - G_EndLine(); - } - -void G_DrawCoordSystem - ( - Vector pos, - Vector forward, - Vector right, - Vector up, - int length - ) - - { - if ( g_showaxis->integer ) - { - G_DebugLine( pos, pos + forward * length, 1,0,0,1 ); - G_DebugLine( pos, pos + right * length, 0,1,0,1 ); - G_DebugLine( pos, pos + up * length, 0,0,1,1 ); - } - } - -void G_DrawCSystem - ( - Vector pos, - Vector forward, - Vector right, - Vector up, - int length - ) +void G_DebugCircle(float *org, float radius, float r, float g, float b, float alpha, qboolean horizontal) { - G_DebugLine( pos, pos + forward * length, 1.0, 0, 0, 1 ); - G_DebugLine( pos, pos + right * length, 0, 1.0, 0, 1 ); - G_DebugLine( pos, pos + up * length, 0, 0, 1.0, 1 ); + int i; + float ang; + Vector angles; + Vector forward; + Vector left; + Vector pos; + Vector delta; + + // only draw circles within a certain radius + delta = Vector(g_entities[0].s.origin) - org; + if ((delta * delta) > ((1000 + radius) * (1000 + radius))) { + return; + } + + G_Color4f(r, g, b, alpha); + + if (horizontal) { + forward = "1 0 0"; + left = "0 -1 0"; + } else { + angles = game.clients[0].ps.viewangles; + angles.AngleVectors(NULL, &left, &forward); + } + + G_BeginLine(); + for (i = 0; i <= NUM_CIRCLE_SEGMENTS; i++) { + ang = DEG2RAD(i * 360 / NUM_CIRCLE_SEGMENTS); + pos = org + (sin(ang) * radius * forward) - (cos(ang) * radius * left); + G_Vertex(pos); + } + G_EndLine(); } -void G_DebugArrow - ( - Vector org, - Vector dir, - float length, - float r, - float g, - float b, - float alpha - ) - { - Vector right; - Vector up; - Vector startpoint; - Vector endpoint; +void G_DebugOrientedCircle(Vector org, float radius, float r, float g, float b, float alpha, Vector angles) +{ + int i; + float ang; + Vector forward; + Vector left; + Vector pos; + Vector delta; - PerpendicularVector( right, dir ); - up.CrossProduct( right, dir ); + // only draw circles within a certain radius + delta = Vector(g_entities[0].s.origin) - org; + if ((delta * delta) > ((1000 + radius) * (1000 + radius))) { + return; + } - startpoint = org; + G_Color4f(r, g, b, alpha); - endpoint = startpoint + dir * length; - length /= 6; - G_DebugLine( startpoint, endpoint, r, g, b, alpha ); - G_DebugLine( endpoint, endpoint - (right * length) - (dir * length), r, g, b, alpha ); - G_DebugLine( endpoint, endpoint + (right * length) - (dir * length), r, g, b, alpha ); - G_DebugLine( endpoint, endpoint - (up * length) - (dir * length), r, g, b, alpha ); - G_DebugLine( endpoint, endpoint + (up * length) - (dir * length), r, g, b, alpha ); - } + angles.AngleVectors(NULL, &left, &forward); -void G_DebugHighlightFacet - ( - Vector org, - Vector mins, - Vector maxs, - facet_t facet, - float r, - float g, - float b, - float alpha - ) - { - int i; - Vector points[8]; + G_BeginLine(); + for (i = 0; i <= NUM_CIRCLE_SEGMENTS; i++) { + ang = DEG2RAD(i * 360 / NUM_CIRCLE_SEGMENTS); + pos = org + (sin(ang) * radius * forward) - (cos(ang) * radius * left); + G_Vertex(pos); + } + G_EndLine(); - /* + // + // Draw the cross sign + // + G_BeginLine(); + ang = DEG2RAD(45 * 360 / NUM_CIRCLE_SEGMENTS); + pos = org + (sin(ang) * radius * forward) - (cos(ang) * radius * left); + G_Vertex(pos); + ang = DEG2RAD(225 * 360 / NUM_CIRCLE_SEGMENTS); + pos = org + (sin(ang) * radius * forward) - (cos(ang) * radius * left); + G_Vertex(pos); + + G_BeginLine(); + ang = DEG2RAD(315 * 360 / NUM_CIRCLE_SEGMENTS); + pos = org + (sin(ang) * radius * forward) - (cos(ang) * radius * left); + G_Vertex(pos); + ang = DEG2RAD(135 * 360 / NUM_CIRCLE_SEGMENTS); + pos = org + (sin(ang) * radius * forward) - (cos(ang) * radius * left); + G_Vertex(pos); +} + +void G_DebugPyramid(Vector org, float radius, float r, float g, float b, float alpha) +{ + Vector delta; + Vector points[4]; + + // only draw pyramids within a certain radius + delta = Vector(g_entities[0].s.origin) - org; + if ((delta * delta) > ((1000 + radius) * (1000 + radius))) { + return; + } + + G_Color4f(r, g, b, alpha); + + points[0] = org; + points[0].z += radius; + + points[1] = org; + points[1].z -= radius; + points[2] = points[1]; + points[3] = points[1]; + + points[1].x += cos(DEG2RAD(0)) * radius; + points[1].y += sin(DEG2RAD(0)) * radius; + points[2].x += cos(DEG2RAD(120)) * radius; + points[2].y += sin(DEG2RAD(120)) * radius; + points[3].x += cos(DEG2RAD(240)) * radius; + points[3].y += sin(DEG2RAD(240)) * radius; + + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[1]); + G_Vertex(points[2]); + G_Vertex(points[0]); + G_EndLine(); + + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[2]); + G_Vertex(points[3]); + G_Vertex(points[0]); + G_EndLine(); + + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[3]); + G_Vertex(points[1]); + G_Vertex(points[0]); + G_EndLine(); + + G_BeginLine(); + G_Vertex(points[1]); + G_Vertex(points[2]); + G_Vertex(points[3]); + G_Vertex(points[1]); + G_EndLine(); +} + +void G_DrawCoordSystem(Vector pos, Vector forward, Vector right, Vector up, int length) +{ + if (g_showaxis->integer) { + G_DebugLine(pos, pos + forward * length, 1, 0, 0, 1); + G_DebugLine(pos, pos + right * length, 0, 1, 0, 1); + G_DebugLine(pos, pos + up * length, 0, 0, 1, 1); + } +} + +void G_DrawCSystem(Vector pos, Vector forward, Vector right, Vector up, int length) +{ + G_DebugLine(pos, pos + forward * length, 1.0, 0, 0, 1); + G_DebugLine(pos, pos + right * length, 0, 1.0, 0, 1); + G_DebugLine(pos, pos + up * length, 0, 0, 1.0, 1); +} + +void G_DebugArrow(Vector org, Vector dir, float length, float r, float g, float b, float alpha) +{ + Vector right; + Vector up; + Vector startpoint; + Vector endpoint; + + PerpendicularVector(right, dir); + up.CrossProduct(right, dir); + + startpoint = org; + + endpoint = startpoint + dir * length; + length /= 6; + G_DebugLine(startpoint, endpoint, r, g, b, alpha); + G_DebugLine(endpoint, endpoint - (right * length) - (dir * length), r, g, b, alpha); + G_DebugLine(endpoint, endpoint + (right * length) - (dir * length), r, g, b, alpha); + G_DebugLine(endpoint, endpoint - (up * length) - (dir * length), r, g, b, alpha); + G_DebugLine(endpoint, endpoint + (up * length) - (dir * length), r, g, b, alpha); +} + +void G_DebugHighlightFacet(Vector org, Vector mins, Vector maxs, facet_t facet, float r, float g, float b, float alpha) +{ + int i; + Vector points[8]; + + /* ** compute a full bounding box */ - for ( i = 0; i < 8; i++ ) - { - Vector tmp; + for (i = 0; i < 8; i++) { + Vector tmp; - if ( i & 1 ) - tmp[0] = org[0] + mins[0]; - else - tmp[0] = org[0] + maxs[0]; + if (i & 1) { + tmp[0] = org[0] + mins[0]; + } else { + tmp[0] = org[0] + maxs[0]; + } - if ( i & 2 ) - tmp[1] = org[1] + mins[1]; - else - tmp[1] = org[1] + maxs[1]; + if (i & 2) { + tmp[1] = org[1] + mins[1]; + } else { + tmp[1] = org[1] + maxs[1]; + } - if ( i & 4 ) - tmp[2] = org[2] + mins[2]; - else - tmp[2] = org[2] + maxs[2]; + if (i & 4) { + tmp[2] = org[2] + mins[2]; + } else { + tmp[2] = org[2] + maxs[2]; + } - points[i] = tmp; - } + points[i] = tmp; + } - G_Color4f( r, g, b, alpha ); + G_Color4f(r, g, b, alpha); - switch( facet ) - { - case north: - G_BeginLine(); - G_Vertex( points[0] ); - G_Vertex( points[5] ); - G_EndLine(); - G_BeginLine(); - G_Vertex( points[1] ); - G_Vertex( points[4] ); - G_EndLine(); - break; - case south: - G_BeginLine(); - G_Vertex( points[2] ); - G_Vertex( points[7] ); - G_EndLine(); - G_BeginLine(); - G_Vertex( points[3] ); - G_Vertex( points[6] ); - G_EndLine(); - break; - case east: - G_BeginLine(); - G_Vertex( points[0] ); - G_Vertex( points[6] ); - G_EndLine(); - G_BeginLine(); - G_Vertex( points[4] ); - G_Vertex( points[2] ); - G_EndLine(); - break; - case west: - G_BeginLine(); - G_Vertex( points[1] ); - G_Vertex( points[7] ); - G_EndLine(); - G_BeginLine(); - G_Vertex( points[5] ); - G_Vertex( points[3] ); - G_EndLine(); - break; - case up: - G_BeginLine(); - G_Vertex( points[0] ); - G_Vertex( points[3] ); - G_EndLine(); - G_BeginLine(); - G_Vertex( points[1] ); - G_Vertex( points[2] ); - G_EndLine(); - break; - case down: - G_BeginLine(); - G_Vertex( points[4] ); - G_Vertex( points[7] ); - G_EndLine(); - G_BeginLine(); - G_Vertex( points[5] ); - G_Vertex( points[6] ); - G_EndLine(); - break; - } - } + switch (facet) { + case north: + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[5]); + G_EndLine(); + G_BeginLine(); + G_Vertex(points[1]); + G_Vertex(points[4]); + G_EndLine(); + break; + case south: + G_BeginLine(); + G_Vertex(points[2]); + G_Vertex(points[7]); + G_EndLine(); + G_BeginLine(); + G_Vertex(points[3]); + G_Vertex(points[6]); + G_EndLine(); + break; + case east: + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[6]); + G_EndLine(); + G_BeginLine(); + G_Vertex(points[4]); + G_Vertex(points[2]); + G_EndLine(); + break; + case west: + G_BeginLine(); + G_Vertex(points[1]); + G_Vertex(points[7]); + G_EndLine(); + G_BeginLine(); + G_Vertex(points[5]); + G_Vertex(points[3]); + G_EndLine(); + break; + case up: + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[3]); + G_EndLine(); + G_BeginLine(); + G_Vertex(points[1]); + G_Vertex(points[2]); + G_EndLine(); + break; + case down: + G_BeginLine(); + G_Vertex(points[4]); + G_Vertex(points[7]); + G_EndLine(); + G_BeginLine(); + G_Vertex(points[5]); + G_Vertex(points[6]); + G_EndLine(); + break; + } +} - void G_DebugString(Vector pos, float scale, float r, float g, float b, const char* pszText, ...) - { - debugstring_t* string; - va_list va; - char szTemp[32768]; +void G_DebugString(Vector pos, float scale, float r, float g, float b, const char *pszText, ...) +{ + debugstring_t *string; + va_list va; + char szTemp[32768]; - if (!g_numdebugstrings) { - return; - } + if (!g_numdebugstrings) { + return; + } - if (*gi.numDebugStrings < g_numdebugstrings->integer) { - string = (debugstring_t*)&DebugStrings[*gi.numDebugStrings]; + if (*gi.numDebugStrings < g_numdebugstrings->integer) { + string = (debugstring_t *)&DebugStrings[*gi.numDebugStrings]; - (*gi.numDebugStrings)++; + (*gi.numDebugStrings)++; - va_start(va, pszText); - vsprintf(szTemp, pszText, va); - va_end(va); + va_start(va, pszText); + vsprintf(szTemp, pszText, va); + va_end(va); - VectorCopy(pos, string->pos); - string->scale = scale; - string->color[0] = r; - string->color[1] = g; - string->color[2] = b; - string->color[3] = 1.0f; - strncpy(string->szText, szTemp, sizeof(string->szText)); - string->szText[sizeof(string->szText) - 1] = 0; - } - else { - gi.DPrintf("G_DebugString: Exceeded g_numdebugstrings\n"); - } - } + VectorCopy(pos, string->pos); + string->scale = scale; + string->color[0] = r; + string->color[1] = g; + string->color[2] = b; + string->color[3] = 1.0f; + strncpy(string->szText, szTemp, sizeof(string->szText)); + string->szText[sizeof(string->szText) - 1] = 0; + } else { + gi.DPrintf("G_DebugString: Exceeded g_numdebugstrings\n"); + } +} diff --git a/code/fgame/debuglines.h b/code/fgame/debuglines.h index 9d497460..ebd1a6de 100644 --- a/code/fgame/debuglines.h +++ b/code/fgame/debuglines.h @@ -22,8 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // debuglines.h: -#ifndef __DEBUGLINES_H__ -#define __DEBUGLINES_H__ +#pragma once #include "g_local.h" @@ -67,5 +66,3 @@ void G_DebugHighlightFacet( Vector org, Vector mins, Vector maxs, facet_t facet, extern debugline_t *DebugLines; extern debugstring_t *DebugStrings; - -#endif /* !__DEBUGLINES_H__ */ From 8324c599de990163be68032e79a042bd471f1ea1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:56:23 +0100 Subject: [PATCH 0250/2040] Implemented G_DebugRotatedBBox --- code/fgame/debuglines.cpp | 62 +++++++++++++++++++++++++++++++++++++++ code/fgame/debuglines.h | 1 + 2 files changed, 63 insertions(+) diff --git a/code/fgame/debuglines.cpp b/code/fgame/debuglines.cpp index 16a4023d..b8e41309 100644 --- a/code/fgame/debuglines.cpp +++ b/code/fgame/debuglines.cpp @@ -295,6 +295,68 @@ void G_DebugBBox(Vector org, Vector mins, Vector maxs, float r, float g, float b } } +void G_DebugRotatedBBox(Vector org, Vector ang, Vector mins, Vector maxs, float r, float g, float b, float alpha) { + int i; + Vector tmp; + Vector points[8]; + vec3_t axis[3]; + + AnglesToAxis(ang, axis); + + /* + ** compute a full bounding box + */ + for (i = 0; i < 8; i++) { + Vector tmp; + + if (i & 1) { + tmp[0] = mins[0]; + } else { + tmp[0] = maxs[0]; + } + + if (i & 2) { + tmp[1] = mins[1]; + } else { + tmp[1] = maxs[1]; + } + + if (i & 4) { + tmp[2] = mins[2]; + } else { + tmp[2] = maxs[2]; + } + + MatrixTransformVector(tmp, axis, points[i]); + points[i] += org; + } + + G_Color4f(r, g, b, alpha); + + G_BeginLine(); + G_Vertex(points[0]); + G_Vertex(points[1]); + G_Vertex(points[3]); + G_Vertex(points[2]); + G_Vertex(points[0]); + G_EndLine(); + + G_BeginLine(); + G_Vertex(points[4]); + G_Vertex(points[5]); + G_Vertex(points[7]); + G_Vertex(points[6]); + G_Vertex(points[4]); + G_EndLine(); + + for (i = 0; i < 4; i++) { + G_BeginLine(); + G_Vertex(points[i]); + G_Vertex(points[4 + i]); + G_EndLine(); + } +} + // // LED style digits // diff --git a/code/fgame/debuglines.h b/code/fgame/debuglines.h index ebd1a6de..e0656332 100644 --- a/code/fgame/debuglines.h +++ b/code/fgame/debuglines.h @@ -39,6 +39,7 @@ void G_BeginLine( void ); void G_Vertex( Vector v ); void G_EndLine( void ); void G_DebugBBox( Vector org, Vector mins, Vector maxs, float r, float g, float b, float alpha ); +void G_DebugRotatedBBox(Vector org, Vector ang, Vector mins, Vector maxs, float r, float g, float b, float alpha); void G_DrawDebugNumber( Vector org, float number, float scale, float r, float g, float b, int precision = 0 ); void G_DebugCircle( float *org, float radius, float r, float g, float b, float alpha, qboolean horizontal = qfalse ); void G_DebugOrientedCircle( Vector org, float radius, float r, float g, float b, float alpha, Vector angles ); From 12e36b987ad54eeb8f79eb40ad8fb5013b0b96d8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:56:35 +0100 Subject: [PATCH 0251/2040] Use G_DebugRotatedBBox when drawing the entity's bounding box --- code/fgame/entity.cpp | 45 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 655c3fc4..471b4bff 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -5933,7 +5933,7 @@ void Entity::DrawBoundingBox(int showbboxes) switch (showbboxes) { case 1: if (edict->s.solid) { - G_DebugBBox(origin, mins, maxs, 1, 1, 0, 1); + G_DebugRotatedBBox(origin, angles, mins, maxs, 1, 1, 0, 1); } break; case 2: @@ -5943,13 +5943,48 @@ void Entity::DrawBoundingBox(int showbboxes) break; case 3: if (edict->tiki && !(edict->s.renderfx & RF_DONTDRAW)) { - G_DebugBBox(origin, mins, maxs, 1, 1, 0, 1); + G_DebugRotatedBBox(origin, angles, mins, maxs, 1, 1, 0, 1); } break; case 4: - G_DebugBBox(origin, mins, maxs, 1, 1, 0, 1); + G_DebugRotatedBBox(origin, angles, mins, maxs, 1, 1, 0, 1); + break; + case 7: + if (edict->tiki && !(edict->s.renderfx & RF_DONTDRAW)) { + Vector vMins, vMaxs; + + gi.TIKI_CalculateBounds(edict->tiki, edict->s.scale, vMins, vMaxs); + if (!VectorCompare(vMins, vec_zero) || !VectorCompare(vMaxs, vec_zero)) { + if (edict->s.parent != ENTITYNUM_NONE && edict->s.tag_num >= 0) { + int i; + Vector vAng; + orientation_t oTag, oBox; + Entity* pParent; + + pParent = G_GetEntity(edict->s.parent); + AnglesToAxis(pParent->angles, pParent->orientation); + oTag = G_TIKI_Orientation(pParent->edict, edict->s.tag_num & TAG_MASK); + + VectorCopy(pParent->origin, oBox.origin); + for (i = 0; i < 3; i++) { + VectorMA(oBox.origin, oTag.origin[i], pParent->orientation[i], oBox.origin); + } + + MatrixMultiply(oTag.axis, pParent->orientation, oBox.axis); + MatrixToEulerAngles(oBox.axis, vAng); + G_DebugRotatedBBox(oBox.origin, vAng, vMins, vMaxs, 0, 1, 1, 1); + } else { + G_DebugRotatedBBox(origin, angles, vMins, vMaxs, 0, 1, 1, 1); + } + } + } + break; + case 8: + if (edict->tiki && !(edict->s.renderfx & RF_DONTDRAW)) { + G_DebugRotatedBBox(origin, angles, mins, maxs, 1, 1, 0, 1); + G_DebugBBox(origin, Vector(-4, -4, -4), Vector(4, 4, 4), 0, 1, 1, 1); + } break; - case 5: default: if (IsSubclassOfAnimate() && edict->tiki) { Animate *anim; @@ -5963,6 +5998,8 @@ void Entity::DrawBoundingBox(int showbboxes) } break; } + + // FIXME: not implemented (implement the rest...) } qboolean Entity::IsDead(void) const From 1ed85387451ff697940ee5b741d81abee36307b3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:23:31 +0100 Subject: [PATCH 0252/2040] Bounds check clarity --- code/qcommon/cm_terrain.c | 40 ++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 042b0ac9..8fb8220d 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -1149,10 +1149,16 @@ void CM_TraceThroughTerrainCollide(traceWork_t *tw, terrainCollide_t *tc) { int i; - if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[0][1] >= tc->vBounds[1][1] - || tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][0] <= tc->vBounds[0][0] - || tw->bounds[1][1] <= tc->vBounds[0][1] || tw->bounds[1][2] <= tc->vBounds[0][2]) { - return; + if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[1][0] <= tc->vBounds[0][0]) { + return qfalse; + } + + if (tw->bounds[0][1] >= tc->vBounds[1][1] || tw->bounds[1][1] <= tc->vBounds[0][1]) { + return qfalse; + } + + if (tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][2] <= tc->vBounds[0][2]) { + return qfalse; } g_trace.tw = tw; @@ -1202,9 +1208,15 @@ qboolean CM_PositionTestInTerrainCollide(traceWork_t *tw, terrainCollide_t *tc) { int i; - if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[0][1] >= tc->vBounds[1][1] - || tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][0] <= tc->vBounds[0][0] - || tw->bounds[1][1] <= tc->vBounds[0][1] || tw->bounds[1][2] <= tc->vBounds[0][2]) { + if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[1][0] <= tc->vBounds[0][0]) { + return qfalse; + } + + if (tw->bounds[0][1] >= tc->vBounds[1][1] || tw->bounds[1][1] <= tc->vBounds[0][1]) { + return qfalse; + } + + if (tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][2] <= tc->vBounds[0][2]) { return qfalse; } @@ -1414,10 +1426,16 @@ qboolean CM_SightTraceThroughTerrainCollide(traceWork_t *tw, terrainCollide_t *t { int i; - if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[0][1] >= tc->vBounds[1][1] - || tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][0] <= tc->vBounds[0][0] - || tw->bounds[1][1] <= tc->vBounds[0][1] || tw->bounds[1][2] <= tc->vBounds[0][2]) { - return qtrue; + if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[1][0] <= tc->vBounds[0][0]) { + return qfalse; + } + + if (tw->bounds[0][1] >= tc->vBounds[1][1] || tw->bounds[1][1] <= tc->vBounds[0][1]) { + return qfalse; + } + + if (tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][2] <= tc->vBounds[0][2]) { + return qfalse; } g_trace.tw = tw; From ea14ab56643ae2a439ca97974bd465ffcc7c0872 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Feb 2024 23:25:39 +0100 Subject: [PATCH 0253/2040] Implemented special func --- code/fgame/scriptslave.cpp | 60 +++++++++++++++++++++++++++----------- code/fgame/scriptslave.h | 6 +++- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 0ce2ec93..4633b8a9 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "game.h" #include "debuglines.h" #include "weaputils.h" +#include "parm.h" /*****************************************************************************/ /*QUAKED script_object (0 0.5 1) ? NOT_SOLID @@ -654,6 +655,10 @@ CLASS_DECLARATION(Mover, ScriptSlave, "script_object") { {&EV_ScriptSlave_FollowPath_RelativeYaw, &ScriptSlave::FollowPathRelativeYaw}, {&EV_ScriptSlave_EndPath, &ScriptSlave::EndPath }, {&EV_ScriptSlave_FollowingPath, &ScriptSlave::FollowingPath }, + {&EV_Touch, &ScriptSlave::TouchFunc }, + {&EV_Blocked, &ScriptSlave::BlockFunc }, + {&EV_Activate, &ScriptSlave::TriggerFunc }, + {&EV_Use, &ScriptSlave::UseFunc }, {&EV_ScriptSlave_MoveDone, &ScriptSlave::MoveEnd }, {&EV_Damage, &ScriptSlave::DamageFunc }, {&EV_ScriptSlave_RotateDownTo, &ScriptSlave::Rotatedownto }, @@ -784,7 +789,6 @@ void ScriptSlave::NewMove(void) } void ScriptSlave::BindEvent(Event *ev) - { Entity *ent; @@ -799,7 +803,6 @@ void ScriptSlave::BindEvent(Event *ev) } void ScriptSlave::EventUnbind(Event *ev) - { unbind(); @@ -825,7 +828,6 @@ void ScriptSlave::MoveEnd(Event *ev) } void ScriptSlave::SetAnglesEvent(Event *ev) - { commandswaiting = true; SetAngles(ev); @@ -833,7 +835,6 @@ void ScriptSlave::SetAnglesEvent(Event *ev) } void ScriptSlave::SetAngleEvent(Event *ev) - { float angle; @@ -885,7 +886,6 @@ void ScriptSlave::SetModelEvent(Event *ev) } void ScriptSlave::TriggerEvent(Event *ev) - { Entity *ent; Event *e; @@ -903,7 +903,6 @@ void ScriptSlave::TriggerEvent(Event *ev) } void ScriptSlave::GotoNextWaypoint(Event *ev) - { commandswaiting = true; @@ -961,7 +960,6 @@ void ScriptSlave::JumpTo(Event *ev) } void ScriptSlave::MoveToEvent(Event *ev) - { commandswaiting = true; @@ -979,14 +977,12 @@ void ScriptSlave::MoveToEvent(Event *ev) } void ScriptSlave::SetSpeed(Event *ev) - { speed = ev->GetFloat(1); traveltime = 0; } void ScriptSlave::SetTime(Event *ev) - { traveltime = ev->GetFloat(1); } @@ -1281,25 +1277,21 @@ void ScriptSlave::RotateAxisup(Event *ev) } void ScriptSlave::RotateX(Event *ev) - { avelocity[0] = ev->GetFloat(1); } void ScriptSlave::RotateY(Event *ev) - { avelocity[1] = ev->GetFloat(1); } void ScriptSlave::RotateZ(Event *ev) - { avelocity[2] = ev->GetFloat(1); } void ScriptSlave::RotateAxis(Event *ev) - { int axis; @@ -1307,25 +1299,60 @@ void ScriptSlave::RotateAxis(Event *ev) avelocity[axis] = ev->GetFloat(2); } +void ScriptSlave::TouchFunc(Event* ev) +{ + parm.other = ev->GetEntity(1); + parm.owner = parm.other; + Unregister(STRING_TOUCH); +} + +void ScriptSlave::BlockFunc(Event* ev) +{ + Entity* other; + + other = ev->GetEntity(1); + if (level.time >= attack_finished) { + attack_finished = level.time + 0.5; + if (dmg) { + other->Damage(this, this, dmg, origin, vec_zero, vec_zero, 0, 0, dmg_means_of_death); + } + } + + parm.other = ev->GetEntity(1); + parm.owner = parm.other; + Unregister(STRING_BLOCK); +} + +void ScriptSlave::TriggerFunc(Event* ev) +{ + parm.other = ev->GetEntity(1); + parm.owner = parm.other; + Unregister(STRING_TRIGGER); +} + +void ScriptSlave::UseFunc(Event* ev) +{ + parm.other = ev->GetEntity(1); + parm.owner = parm.other; + Unregister(STRING_USE); +} + void ScriptSlave::DamageFunc(Event *ev) { Unregister(STRING_DAMAGE); } void ScriptSlave::SetDamage(Event *ev) - { dmg = ev->GetInteger(1); } void ScriptSlave::SetMeansOfDeath(Event *ev) - { dmg_means_of_death = MOD_string_to_int(ev->GetString(1)); } void ScriptSlave::CreatePath(SplinePath *path, splinetype_t type) - { SplinePath *node; @@ -1641,7 +1668,6 @@ void ScriptSlave::FollowingPath(Event *ev) } void ScriptSlave::Explode(Event *ev) - { float damage; diff --git a/code/fgame/scriptslave.h b/code/fgame/scriptslave.h index c37a133e..277ddfba 100644 --- a/code/fgame/scriptslave.h +++ b/code/fgame/scriptslave.h @@ -136,6 +136,11 @@ protected: void RotateY(Event *ev); void RotateZ(Event *ev); void RotateAxis(Event *ev); + void TouchFunc(Event *ev); + void BlockFunc(Event *ev); + void TriggerFunc(Event *ev); + void UseFunc(Event *ev); + void DamageFunc(Event *ev); void SetDamage(Event *ev); void SetMeansOfDeath(Event *ev); void FollowPath(Event *ev); @@ -150,7 +155,6 @@ protected: void PhysicsOn(Event *ev); void PhysicsOff(Event *ev); void PhysicsVelocity(Event *ev); - void DamageFunc(Event *ev); void EventFlyPath(Event *ev); void EventModifyFlyPath(Event *ev); void EventNormalAngles(Event *ev); // Added in 2.0 From 36af9e65891a10afdbe1757260dcb51d33035263 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 27 Feb 2024 00:02:20 +0100 Subject: [PATCH 0254/2040] Fixed a very boring mistake ignored by MSVC --- code/qcommon/cm_terrain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 8fb8220d..82dee2ed 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -1150,15 +1150,15 @@ void CM_TraceThroughTerrainCollide(traceWork_t *tw, terrainCollide_t *tc) int i; if (tw->bounds[0][0] >= tc->vBounds[1][0] || tw->bounds[1][0] <= tc->vBounds[0][0]) { - return qfalse; + return; } if (tw->bounds[0][1] >= tc->vBounds[1][1] || tw->bounds[1][1] <= tc->vBounds[0][1]) { - return qfalse; + return; } if (tw->bounds[0][2] >= tc->vBounds[1][2] || tw->bounds[1][2] <= tc->vBounds[0][2]) { - return qfalse; + return; } g_trace.tw = tw; From 35a8c4edfa3b60ed5b5aee42b7a889a5c9b8aeb6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:10:07 +0100 Subject: [PATCH 0255/2040] g_droppeditemlife: make sure the value is non-null --- code/fgame/weapon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index cc26ed6e..b754155c 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -2394,7 +2394,10 @@ qboolean Weapon::Drop(void) // Remove this from the owner's item list RemoveFromOwner(); - PostEvent(EV_Remove, g_droppeditemlife->value); + if (g_droppeditemlife->value > 0) { + PostEvent(EV_Remove, g_droppeditemlife->value); + } + PostEvent(EV_Weapon_FallingAngleAdjust, level.frametime); return true; } From 07c840a4a9beeb839e8d1e2d5d4eb527e6b00da7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:10:18 +0100 Subject: [PATCH 0256/2040] Don't assert for NULL owner --- code/fgame/weapon.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index b754155c..5a06f008 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -2777,10 +2777,7 @@ void Weapon::GiveStartingAmmoToOwner(Event *ev) int mode; int i; - assert(owner); - if (!owner) { - warning("Weapon::GiveStartingAmmoToOwner", "Owner not found\n"); return; } From 77ef0f35792ef6cac8d4460c4fde0e212ced6893 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:21:53 +0100 Subject: [PATCH 0257/2040] Implemented game.detail and game.skill --- code/fgame/game.cpp | 60 ++++++++++++++++++++++++++++++++++++++++----- code/fgame/game.h | 10 ++++++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/code/fgame/game.cpp b/code/fgame/game.cpp index 00030a35..c485a718 100644 --- a/code/fgame/game.cpp +++ b/code/fgame/game.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2023 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -31,18 +31,66 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "player.h" #include "dm_manager.h" +Event EV_Game_Detail +( + "skill", + EV_DEFAULT, + NULL, + NULL, + "game.skill" +); + +Event EV_Game_Skill +( + "detail", + EV_DEFAULT, + NULL, + NULL, + "game.detail" +); + Game game; +void Game::GetSkill(Event *ev) +{ + switch (skill->integer) { + case 0: + case 1: + ev->AddString("easy"); + break; + case 2: + ev->AddString("hard"); + break; + default: + ev->AddString("unknown"); + break; + } +} + +void Game::GetDetail(Event *ev) +{ + ev->AddFloat(detail->value); +} + +void Game::Init() +{ + clients = NULL; + autosaved = qfalse; + maxentities = 0; + maxclients = 0; +} + +void Game::Archive(Archiver& arc) {} + Game::Game() { - clients = NULL; - maxclients = 0; + Init(); } Game::~Game() {} -void Game::Archive(Archiver& arc) {} - CLASS_DECLARATION(Listener, Game, NULL) { - {NULL, NULL} + {&EV_Game_Skill, &Game::GetSkill }, + {&EV_Game_Detail, &Game::GetDetail}, + {NULL, NULL } }; diff --git a/code/fgame/game.h b/code/fgame/game.h index b97c59d0..61f7821a 100644 --- a/code/fgame/game.h +++ b/code/fgame/game.h @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2023 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -39,10 +39,16 @@ public: public: CLASS_PROTOTYPE(Game); - void Archive(Archiver& arc) override; +protected: + void GetSkill(Event *ev); + void GetDetail(Event *ev); +public: Game(); ~Game(); + + void Init(); + void Archive(Archiver& arc) override; }; class SimpleArchivedEntity; From 960469be77994cbeff9ccb3d7367f3518f7c5552 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:52:25 +0100 Subject: [PATCH 0258/2040] Implemented MakePrimitive() --- code/script/scriptvariable.cpp | 22 ++++++++++++++++++++++ code/script/scriptvariable.h | 17 +++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/code/script/scriptvariable.cpp b/code/script/scriptvariable.cpp index f079cae7..ef74bee0 100644 --- a/code/script/scriptvariable.cpp +++ b/code/script/scriptvariable.cpp @@ -281,6 +281,19 @@ void ScriptVariable::ArchiveInternal(Archiver& arc) break; } } + +void ScriptVariable::MakePrimitive() +{ + switch (type) { + case VARIABLE_LISTENER: + case VARIABLE_REF: + case VARIABLE_CONTAINER: + case VARIABLE_SAFECONTAINER: + Com_Error(ERR_DROP, "^~^~^ game.%s cannot be archived since it is of type '%s'.", getName().c_str(), GetTypeName()); + Clear(); + break; + } +} #endif ScriptArrayHolder::ScriptArrayHolder() @@ -2568,6 +2581,15 @@ void ScriptVariableList::Archive(Archiver& arc) list.Archive(arc); } +void ScriptVariableList::MakePrimitive() +{ + con_set_enum en = list; + + for (con_set_enum::Entry *entry = en.NextElement(); entry; entry = en.NextElement()) { + entry->value.MakePrimitive(); + } +} + CLASS_DECLARATION(Class, ScriptVariableList, NULL) { {NULL, NULL} }; diff --git a/code/script/scriptvariable.h b/code/script/scriptvariable.h index 92d349c7..49056942 100644 --- a/code/script/scriptvariable.h +++ b/code/script/scriptvariable.h @@ -111,10 +111,6 @@ public: ~ScriptVariable(); - void Archive(Archiver& arc); - static void Archive(Archiver& arc, ScriptVariable **obj); - void ArchiveInternal(Archiver& arc); - void CastBoolean(void); void CastConstArrayValue(void); void CastEntity(void); @@ -235,6 +231,12 @@ public: ScriptVariable operator++(int); ScriptVariable operator--(int); + + void Archive(Archiver& arc); + static void Archive(Archiver& arc, ScriptVariable** obj); + void ArchiveInternal(Archiver& arc); + + void MakePrimitive(); }; class ScriptArrayHolder : public LightClass @@ -293,6 +295,8 @@ class con_set_Entry private: con_set_Entry *next; + +public: ScriptVariable value; public: @@ -318,8 +322,6 @@ public: ScriptVariableList(); - void Archive(Archiver& arc) override; - void ClearList(void); ScriptVariable *GetOrCreateVariable(str name); @@ -338,6 +340,9 @@ public: ScriptVariable *SetVariable(const char *name, ScriptVariable& value); ScriptVariable *SetVariable(unsigned int name, ScriptVariable& value); ScriptVariable *SetVariable(unsigned int name, ScriptVariable&& value); + + void Archive(Archiver& arc) override; + void MakePrimitive(); }; #endif From 8b9840d37f9a9895f0fedcc1a390928e61ad1aa3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:52:44 +0100 Subject: [PATCH 0259/2040] Implemented Game::Archive() --- code/fgame/game.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/code/fgame/game.cpp b/code/fgame/game.cpp index c485a718..b92d63ae 100644 --- a/code/fgame/game.cpp +++ b/code/fgame/game.cpp @@ -80,7 +80,48 @@ void Game::Init() maxclients = 0; } -void Game::Archive(Archiver& arc) {} +void Game::Archive(Archiver& arc) +{ + static cvar_t *g_maxplayerhealth = gi.Cvar_Get("g_maxplayerhealth", "250", 0); + int i; + + if (arc.Saving()) { + Vars()->MakePrimitive(); + } + + Listener::Archive(arc); + + if (arc.Saving()) { + float fTmp; + int iTmp; + + fTmp = skill->value; + arc.ArchiveFloat(&fTmp); + + iTmp = g_maxplayerhealth->integer; + arc.ArchiveInteger(&iTmp); + } else { + float fTmp; + int iTmp; + + arc.ArchiveFloat(&fTmp); + gi.cvar_set("skill", va("%f", fTmp)); + arc.ArchiveInteger(&iTmp); + gi.cvar_set("g_maxplayerhealth", va("%d", iTmp)); + } + + arc.ArchiveBoolean(&autosaved); + arc.ArchiveInteger(&maxentities); + arc.ArchiveInteger(&maxclients); + + if (arc.Loading()) { + G_AllocGameData(); + } + + for (i = 0; i < maxclients; i++) { + arc.ArchiveRaw(&clients[i], sizeof(gclient_t)); + } +} Game::Game() { From 06d8ddbfc75ce1d0ac339b6df5a0ba221694022d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 22:56:05 +0100 Subject: [PATCH 0260/2040] Fixed AI firing multiple bullets when it should fire one This fixes AI killing the player almost instantly --- code/fgame/sentient_combat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/sentient_combat.cpp b/code/fgame/sentient_combat.cpp index 6ebe3279..4aef186e 100644 --- a/code/fgame/sentient_combat.cpp +++ b/code/fgame/sentient_combat.cpp @@ -446,7 +446,7 @@ void Sentient::FireWeapon(int number, firemode_t mode) { Weapon *activeWeapon = activeWeaponList[number]; - if (activeWeapon) { + if (activeWeapon && activeWeapon->ReadyToFire(mode)) { if (mode == FIRE_SECONDARY && activeWeapon->GetZoom() && !activeWeapon->GetAutoZoom() && IsSubclassOfPlayer()) { Player *p = (Player *)this; p->ToggleZoom(activeWeapon->GetZoom()); From 76c9e4e0484280b04b02cf845229bfc05259d5b5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 23:33:10 +0100 Subject: [PATCH 0261/2040] Fixed pickup message appearing twice --- code/fgame/weapon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index 5a06f008..805fbd40 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -2980,7 +2980,7 @@ void Weapon::PickupWeapon(Event *ev) gi.SendServerCommand(other->edict - g_entities, "print \"" HUD_MESSAGE_YELLOW "%s\n\"", sMessage.c_str()); } - if (ammo_type[FIRE_SECONDARY] != ammo_type[FIRE_PRIMARY]) { + if (ammo_type[FIRE_SECONDARY] != ammo_type[FIRE_PRIMARY] && str::icmp(ammo_type[FIRE_SECONDARY], "none")) { if (startammo[FIRE_SECONDARY] && ammo_type[FIRE_SECONDARY].length() && other->isClient()) { str sMessage; const str& sAmmoType = ammo_type[FIRE_PRIMARY]; From e06ee0f26ace669f9578d001a6981ab576a68b16 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Feb 2024 23:40:41 +0100 Subject: [PATCH 0262/2040] Bounce backwards check --- code/fgame/vehicle.cpp | 72 +++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index ea8aa564..fb6c53b1 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -3134,19 +3134,26 @@ void Vehicle::AutoPilot(void) fCoef = ProjectLineOnPlane(vDelta, DotProduct(origin, vDelta), vPrev, vCur, NULL); if (g_showvehiclemovedebug->integer) { - Vector vColor; - G_DebugBBox(vColor, Vector(-32, -32, -32), Vector(32, 32, 32), 0, 1, 1, 1); - G_DebugBBox(vColor, Vector(-32, -32, -32), Vector(32, 32, 32), 1, 1, 0, 1); - G_DebugArrow(vColor, m_vIdealDir * -1, (1 - fCoef) * fTotal, 0, 1, 0, 1); - G_DebugArrow(vColor, m_vIdealDir * 1, fCoef * fTotal, 0, 0, 1, 1); + G_DebugBBox(vPrev, Vector(-32, -32, -32), Vector(32, 32, 32), 0, 1, 1, 1); + G_DebugBBox(vCur, Vector(-32, -32, -32), Vector(32, 32, 32), 1, 1, 0, 1); + G_DebugArrow(vCur, m_vIdealDir * -1, (1 - fCoef) * fTotal, 0, 1, 0, 1); + G_DebugArrow(vPrev, m_vIdealDir * 1, fCoef * fTotal, 0, 0, 1, 1); } vTmp = m_pCurPath->GetByNode(m_iCurNode - (1.0 - fCoef), NULL); fCurPathPosition = vTmp[0]; - vTmp = m_pCurPath->Get(fCurPathPosition + m_fLookAhead, NULL); - vWishPosition = vTmp + 1; - fDistToCurPos = Vector(origin[0] - vWishPosition[0], origin[1] - vWishPosition[1], 0).length(); + // Added in 2.30 + // Check if vehicle bounces backwards + if (m_bBounceBackwards) { + vTmp = m_pCurPath->Get(fCurPathPosition - m_fLookAhead, NULL); + } else { + vTmp = m_pCurPath->Get(fCurPathPosition + m_fLookAhead, NULL); + } + vWishPosition = vTmp + 1; + fDistToCurPos = Vector(origin[0] - vWishPosition[0], origin[1] - vWishPosition[1], 0).length(); + // Added in 2.30 + // Check if vehicle bounces backwards if (fCoef > 1 && !m_bBounceBackwards) { m_iCurNode++; if (m_iCurNode >= m_pCurPath->m_iPoints) { @@ -3254,7 +3261,8 @@ void Vehicle::AutoPilot(void) vDeltaSave[2] = 0; if (fDistToCurPos > 1) { - if (moveimpulse >= 0 && !m_bBounceBackwards) { // 2.30: checks if it doesn't bounce backwards + // Added 2.30: checks if it doesn't bounce backwards + if (moveimpulse >= 0 && !m_bBounceBackwards) { vectoangles(vDelta, vDeltaAngles); turnimpulse = angledist(vDeltaAngles.y - angles.y); } else { @@ -3307,13 +3315,19 @@ void Vehicle::AutoPilot(void) if (m_iNextPathStartNode >= 0 && m_pNextPath && m_pNextPath->m_iPoints && m_iCurNode > m_iNextPathStartNode + 2) { - cVehicleSpline *spline = m_pCurPath; - m_pCurPath = m_pNextPath; - m_pNextPath = spline; - m_iCurNode = 2; + cVehicleSpline *spline; + + spline = m_pCurPath; + m_pCurPath = m_pNextPath; + m_pNextPath = spline; + + m_iCurNode = 2; m_pNextPath->Reset(); m_iNextPathStartNode = -1; + + // notify scripts that the drive has finished Unregister(STRING_DRIVE); + m_bStopEnabled = false; m_bEnableSkidding = false; } @@ -3389,7 +3403,7 @@ void Vehicle::EventDriveInternal(Event *ev, bool wait) m_fIdealAccel = ev->GetFloat(3); case 2: m_fIdealSpeed = ev->GetFloat(2); - m_fMaxSpeed = m_fIdealSpeed;// Added in 2.30 + m_fMaxSpeed = m_fIdealSpeed; // Added in 2.30 case 1: path = ev->GetSimpleEntity(1); if (!path) { @@ -4091,11 +4105,12 @@ void Vehicle::SlidePush(Vector vPush) other->entity->CheckGround(); if (other->entity->groundentity) { - if (other->entity->groundentity == edict || m_pCollisionEntity && other->entity->groundentity->entity == m_pCollisionEntity) { + if (other->entity->groundentity == edict + || m_pCollisionEntity && other->entity->groundentity->entity == m_pCollisionEntity) { // save the entity - pSkippedEntities[iNumSkipped] = other->entity; + pSkippedEntities[iNumSkipped] = other->entity; iContentsEntities[iNumSkipped] = other->r.contents; - solidEntities[iNumSkipped] = other->solid; + solidEntities[iNumSkipped] = other->solid; iNumSkipped++; if (iNumSkipped >= MAX_SKIPPED_ENTITIES) { @@ -5849,15 +5864,20 @@ void Vehicle::UpdateNormals(void) } if (m_iNumNormals > 1) { + float x, z; + temp = m_vNormalSum / m_iNumNormals; i = temp.CrossProduct(temp, j); - pitch = i; - angles[0] = pitch.toPitch(); + pitch = i; + x = pitch.toPitch(); - temp = m_vNormalSum / m_iNumNormals; - pitch = temp.CrossProduct(temp, i); - angles[2] = pitch.toPitch(); + temp = m_vNormalSum / m_iNumNormals; + pitch = temp.CrossProduct(temp, i); + z = pitch.toPitch(); + + angles[0] = x; + angles[2] = z; } } @@ -6475,9 +6495,9 @@ void Vehicle::Archive(Archiver& arc) arc.ArchiveBoolean(&jumpable); arc.ArchiveBoolean(&m_bMovementLocked); - arc.ArchiveBoolean(&m_bAnimMove); // Added in 2.0 - arc.ArchiveBoolean(&m_bDamageSounds); // Added in 2.0 - arc.ArchiveBoolean(&m_bRunSounds); // Added in 2.0 + arc.ArchiveBoolean(&m_bAnimMove); // Added in 2.0 + arc.ArchiveBoolean(&m_bDamageSounds); // Added in 2.0 + arc.ArchiveBoolean(&m_bRunSounds); // Added in 2.0 arc.ArchiveInteger(&m_iProjectileHitsRemaining); // Added in 2.30 driver.Archive(arc); @@ -6716,7 +6736,7 @@ void Vehicle::Archive(Archiver& arc) m_sMoveGrid->Archive(arc); arc.ArchiveFloat(&m_fIdealSpeed); - arc.ArchiveFloat(&m_fMaxSpeed); // Added in 2.30 + arc.ArchiveFloat(&m_fMaxSpeed); // Added in 2.30 arc.ArchiveBool(&m_bBounceBackwards); // Added in 2.30 arc.ArchiveVector(&m_vIdealPosition); arc.ArchiveVector(&m_vIdealDir); From e7cd70b8ee7ea8bc1e688c32a7ad3252ef581620 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 1 Mar 2024 22:19:18 +0100 Subject: [PATCH 0263/2040] Enable cg_rain by default --- code/cgame/cg_nature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/cgame/cg_nature.cpp b/code/cgame/cg_nature.cpp index 304f0906..c532144e 100644 --- a/code/cgame/cg_nature.cpp +++ b/code/cgame/cg_nature.cpp @@ -58,7 +58,7 @@ void ClientGameCommandManager::InitializeRainCvars() { int i; - cg_rain = cgi.Cvar_Get("cg_rain", "0", CVAR_ARCHIVE); + cg_rain = cgi.Cvar_Get("cg_rain", "1", CVAR_ARCHIVE); cg_rain_drawcoverage = cgi.Cvar_Get("cg_rain_drawcoverage", "0", CVAR_SAVEGAME | CVAR_SERVER_CREATED | CVAR_SYSTEMINFO); From 52c89f1de3e8d708875a93e618335df63890620a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 1 Mar 2024 22:31:33 +0100 Subject: [PATCH 0264/2040] Fixed comparison operator --- code/renderer/tr_light.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_light.c b/code/renderer/tr_light.c index 5e7018b3..59c3bd62 100644 --- a/code/renderer/tr_light.c +++ b/code/renderer/tr_light.c @@ -932,7 +932,7 @@ static int RB_GetEntityGridLighting() } // normalize - if (vLight[0] < 255.0 || vLight[1] < 255.0 || vLight[2] < 255.0) { + if (vLight[0] > 255.0 || vLight[1] > 255.0 || vLight[2] > 255.0) { float scale = 255.0 / fmin(vLight[0], fmin(vLight[1], vLight[2])); VectorScale(vLight, scale, vLight); } From b77af7fced0714182656310a6b4abd7dec527b24 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 1 Mar 2024 22:59:06 +0100 Subject: [PATCH 0265/2040] Implemented R_GetLightingForDecal --- code/renderer/tr_light.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_light.c b/code/renderer/tr_light.c index 59c3bd62..6c8c914d 100644 --- a/code/renderer/tr_light.c +++ b/code/renderer/tr_light.c @@ -884,8 +884,20 @@ void R_GetLightingGridValueFast(const vec3_t vPos, vec3_t vLight) void R_GetLightingForDecal(vec3_t vLight, const vec3_t vFacing, const vec3_t vOrigin) { - // FIXME: unimplemented - VectorSet(vLight, 1.f, 1.f, 1.f); + float fMax; + + R_GetLightingGridValue(vOrigin, vLight); + + if (!tr.overbrightShift) { + return; + } + + VectorScale(vLight, tr.overbrightMult, vLight); + + if (vLight[0] > 255.0 || vLight[1] > 255.0 || vLight[2] > 255.0) { + float scale = 255.0 / fmin(vLight[0], fmin(vLight[1], vLight[2])); + VectorScale(vLight, scale, vLight); + } } void R_GetLightingForSmoke(vec3_t vLight, const vec3_t vOrigin) From a7b3fdd70b50f33ed3f04ffdcd669435d36372e4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 2 Mar 2024 14:06:32 +0100 Subject: [PATCH 0266/2040] Added getConfigStringIdNormalized client game import to normalize config strings --- code/cgame/cg_public.h | 2 ++ code/cgame/cg_servercmds.c | 2 +- code/client/cl_cgame.cpp | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index 1b895795..58d515d4 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -430,6 +430,8 @@ functions exported to the main executable void (*CL_RestoreSavedCgameState)(); void (*CL_ClearSavedCgameState)(); + size_t (*getConfigStringIdNormalized)(size_t num); + cvar_t *fsDebug; hdelement_t *HudDrawElements; clientAnim_t *anim; diff --git a/code/cgame/cg_servercmds.c b/code/cgame/cg_servercmds.c index 25c0e356..9f4ea4be 100644 --- a/code/cgame/cg_servercmds.c +++ b/code/cgame/cg_servercmds.c @@ -296,7 +296,7 @@ static void CG_ServerCommand(qboolean modelOnly) } if (!strcmp(cmd, "cs")) { - CG_ConfigStringModified(atoi(cgi.Argv(1)), modelOnly); + CG_ConfigStringModified(cgi.getConfigStringIdNormalized(atoi(cgi.Argv(1))), modelOnly); return; } diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index 238fed26..4733b336 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -815,6 +815,8 @@ void CL_InitCGameDLL( clientGameImport_t *cgi, clientGameExport_t **cge ) { cgi->CL_RestoreSavedCgameState = CL_RestoreSavedCgameState; cgi->CL_ClearSavedCgameState = CL_ClearSavedCgameState; + cgi->getConfigStringIdNormalized = CPT_NormalizeConfigstring; + cgi->fsDebug = fs_debug; cgi->HudDrawElements = cls.HudDrawElements; cgi->anim = &cls.anim; From 40035f4df303e28595cd23465e2aa86098b4d99c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 2 Mar 2024 14:23:32 +0100 Subject: [PATCH 0267/2040] Fixed multi-shaders snow --- code/cgame/cg_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index ab3c46ee..4a59a432 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -336,6 +336,14 @@ void CG_ProcessConfigString(int num, qboolean modelOnly) return; case CS_RAIN_SHADER: Q_strncpyz(cg.rain.currentShader, str, sizeof(cg.rain.currentShader)); + if (cg.rain.numshaders) { + // Fixed in OPM + // not sure why some maps set a digit at the end... + int len = strlen(cg.rain.currentShader); + if (isdigit(cg.rain.currentShader[len - 1])) { + cg.rain.currentShader[len - 1] = 0; + } + } for (i = 0; i < cg.rain.numshaders; ++i) { Com_sprintf(cg.rain.shader[i], sizeof(cg.rain.shader[i]), "%s%i", cg.rain.currentShader, i); } From 9bd4d40f09b74110bc0c54e3ac1ceed539f8af38 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 2 Mar 2024 15:00:56 +0100 Subject: [PATCH 0268/2040] Formatted document --- code/qcommon/cm_fencemask.c | 926 ++++++++++++++++++------------------ 1 file changed, 457 insertions(+), 469 deletions(-) diff --git a/code/qcommon/cm_fencemask.c b/code/qcommon/cm_fencemask.c index 70747b69..098081fb 100644 --- a/code/qcommon/cm_fencemask.c +++ b/code/qcommon/cm_fencemask.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "cm_local.h" #include "../client/client.h" -byte cmf_dummy_trans_data; +byte cmf_dummy_trans_data; cfencemask_t cmf_dummy_trans; /* @@ -31,40 +31,40 @@ cfencemask_t cmf_dummy_trans; CM_LoadFTX ==================== */ -qboolean CM_LoadFTX( const char *name, byte **pic, int *width, int *height ) +qboolean CM_LoadFTX(const char *name, byte **pic, int *width, int *height) { - int length; - int numPixels; - fileHandle_t h; - ftx_t header; + int length; + int numPixels; + fileHandle_t h; + ftx_t header; - *pic = NULL; - length = FS_FOpenFileRead( name, &h, qtrue, qtrue ); - if( length <= 0 ) { - return qtrue; - } + *pic = NULL; + length = FS_FOpenFileRead(name, &h, qtrue, qtrue); + if (length <= 0) { + return qtrue; + } - FS_Read( &header, sizeof( ftx_t ), h ); + FS_Read(&header, sizeof(ftx_t), h); - header.has_alpha = LittleLong(header.has_alpha); - header.height = LittleLong(header.height); - header.width = LittleLong(header.width); + header.has_alpha = LittleLong(header.has_alpha); + header.height = LittleLong(header.height); + header.width = LittleLong(header.width); - if( !header.has_alpha ) { - FS_FCloseFile( h ); - return qfalse; - } + if (!header.has_alpha) { + FS_FCloseFile(h); + return qfalse; + } - // Load the FTX data - numPixels = header.width * header.height; - *height = header.height; - *width = header.width; - *pic = Hunk_AllocateTempMemory( numPixels * 4 ); + // Load the FTX data + numPixels = header.width * header.height; + *height = header.height; + *width = header.width; + *pic = Hunk_AllocateTempMemory(numPixels * 4); - FS_Read( *pic, numPixels * 4, h ); - FS_FCloseFile( h ); + FS_Read(*pic, numPixels * 4, h); + FS_FCloseFile(h); - return qtrue; + return qtrue; } /* @@ -72,190 +72,193 @@ qboolean CM_LoadFTX( const char *name, byte **pic, int *width, int *height ) CM_LoadTGA ==================== */ -qboolean CM_LoadTGA( const char *name, byte **pic, int *width, int *height ) +qboolean CM_LoadTGA(const char *name, byte **pic, int *width, int *height) { - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *buffer; - int length; - TargaHeader targa_header; - byte *targa_rgba; + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; + TargaHeader targa_header; + byte *targa_rgba; - *pic = NULL; + *pic = NULL; - // - // load the file - // - length = FS_ReadFile (name, (void **)&buffer); - if (!buffer) { - return qfalse; - } + // + // load the file + // + length = FS_ReadFile(name, (void **)&buffer); + if (!buffer) { + return qfalse; + } - buf_p = buffer; + buf_p = buffer; - targa_header.id_length = *buf_p++; - targa_header.colormap_type = *buf_p++; - targa_header.image_type = *buf_p++; - - targa_header.colormap_index = LittleShort ( *((short *)buf_p) ); - buf_p+=2; - targa_header.colormap_length = LittleShort ( *((short *)buf_p) ); - buf_p+=2; - targa_header.colormap_size = *buf_p++; - targa_header.x_origin = LittleShort ( *((short *)buf_p) ); - buf_p+=2; - targa_header.y_origin = LittleShort ( *((short *)buf_p) ); - buf_p+=2; - targa_header.width = LittleShort ( *((short *)buf_p) ); - buf_p+=2; - targa_header.height = LittleShort ( *((short *)buf_p) ); - buf_p+=2; - targa_header.pixel_size = *buf_p++; - targa_header.attributes = *buf_p++; + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; - if (targa_header.image_type!=2 - && targa_header.image_type!=10 - && targa_header.image_type!=3) - Com_Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + targa_header.colormap_index = LittleShort(*((short *)buf_p)); + buf_p += 2; + targa_header.colormap_length = LittleShort(*((short *)buf_p)); + buf_p += 2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort(*((short *)buf_p)); + buf_p += 2; + targa_header.y_origin = LittleShort(*((short *)buf_p)); + buf_p += 2; + targa_header.width = LittleShort(*((short *)buf_p)); + buf_p += 2; + targa_header.height = LittleShort(*((short *)buf_p)); + buf_p += 2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; - if(targa_header.colormap_type!=0) - Com_Error (ERR_DROP, "LoadTGA: colormaps not supported\n"); + if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3) { + Com_Error(ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + } - if (targa_header.pixel_size != 32) { + if (targa_header.colormap_type != 0) { + Com_Error(ERR_DROP, "LoadTGA: colormaps not supported\n"); + } + + if (targa_header.pixel_size != 32) { if (targa_header.pixel_size != 24 && targa_header.image_type != 3) { Com_Error(ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - } + } - FS_FreeFile(buffer); - return qfalse; - } - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; + FS_FreeFile(buffer); + return qfalse; + } + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; - if (width) - *width = columns; - if (height) - *height = rows; + if (width) { + *width = columns; + } + if (height) { + *height = rows; + } - targa_rgba = Hunk_AllocateTempMemory (numPixels*4); - *pic = targa_rgba; + targa_rgba = Hunk_AllocateTempMemory(numPixels * 4); + *pic = targa_rgba; - if (targa_header.id_length != 0) - buf_p += targa_header.id_length; // skip TARGA image comment - - if(targa_header.image_type == 2 || targa_header.image_type == 3) { // Uncompressed, RGB images - for(row=rows-1; row>=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - else { // non run-length packet - for(j=0;j0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - } - breakOut:; - } - } + if (targa_header.id_length != 0) { + buf_p += targa_header.id_length; // skip TARGA image comment + } - FS_FreeFile (buffer); - return qtrue; + if (targa_header.image_type == 2 || targa_header.image_type == 3) { // Uncompressed, RGB images + for (row = rows - 1; row >= 0; row--) { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns; column++) { + unsigned char red, green, blue, alphabyte; + switch (targa_header.pixel_size) { + case 24: + + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + } + } + } else if (targa_header.image_type == 10) { // Runlength encoded RGB images + unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j; + for (row = rows - 1; row >= 0; row--) { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns;) { + packetHeader = *buf_p++; + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + break; + } + + for (j = 0; j < packetSize; j++) { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + column++; + if (column == columns) { // run spans across rows + column = 0; + if (row > 0) { + row--; + } else { + goto breakOut; + } + pixbuf = targa_rgba + row * columns * 4; + } + } + } else { // non run-length packet + for (j = 0; j < packetSize; j++) { + switch (targa_header.pixel_size) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + column++; + if (column == columns) { // pixel packet run spans across rows + column = 0; + if (row > 0) { + row--; + } else { + goto breakOut; + } + pixbuf = targa_rgba + row * columns * 4; + } + } + } + } + breakOut:; + } + } + + FS_FreeFile(buffer); + return qtrue; } /* @@ -263,64 +266,62 @@ qboolean CM_LoadTGA( const char *name, byte **pic, int *width, int *height ) CM_LoadFCM ==================== */ -qboolean CM_LoadFCM( const char *szName, cfencemask_t **pMask ) +qboolean CM_LoadFCM(const char *szName, cfencemask_t **pMask) { - unsigned int version; - int length; - int iDataSize; - fileHandle_t h; - fcm_t header; - cfencemask_t *m; - char tempName[ 256 ]; + unsigned int version; + int length; + int iDataSize; + fileHandle_t h; + fcm_t header; + cfencemask_t *m; + char tempName[256]; - *pMask = NULL; + *pMask = NULL; - COM_StripExtension( szName, tempName, sizeof( tempName ) ); - strcat( tempName, ".fcm" ); + COM_StripExtension(szName, tempName, sizeof(tempName)); + strcat(tempName, ".fcm"); - length = FS_FOpenFileRead( tempName, &h, qtrue, qtrue ); - if( length <= 0 ) { - return qfalse; - } + length = FS_FOpenFileRead(tempName, &h, qtrue, qtrue); + if (length <= 0) { + return qfalse; + } - FS_Read( &version, sizeof( int ), h ); + FS_Read(&version, sizeof(int), h); - if( LittleLong( version ) != FENCEMASK_VERSION ) - { - FS_FCloseFile( h ); - Com_Printf( "CM_LoadFCM: %s is not correct version, skipping\n", tempName ); - return qfalse; - } + if (LittleLong(version) != FENCEMASK_VERSION) { + FS_FCloseFile(h); + Com_Printf("CM_LoadFCM: %s is not correct version, skipping\n", tempName); + return qfalse; + } - FS_Read( &header, sizeof( fcm_t ), h ); + FS_Read(&header, sizeof(fcm_t), h); - iDataSize = LittleLong( header.iWidth ) * LittleLong( header.iHeight ) + 7; - if( iDataSize < 0 ) { - iDataSize = LittleLong( header.iWidth ) * LittleLong( header.iHeight ) + 14; - } + iDataSize = LittleLong(header.iWidth) * LittleLong(header.iHeight) + 7; + if (iDataSize < 0) { + iDataSize = LittleLong(header.iWidth) * LittleLong(header.iHeight) + 14; + } - iDataSize >>= 3; + iDataSize >>= 3; - if( iDataSize != ( length - sizeof( fcm_t ) - sizeof( unsigned int ) ) ) - { - FS_FCloseFile( h ); - Com_Printf( "CM_LoadFCM: size mismatch in %s, skipping\n", tempName ); - return qfalse; - } + if (iDataSize != (length - sizeof(fcm_t) - sizeof(unsigned int))) { + FS_FCloseFile(h); + Com_Printf("CM_LoadFCM: size mismatch in %s, skipping\n", tempName); + return qfalse; + } - m = (cfencemask_t*)Hunk_Alloc(sizeof(cfencemask_t), h_dontcare); - *pMask = m; - strcpy( m->name, szName ); - m->iWidth = header.iWidth; + m = (cfencemask_t *)Hunk_Alloc(sizeof(cfencemask_t), h_dontcare); + *pMask = m; + strcpy(m->name, szName); + m->iWidth = header.iWidth; m->iHeight = header.iHeight; - m->pData = (byte*)Hunk_Alloc(iDataSize, h_dontcare); - FS_Read( m->pData, iDataSize, h ); - FS_FCloseFile( h ); + m->pData = (byte *)Hunk_Alloc(iDataSize, h_dontcare); + FS_Read(m->pData, iDataSize, h); + FS_FCloseFile(h); - sprintf( tempName, "f%s", szName ); - UI_LoadResource( tempName ); + sprintf(tempName, "f%s", szName); + UI_LoadResource(tempName); - return qtrue; + return qtrue; } /* @@ -328,72 +329,69 @@ qboolean CM_LoadFCM( const char *szName, cfencemask_t **pMask ) CM_SaveFCM ==================== */ -void CM_SaveFCM( const char *szName, cfencemask_t **pMask ) +void CM_SaveFCM(const char *szName, cfencemask_t **pMask) { - fileHandle_t h; - unsigned int version; - byte *pData; - int i, j; - int iMaskPos; - char endline, solid, clear; - char tempName[ 256 ]; + fileHandle_t h; + unsigned int version; + byte *pData; + int i, j; + int iMaskPos; + char endline, solid, clear; + char tempName[256]; - COM_StripExtension( szName, tempName, sizeof( tempName ) ); - strcat( tempName, ".fcm" ); - h = FS_FOpenFileWrite( tempName ); + COM_StripExtension(szName, tempName, sizeof(tempName)); + strcat(tempName, ".fcm"); + h = FS_FOpenFileWrite(tempName); - if( !h ) { - return; - } + if (!h) { + return; + } - version = FENCEMASK_VERSION; - FS_Write( &version, sizeof( unsigned int ), h ); - FS_Write( &( *pMask )->iWidth, sizeof( int ), h ); - FS_Write( &( *pMask )->iHeight, sizeof( int ), h ); + version = FENCEMASK_VERSION; + FS_Write(&version, sizeof(unsigned int), h); + FS_Write(&(*pMask)->iWidth, sizeof(int), h); + FS_Write(&(*pMask)->iHeight, sizeof(int), h); - iMaskPos = ( *pMask )->iHeight * ( *pMask )->iWidth + 7; - if( iMaskPos < 0 ) { - iMaskPos = ( *pMask )->iHeight * ( *pMask )->iWidth + 7 * 2; - } - FS_Write( ( *pMask )->pData, iMaskPos >> 3, h ); - FS_FCloseFile( h ); + iMaskPos = (*pMask)->iHeight * (*pMask)->iWidth + 7; + if (iMaskPos < 0) { + iMaskPos = (*pMask)->iHeight * (*pMask)->iWidth + 7 * 2; + } + FS_Write((*pMask)->pData, iMaskPos >> 3, h); + FS_FCloseFile(h); - // save debug info - if( developer->integer && cm_FCMdebug->integer ) - { - endline = '\n'; - solid = 'X'; - clear = '.'; + // save debug info + if (developer->integer && cm_FCMdebug->integer) { + endline = '\n'; + solid = 'X'; + clear = '.'; - COM_StripExtension( szName, tempName, sizeof( tempName ) ); - strcat( tempName, ".fcm" ); - h = FS_FOpenFileWrite( tempName ); - if( !h ) { - return; - } + COM_StripExtension(szName, tempName, sizeof(tempName)); + strcat(tempName, ".fcm"); + h = FS_FOpenFileWrite(tempName); + if (!h) { + return; + } - pData = ( *pMask )->pData; - for( i = 0; i < ( *pMask )->iHeight; i++ ) - { - for( j = 0; j < ( *pMask )->iWidth; j++ ) - { - int b1, b2; + pData = (*pMask)->pData; + for (i = 0; i < (*pMask)->iHeight; i++) { + for (j = 0; j < (*pMask)->iWidth; j++) { + int b1, b2; - b1 = ( j + ( *pMask )->iWidth * i ) & 7; - b2 = pData[ ( j + ( *pMask )->iWidth * i ) >> 3 ]; + b1 = (j + (*pMask)->iWidth * i) & 7; + b2 = pData[(j + (*pMask)->iWidth * i) >> 3]; - if(b2 & (1 << b1)) { - FS_Write( &solid, 1, h ); - } else { - FS_Write( &clear, 1, h ); - } - } + if (b2 & (1 << b1)) { + FS_Write(&solid, 1, h); + } else { + FS_Write(&clear, 1, h); + } + } - FS_Write( &endline, 1, h ); - } + FS_Write(&endline, 1, h); + } - FS_FCloseFile( h ); - } + FS_FCloseFile(h); + } } /* @@ -401,22 +399,22 @@ void CM_SaveFCM( const char *szName, cfencemask_t **pMask ) CM_GenerateDummyFenceMask ==================== */ -cfencemask_t *CM_GenerateDummyFenceMask( const char *szName, qboolean bOpaque ) +cfencemask_t *CM_GenerateDummyFenceMask(const char *szName, qboolean bOpaque) { - cfencemask_t *pMask; + cfencemask_t *pMask; - pMask = Hunk_Alloc(sizeof(cfencemask_t) + sizeof(byte), h_dontcare); - pMask->iWidth = 2; - pMask->iHeight = 2; - pMask->pData = ( byte * )( ( char * )pMask + sizeof( cfencemask_t ) ); + pMask = Hunk_Alloc(sizeof(cfencemask_t) + sizeof(byte), h_dontcare); + pMask->iWidth = 2; + pMask->iHeight = 2; + pMask->pData = (byte *)((char *)pMask + sizeof(cfencemask_t)); - if( bOpaque ) { - *( byte * )pMask->pData = -1; - } else { - *( byte * )pMask->pData = 0; - } + if (bOpaque) { + *(byte *)pMask->pData = -1; + } else { + *(byte *)pMask->pData = 0; + } - return pMask; + return pMask; } /* @@ -424,89 +422,84 @@ cfencemask_t *CM_GenerateDummyFenceMask( const char *szName, qboolean bOpaque ) CM_GenerateFenceMask ==================== */ -qboolean CM_GenerateFenceMask( const char *szName, cfencemask_t **pMask ) +qboolean CM_GenerateFenceMask(const char *szName, cfencemask_t **pMask) { - int i; - int iImageWidth; - int iImageHeight; - int iImageSize; - int iMaskSize; - int iWidth; - int iHeight; - byte *pImage; - byte *pCurrImage; - byte *pCurrMask; - qboolean bHasTrans = qfalse; - qboolean bHasOpaque = qfalse; - char tempName[ 256 ]; + int i; + int iImageWidth; + int iImageHeight; + int iImageSize; + int iMaskSize; + int iWidth; + int iHeight; + byte *pImage; + byte *pCurrImage; + byte *pCurrMask; + qboolean bHasTrans = qfalse; + qboolean bHasOpaque = qfalse; + char tempName[256]; - *pMask = NULL; + *pMask = NULL; - COM_StripExtension( szName, tempName, sizeof( tempName ) ); - strcat( tempName, ".ftx" ); + COM_StripExtension(szName, tempName, sizeof(tempName)); + strcat(tempName, ".ftx"); - if( !CM_LoadFTX( tempName, &pImage, &iImageWidth, &iImageHeight ) ) { - return qfalse; - } + if (!CM_LoadFTX(tempName, &pImage, &iImageWidth, &iImageHeight)) { + return qfalse; + } - if( !pImage ) - { - if( !CM_LoadTGA( szName, &pImage, &iImageWidth, &iImageHeight ) ) { - return qfalse; - } + if (!pImage) { + if (!CM_LoadTGA(szName, &pImage, &iImageWidth, &iImageHeight)) { + return qfalse; + } - if( !pImage ) { - return qfalse; - } - } + if (!pImage) { + return qfalse; + } + } - iWidth = iImageWidth; - iHeight = iImageHeight; - iImageSize = iImageWidth * iImageHeight; - iMaskSize = iImageSize + 7; - if( iMaskSize < 0 ) { - iMaskSize = iImageSize + 7 * 2; - } + iWidth = iImageWidth; + iHeight = iImageHeight; + iImageSize = iImageWidth * iImageHeight; + iMaskSize = iImageSize + 7; + if (iMaskSize < 0) { + iMaskSize = iImageSize + 7 * 2; + } - pCurrImage = pImage + 3; + pCurrImage = pImage + 3; - for( i = 0; i < iImageSize; i++, pCurrImage += sizeof( unsigned int ) ) - { - if( *pCurrImage & 0x80 ) - { - bHasOpaque = qtrue; - } else { - bHasTrans = qtrue; - } + for (i = 0; i < iImageSize; i++, pCurrImage += sizeof(unsigned int)) { + if (*pCurrImage & 0x80) { + bHasOpaque = qtrue; + } else { + bHasTrans = qtrue; + } - if( bHasOpaque && bHasTrans ) { - break; - } - } + if (bHasOpaque && bHasTrans) { + break; + } + } - // load the mask if it has transparence and is opaque - if( bHasOpaque && bHasTrans ) - { + // load the mask if it has transparence and is opaque + if (bHasOpaque && bHasTrans) { *pMask = Hunk_Alloc((iMaskSize >> 3) + sizeof(cfencemask_t), h_dontcare); - strcpy( ( *pMask )->name, szName ); - ( *pMask )->iWidth = iWidth; - ( *pMask )->iHeight = iHeight; - ( *pMask )->pData = ( byte * )( ( char * )*pMask + sizeof( cfencemask_t ) ); + strcpy((*pMask)->name, szName); + (*pMask)->iWidth = iWidth; + (*pMask)->iHeight = iHeight; + (*pMask)->pData = (byte *)((char *)*pMask + sizeof(cfencemask_t)); - pCurrMask = ( *pMask )->pData; - pCurrImage = pImage + 3; - for( i = 0; i < iImageSize; i++, pCurrImage += sizeof( unsigned int ) ) - { - if( *pCurrImage < 0 ) { - pCurrMask[ i >> 3 ] |= 1 << ( i & 7 ); - } - } - } else { - *pMask = CM_GenerateDummyFenceMask( szName, bHasOpaque ); - } + pCurrMask = (*pMask)->pData; + pCurrImage = pImage + 3; + for (i = 0; i < iImageSize; i++, pCurrImage += sizeof(unsigned int)) { + if (*pCurrImage < 0) { + pCurrMask[i >> 3] |= 1 << (i & 7); + } + } + } else { + *pMask = CM_GenerateDummyFenceMask(szName, bHasOpaque); + } - Hunk_FreeTempMemory( pImage ); - return qtrue; + Hunk_FreeTempMemory(pImage); + return qtrue; } /* @@ -514,13 +507,13 @@ qboolean CM_GenerateFenceMask( const char *szName, cfencemask_t **pMask ) CM_CheckFCMFileRefresh ==================== */ -qboolean CM_CheckFCMFileRefresh( const char *szFile ) +qboolean CM_CheckFCMFileRefresh(const char *szFile) { - char tempName[ 256 ]; + char tempName[256]; - COM_StripExtension( szFile, tempName, sizeof( tempName ) ); - strcat( tempName, ".fcm" ); - return FS_FileNewer( szFile, tempName ) > 0; + COM_StripExtension(szFile, tempName, sizeof(tempName)); + strcat(tempName, ".fcm"); + return FS_FileNewer(szFile, tempName) > 0; } /* @@ -528,70 +521,63 @@ qboolean CM_CheckFCMFileRefresh( const char *szFile ) CM_GetFenceMask ==================== */ -cfencemask_t *CM_GetFenceMask( const char *szMaskName ) +cfencemask_t *CM_GetFenceMask(const char *szMaskName) { - qboolean save; - cfencemask_t *pMask; + qboolean save; + cfencemask_t *pMask; - if( !szMaskName || !*szMaskName ) { - return NULL; - } + if (!szMaskName || !*szMaskName) { + return NULL; + } - if( !memcmp( szMaskName, "nomask", 7 ) ) { - return NULL; - } + if (!memcmp(szMaskName, "nomask", 7)) { + return NULL; + } - if( !memcmp( szMaskName, "ignore", 7 ) ) { - return &cmf_dummy_trans; - } + if (!memcmp(szMaskName, "ignore", 7)) { + return &cmf_dummy_trans; + } - for( pMask = cm.fencemasks; pMask != NULL; pMask = pMask->pNext ) - { - if( !strcmp( szMaskName, pMask->name ) ) { - if( pMask->pData ) { - return pMask; - } else { - return NULL; - } - } - } + for (pMask = cm.fencemasks; pMask != NULL; pMask = pMask->pNext) { + if (!strcmp(szMaskName, pMask->name)) { + if (pMask->pData) { + return pMask; + } else { + return NULL; + } + } + } - save = qfalse; + save = qfalse; - if( developer->integer ) - { - if( cm_FCMcacheall->integer ) - { - save = qtrue; - } - else - { - if( CM_CheckFCMFileRefresh( szMaskName ) ) { - save = qtrue; - } - } - } + if (developer->integer) { + if (cm_FCMcacheall->integer) { + save = qtrue; + } else { + if (CM_CheckFCMFileRefresh(szMaskName)) { + save = qtrue; + } + } + } - if( save || !CM_LoadFCM( szMaskName, &pMask ) ) - { - if( !CM_GenerateFenceMask( szMaskName, &pMask ) ) - { - pMask = (cfencemask_t*)Hunk_Alloc(sizeof(cfencemask_t), h_dontcare); - strcpy( pMask->name, szMaskName ); - pMask->pData = NULL; - pMask->pNext = cm.fencemasks; - cm.fencemasks = pMask; - return NULL; - } - } + if (save || !CM_LoadFCM(szMaskName, &pMask)) { + if (!CM_GenerateFenceMask(szMaskName, &pMask)) { + pMask = (cfencemask_t *)Hunk_Alloc(sizeof(cfencemask_t), h_dontcare); + strcpy(pMask->name, szMaskName); + pMask->pData = NULL; + pMask->pNext = cm.fencemasks; + cm.fencemasks = pMask; + return NULL; + } + } - if( save ) { - CM_SaveFCM( szMaskName, &pMask ); - } + if (save) { + CM_SaveFCM(szMaskName, &pMask); + } - pMask->pNext = cm.fencemasks; - cm.fencemasks = pMask; - return pMask; + pMask->pNext = cm.fencemasks; + cm.fencemasks = pMask; + return pMask; } /* @@ -599,47 +585,49 @@ cfencemask_t *CM_GetFenceMask( const char *szMaskName ) CM_TraceThroughFence ==================== */ -qboolean CM_TraceThroughFence( traceWork_t *tw, cbrush_t *brush, cbrushside_t *side, float fTraceFraction ) +qboolean CM_TraceThroughFence(traceWork_t *tw, cbrush_t *brush, cbrushside_t *side, float fTraceFraction) { - int i; - int iMaskPos; - float fS; - float fT; - float *vNorm; - vec3_t vPos; - cfencemask_t *pMask; + int i; + int iMaskPos; + float fS; + float fT; + float *vNorm; + vec3_t vPos; + cfencemask_t *pMask; - pMask = cm.shaders[ side->shaderNum ].mask; - if( !pMask ) { - return qtrue; - } + pMask = cm.shaders[side->shaderNum].mask; + if (!pMask) { + return qtrue; + } - if( pMask == &cmf_dummy_trans ) { - return qfalse; - } + if (pMask == &cmf_dummy_trans) { + return qfalse; + } - if( !side->pEq ) { - return qtrue; - } + if (!side->pEq) { + return qtrue; + } - for( i = 0; i < 3; i++ ) - { - vNorm = side->plane->normal; - vPos[ i ] = tw->start[ i ] + fTraceFraction * ( tw->end[ i ] - tw->start[ i ] ) - SURFACE_CLIP_EPSILON * vNorm[ i ]; - } + for (i = 0; i < 3; i++) { + vNorm = side->plane->normal; + vPos[i] = tw->start[i] + fTraceFraction * (tw->end[i] - tw->start[i]) - SURFACE_CLIP_EPSILON * vNorm[i]; + } - fS = DotProduct( vPos, side->pEq->fSeq ) + side->pEq->fSeq[ 3 ]; - fS = fS - floor( fS ); - fT = DotProduct( vPos, side->pEq->fTeq ) + side->pEq->fTeq[ 3 ]; - fT = fT - floor( fT ); + fS = DotProduct(vPos, side->pEq->fSeq) + side->pEq->fSeq[3]; + fS = fS - floor(fS); + fT = DotProduct(vPos, side->pEq->fTeq) + side->pEq->fTeq[3]; + fT = fT - floor(fT); - if( cm_FCMdebug->integer ) - { - Com_Printf( "Trace ST coords: (%.2f %.2f) or (%i %i)\n", - fS, fT, - ( int )( ( float )pMask->iWidth * fS ), ( int )( ( float )pMask->iHeight * fT ) ); - } + if (cm_FCMdebug->integer) { + Com_Printf( + "Trace ST coords: (%.2f %.2f) or (%i %i)\n", + fS, + fT, + (int)((float)pMask->iWidth * fS), + (int)((float)pMask->iHeight * fT) + ); + } - iMaskPos = ( int )( ( float )pMask->iWidth * fS ) + pMask->iWidth * ( int )( ( float )pMask->iHeight * fT ); - return ( 1 << ( iMaskPos & 7 ) ) & pMask->pData[ iMaskPos >> 3 ]; + iMaskPos = (int)((float)pMask->iWidth * fS) + pMask->iWidth * (int)((float)pMask->iHeight * fT); + return (1 << (iMaskPos & 7)) & pMask->pData[iMaskPos >> 3]; } From e930b5481a6102c3dfd6ed6b62ef4fc3ad151fc5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 2 Mar 2024 15:27:35 +0100 Subject: [PATCH 0269/2040] Mark the trigger as dead after kill --- code/fgame/trigger.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/trigger.cpp b/code/fgame/trigger.cpp index 1c504090..11cc3392 100644 --- a/code/fgame/trigger.cpp +++ b/code/fgame/trigger.cpp @@ -788,6 +788,10 @@ void Trigger::DamageEvent(Event *ev) if (health <= 0) { Event *event; + if (max_health) { + deadflag = DEAD_DEAD; + } + event = new Event(EV_Activate, 1); event->AddEntity(attacker); ProcessEvent(event); From 01e68fd5eeb6ebbc5856ce640951630e94c33ca0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 2 Mar 2024 15:29:08 +0100 Subject: [PATCH 0270/2040] Fixed turret gun never being killed This fixes #231 --- code/fgame/vehicleturret.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/vehicleturret.cpp b/code/fgame/vehicleturret.cpp index 5e58c1c9..a100b02b 100644 --- a/code/fgame/vehicleturret.cpp +++ b/code/fgame/vehicleturret.cpp @@ -756,7 +756,7 @@ void VehicleTurretGun::EventDamage(Event *ev) break; } - DamageEvent(ev); + Entity::DamageEvent(ev); return; } From bf5fdb8f06d454ecab8011748ddbc86b1075167f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 2 Mar 2024 15:29:25 +0100 Subject: [PATCH 0271/2040] Fixed improper fence masks This fixes #284, fixes #280 --- code/qcommon/cm_fencemask.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/code/qcommon/cm_fencemask.c b/code/qcommon/cm_fencemask.c index 098081fb..42c53357 100644 --- a/code/qcommon/cm_fencemask.c +++ b/code/qcommon/cm_fencemask.c @@ -468,7 +468,8 @@ qboolean CM_GenerateFenceMask(const char *szName, cfencemask_t **pMask) pCurrImage = pImage + 3; for (i = 0; i < iImageSize; i++, pCurrImage += sizeof(unsigned int)) { - if (*pCurrImage & 0x80) { + if (*pCurrImage >= 128) { + // Treat pixels with > 128 alpha value as opaque bHasOpaque = qtrue; } else { bHasTrans = qtrue; @@ -485,12 +486,12 @@ qboolean CM_GenerateFenceMask(const char *szName, cfencemask_t **pMask) strcpy((*pMask)->name, szName); (*pMask)->iWidth = iWidth; (*pMask)->iHeight = iHeight; - (*pMask)->pData = (byte *)((char *)*pMask + sizeof(cfencemask_t)); + (*pMask)->pData = (byte *)((byte *)*pMask + sizeof(**pMask)); pCurrMask = (*pMask)->pData; pCurrImage = pImage + 3; for (i = 0; i < iImageSize; i++, pCurrImage += sizeof(unsigned int)) { - if (*pCurrImage < 0) { + if (*pCurrImage >= 128) { pCurrMask[i >> 3] |= 1 << (i & 7); } } From 4c4ac9f90e1087296947af835273fdfe74839880 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 14:03:38 +0100 Subject: [PATCH 0272/2040] Added more assertions for consistency --- code/renderer/tr_terrain.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 80c4bb01..831f409a 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -99,6 +99,8 @@ static terraInt R_AllocateVert(cTerraPatchUnpacked_t* patch) patch->drawinfo.iVertHead = iVert; patch->drawinfo.nVerts++; + + assert(g_vert.nFree > 0); g_vert.nFree--; g_pVert[iVert].nRef = 0; @@ -170,6 +172,7 @@ terraInt R_AllocateTri(cTerraPatchUnpacked_t* patch, qboolean check) } patch->drawinfo.nTris++; + assert(g_tri.nFree > 0); g_tri.nFree--; g_pTris[iTri].byConstChecks = check ? 0 : 4; @@ -424,9 +427,13 @@ static void R_ForceSplit(terraInt iTri) terraTri_t* pBase = &g_pTris[iBase]; if (iBase && pBase->lod != pTri->lod) { - assert(g_pTris[pBase->iBase].iBase != iTri); + assert(g_pTris[pTri->iBase].iBase != iTri); + assert(g_tri.nFree >= 8); R_ForceSplit(iBase); + + assert(g_tri.nFree >= 4); + iBase = pTri->iBase; pBase = &g_pTris[iBase]; } @@ -1158,7 +1165,7 @@ void R_TessellateTerrain() R_DoTriSplitting(); // Morph geometry according to the view R_DoGeomorphs(); - // Split vertices + // Merge vertices R_DoTriMerging(); } From 26495fe0f800473fe4844bf88a52ecb7ef6290f7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 16:43:27 +0100 Subject: [PATCH 0273/2040] Refactored R_TerraTriNeighbor --- code/renderer/tr_terrain.c | 77 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 831f409a..4e637206 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -516,7 +516,7 @@ static void R_ForceMerge(terraInt iTri) { terraInt iLeft = g_pTris[pTri->iLeftChild].iBase; - g_pTris[iTri].iLeft = iLeft; + pTri->iLeft = iLeft; if (iLeft) { if (g_pTris[iLeft].lod == pTri->lod) @@ -538,7 +538,8 @@ static void R_ForceMerge(terraInt iTri) if (pTri->iRightChild) { terraInt iRight = g_pTris[pTri->iRightChild].iBase; - g_pTris[iTri].iRight = iRight; + + pTri->iRight = iRight; if (iRight) { if (g_pTris[iRight].lod == pTri->lod) @@ -585,45 +586,41 @@ static void R_ForceMerge(terraInt iTri) static int R_TerraTriNeighbor(cTerraPatchUnpacked_t* terraPatches, int iPatch, int dir) { - if (iPatch >= 0) - { - int iNeighbor = 2 * iPatch + 1; + int iNeighbor; - if (dir == 1) - { - if (terraPatches[iPatch].flags & 0x80) - { - return iNeighbor; - } - else - { - return iNeighbor + 1; - } - } - else if (dir > 1) - { - if (dir == 2) - { - return 2 * iPatch + 2; - } - if (dir == 3) - { - if (terraPatches[iPatch].flags & 0x80) - { - return iNeighbor + 1; - } - else - { - return iNeighbor; - } - } - } - else if (!dir) - { - return 2 * iPatch + 1; - } + if (iPatch < 0) { + return 0; } + iNeighbor = 2 * iPatch + 1; + + switch (dir) { + case 0: + return iNeighbor; + case 1: + if (terraPatches[iPatch].flags & 0x80) + { + return iNeighbor; + } + else + { + return iNeighbor + 1; + } + break; + case 2: + return iNeighbor + 1; + case 3: + if (terraPatches[iPatch].flags & 0x80) + { + return iNeighbor + 1; + } + else + { + return iNeighbor; + } + break; + } + return 0; } @@ -1181,6 +1178,10 @@ void R_TerrainPrepareFrame() return; } + if (tr.viewParms.isPortalSky) { + return; + } + g_terVisCount++; tr.world->activeTerraPatches = NULL; From bebe117487e743e96ed6ab5271fdc737a8c5b62f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 17:34:01 +0100 Subject: [PATCH 0274/2040] Formatted document --- code/renderer/tr_terrain.c | 2145 +++++++++++++++++------------------- 1 file changed, 1003 insertions(+), 1142 deletions(-) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 4e637206..0c787b73 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -24,15 +24,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" -cvar_t* ter_maxlod; -cvar_t* ter_maxtris; -cvar_t* ter_cull; -cvar_t* ter_lock; -cvar_t* ter_error; -cvar_t* ter_cautiousframes; -cvar_t* ter_count; +cvar_t *ter_maxlod; +cvar_t *ter_maxtris; +cvar_t *ter_cull; +cvar_t *ter_lock; +cvar_t *ter_error; +cvar_t *ter_cautiousframes; +cvar_t *ter_count; -#define TERRAIN_TABLE_SIZE 180 +#define TERRAIN_TABLE_SIZE 180 static float g_fDistanceTable[TERRAIN_TABLE_SIZE]; static float g_fClipDotProductTable[TERRAIN_TABLE_SIZE]; @@ -46,551 +46,510 @@ static vec3_t g_vClipVector; static vec3_t g_vViewOrigin; static vec3_t g_vViewVector; -static int g_terVisCount; -static float g_fCheck; +static int g_terVisCount; +static float g_fCheck; static size_t g_nTris; static size_t g_nVerts; -static int g_nMerge; -static int g_nSplit; -unsigned int g_uiTerDist; -vec2_t g_vTerOrg; -vec3_t g_vTerFwd; +static int g_nMerge; +static int g_nSplit; +unsigned int g_uiTerDist; +vec2_t g_vTerOrg; +vec3_t g_vTerFwd; -static const unsigned int MAX_TERRAIN_LOD = 6; -static const float TERRAIN_LIGHTMAP_SIZE = 128.0f; +static const unsigned int MAX_TERRAIN_LOD = 6; +static const float TERRAIN_LIGHTMAP_SIZE = 128.0f; -typedef struct poolInfo_s -{ - terraInt iFreeHead; - terraInt iCur; - size_t nFree; +typedef struct poolInfo_s { + terraInt iFreeHead; + terraInt iCur; + size_t nFree; } poolInfo_t; static int modeTable[8]; -terraTri_t* g_pTris; -terrainVert_t* g_pVert; +terraTri_t *g_pTris; +terrainVert_t *g_pVert; poolInfo_t g_tri; poolInfo_t g_vert; -static void R_ValidateHeightmapForVertex(terraTri_t* pTri) +static void R_ValidateHeightmapForVertex(terraTri_t *pTri) { - for (terraInt i = 0; i < 3; i++) - { - terrainVert_t* pVert = &g_pVert[pTri->iPt[i]]; - if (pVert->pHgt < pTri->patch->heightmap || pVert->pHgt > &pTri->patch->heightmap[80]) - { - pVert->pHgt = pTri->patch->heightmap; - } - } + for (terraInt i = 0; i < 3; i++) { + terrainVert_t *pVert = &g_pVert[pTri->iPt[i]]; + if (pVert->pHgt < pTri->patch->heightmap || pVert->pHgt > &pTri->patch->heightmap[80]) { + pVert->pHgt = pTri->patch->heightmap; + } + } } -static terraInt R_AllocateVert(cTerraPatchUnpacked_t* patch) +static terraInt R_AllocateVert(cTerraPatchUnpacked_t *patch) { - terraInt iVert = g_vert.iFreeHead; + terraInt iVert = g_vert.iFreeHead; - g_vert.iFreeHead = g_pVert[g_vert.iFreeHead].iNext; - g_pVert[g_vert.iFreeHead].iPrev = 0; + g_vert.iFreeHead = g_pVert[g_vert.iFreeHead].iNext; + g_pVert[g_vert.iFreeHead].iPrev = 0; - g_pVert[iVert].iPrev = 0; - g_pVert[iVert].iNext = patch->drawinfo.iVertHead; - g_pVert[patch->drawinfo.iVertHead].iPrev = iVert; + g_pVert[iVert].iPrev = 0; + g_pVert[iVert].iNext = patch->drawinfo.iVertHead; + g_pVert[patch->drawinfo.iVertHead].iPrev = iVert; - patch->drawinfo.iVertHead = iVert; - patch->drawinfo.nVerts++; + patch->drawinfo.iVertHead = iVert; + patch->drawinfo.nVerts++; - assert(g_vert.nFree > 0); - g_vert.nFree--; + assert(g_vert.nFree > 0); + g_vert.nFree--; - g_pVert[iVert].nRef = 0; - g_pVert[iVert].uiDistRecalc = 0; + g_pVert[iVert].nRef = 0; + g_pVert[iVert].uiDistRecalc = 0; - return iVert; + return iVert; } -static void R_InterpolateVert(terraTri_t* pTri, terrainVert_t* pVert) +static void R_InterpolateVert(terraTri_t *pTri, terrainVert_t *pVert) { - const terrainVert_t* pVert0 = &g_pVert[pTri->iPt[0]]; - const terrainVert_t* pVert1 = &g_pVert[pTri->iPt[1]]; - const cTerraPatchUnpacked_t* pPatch = pTri->patch; + const terrainVert_t *pVert0 = &g_pVert[pTri->iPt[0]]; + const terrainVert_t *pVert1 = &g_pVert[pTri->iPt[1]]; + const cTerraPatchUnpacked_t *pPatch = pTri->patch; - // Interpolate texture coordinates - pVert->texCoords[0][0] = (pVert0->texCoords[0][0] + pVert1->texCoords[0][0]) * 0.5f; - pVert->texCoords[0][1] = (pVert0->texCoords[0][1] + pVert1->texCoords[0][1]) * 0.5f; - pVert->texCoords[1][0] = (pVert0->texCoords[1][0] + pVert1->texCoords[1][0]) * 0.5f; - pVert->texCoords[1][1] = (pVert0->texCoords[1][1] + pVert1->texCoords[1][1]) * 0.5f; + // Interpolate texture coordinates + pVert->texCoords[0][0] = (pVert0->texCoords[0][0] + pVert1->texCoords[0][0]) * 0.5f; + pVert->texCoords[0][1] = (pVert0->texCoords[0][1] + pVert1->texCoords[0][1]) * 0.5f; + pVert->texCoords[1][0] = (pVert0->texCoords[1][0] + pVert1->texCoords[1][0]) * 0.5f; + pVert->texCoords[1][1] = (pVert0->texCoords[1][1] + pVert1->texCoords[1][1]) * 0.5f; - pVert->pHgt = (uint8_t*)(((size_t)pVert0->pHgt + (size_t)pVert1->pHgt) >> 1); - pVert->fHgtAvg = (float)(*pVert0->pHgt + *pVert1->pHgt); - pVert->fHgtAdd = (float)(*pVert->pHgt * 2) - pVert->fHgtAvg; - pVert->fHgtAvg += pPatch->z0; - pVert->xyz[0] = (pVert0->xyz[0] + pVert1->xyz[0]) * 0.5f; - pVert->xyz[1] = (pVert0->xyz[1] + pVert1->xyz[1]) * 0.5f; - pVert->xyz[2] = pVert->fHgtAvg; + pVert->pHgt = (uint8_t *)(((size_t)pVert0->pHgt + (size_t)pVert1->pHgt) >> 1); + pVert->fHgtAvg = (float)(*pVert0->pHgt + *pVert1->pHgt); + pVert->fHgtAdd = (float)(*pVert->pHgt * 2) - pVert->fHgtAvg; + pVert->fHgtAvg += pPatch->z0; + pVert->xyz[0] = (pVert0->xyz[0] + pVert1->xyz[0]) * 0.5f; + pVert->xyz[1] = (pVert0->xyz[1] + pVert1->xyz[1]) * 0.5f; + pVert->xyz[2] = pVert->fHgtAvg; } -static void R_ReleaseVert(cTerraPatchUnpacked_t* patch, int iVert) +static void R_ReleaseVert(cTerraPatchUnpacked_t *patch, int iVert) { - terrainVert_t* pVert = &g_pVert[iVert]; + terrainVert_t *pVert = &g_pVert[iVert]; - terraInt iPrev = pVert->iPrev; - terraInt iNext = pVert->iNext; - g_pVert[iPrev].iNext = iNext; - g_pVert[iNext].iPrev = iPrev; + terraInt iPrev = pVert->iPrev; + terraInt iNext = pVert->iNext; + g_pVert[iPrev].iNext = iNext; + g_pVert[iNext].iPrev = iPrev; - assert(patch->drawinfo.nVerts > 0); - patch->drawinfo.nVerts--; + assert(patch->drawinfo.nVerts > 0); + patch->drawinfo.nVerts--; - if (patch->drawinfo.iVertHead == iVert) - { - patch->drawinfo.iVertHead = iNext; - } + if (patch->drawinfo.iVertHead == iVert) { + patch->drawinfo.iVertHead = iNext; + } - pVert->iPrev = 0; - pVert->iNext = g_vert.iFreeHead; - g_pVert[g_vert.iFreeHead].iPrev = iVert; - g_vert.iFreeHead = iVert; - g_vert.nFree++; + pVert->iPrev = 0; + pVert->iNext = g_vert.iFreeHead; + g_pVert[g_vert.iFreeHead].iPrev = iVert; + g_vert.iFreeHead = iVert; + g_vert.nFree++; } -terraInt R_AllocateTri(cTerraPatchUnpacked_t* patch, qboolean check) +terraInt R_AllocateTri(cTerraPatchUnpacked_t *patch, qboolean check) { - terraInt iTri = g_tri.iFreeHead; + terraInt iTri = g_tri.iFreeHead; - g_tri.iFreeHead = g_pTris[iTri].iNext; - g_pTris[g_tri.iFreeHead].iPrev = 0; + g_tri.iFreeHead = g_pTris[iTri].iNext; + g_pTris[g_tri.iFreeHead].iPrev = 0; - g_pTris[iTri].iPrev = patch->drawinfo.iTriTail; - g_pTris[iTri].iNext = 0; - g_pTris[patch->drawinfo.iTriTail].iNext = iTri; - patch->drawinfo.iTriTail = iTri; + g_pTris[iTri].iPrev = patch->drawinfo.iTriTail; + g_pTris[iTri].iNext = 0; + g_pTris[patch->drawinfo.iTriTail].iNext = iTri; + patch->drawinfo.iTriTail = iTri; - if (!patch->drawinfo.iTriHead) - { - patch->drawinfo.iTriHead = iTri; - } + if (!patch->drawinfo.iTriHead) { + patch->drawinfo.iTriHead = iTri; + } - patch->drawinfo.nTris++; - assert(g_tri.nFree > 0); - g_tri.nFree--; + patch->drawinfo.nTris++; + assert(g_tri.nFree > 0); + g_tri.nFree--; - g_pTris[iTri].byConstChecks = check ? 0 : 4; - g_pTris[iTri].uiDistRecalc = 0; - patch->uiDistRecalc = 0; + g_pTris[iTri].byConstChecks = check ? 0 : 4; + g_pTris[iTri].uiDistRecalc = 0; + patch->uiDistRecalc = 0; - return iTri; + return iTri; } -static void R_ReleaseTri(cTerraPatchUnpacked_t* patch, terraInt iTri) +static void R_ReleaseTri(cTerraPatchUnpacked_t *patch, terraInt iTri) { - terraTri_t* pTri = &g_pTris[iTri]; + terraTri_t *pTri = &g_pTris[iTri]; - terraInt iPrev = pTri->iPrev; - terraInt iNext = pTri->iNext; - g_pTris[iPrev].iNext = iNext; - g_pTris[iNext].iPrev = iPrev; + terraInt iPrev = pTri->iPrev; + terraInt iNext = pTri->iNext; + g_pTris[iPrev].iNext = iNext; + g_pTris[iNext].iPrev = iPrev; - if (g_tri.iCur == iTri) - { - g_tri.iCur = iNext; - } + if (g_tri.iCur == iTri) { + g_tri.iCur = iNext; + } - patch->uiDistRecalc = 0; + patch->uiDistRecalc = 0; - assert(patch->drawinfo.nTris > 0); - patch->drawinfo.nTris--; + assert(patch->drawinfo.nTris > 0); + patch->drawinfo.nTris--; - if (patch->drawinfo.iTriHead == iTri) - { - patch->drawinfo.iTriHead = iNext; - } + if (patch->drawinfo.iTriHead == iTri) { + patch->drawinfo.iTriHead = iNext; + } - if (patch->drawinfo.iTriTail == iTri) - { - patch->drawinfo.iTriTail = iPrev; - } + if (patch->drawinfo.iTriTail == iTri) { + patch->drawinfo.iTriTail = iPrev; + } - pTri->iPrev = 0; - pTri->iNext = g_tri.iFreeHead; - g_pTris[g_tri.iFreeHead].iPrev = iTri; - g_tri.iFreeHead = iTri; - g_tri.nFree++; + pTri->iPrev = 0; + pTri->iNext = g_tri.iFreeHead; + g_pTris[g_tri.iFreeHead].iPrev = iTri; + g_tri.iFreeHead = iTri; + g_tri.nFree++; - for (int i = 0; i < 3; i++) - { - terraInt ptNum = pTri->iPt[i]; + for (int i = 0; i < 3; i++) { + terraInt ptNum = pTri->iPt[i]; - g_pVert[ptNum].nRef--; - if (!g_pVert[ptNum].nRef) { - R_ReleaseVert(patch, ptNum); - } - } + g_pVert[ptNum].nRef--; + if (!g_pVert[ptNum].nRef) { + R_ReleaseVert(patch, ptNum); + } + } } -static int R_ConstChecksForTri(terraTri_t* pTri) +static int R_ConstChecksForTri(terraTri_t *pTri) { - varnodeUnpacked_t vn; + varnodeUnpacked_t vn; - if (pTri->lod == MAX_TERRAIN_LOD) { - return 2; - } + if (pTri->lod == MAX_TERRAIN_LOD) { + return 2; + } - vn = *pTri->varnode; - vn.s.flags &= 0xF0u; + vn = *pTri->varnode; + vn.s.flags &= 0xF0u; - if (vn.fVariance == 0.0 && !(pTri->varnode->s.flags & 8)) { - return 2; - } else if (pTri->varnode->s.flags & 8) { - return 3; - } else if ((pTri->byConstChecks & 4) && !(pTri->varnode->s.flags & 4) && pTri->lod < ter_maxlod->integer) { - return 0; - } + if (vn.fVariance == 0.0 && !(pTri->varnode->s.flags & 8)) { + return 2; + } else if (pTri->varnode->s.flags & 8) { + return 3; + } else if ((pTri->byConstChecks & 4) && !(pTri->varnode->s.flags & 4) && pTri->lod < ter_maxlod->integer) { + return 0; + } - return 2; + return 2; } -static void R_DemoteInAncestry(cTerraPatchUnpacked_t* patch, terraInt iTri) +static void R_DemoteInAncestry(cTerraPatchUnpacked_t *patch, terraInt iTri) { - terraInt iPrev = g_pTris[iTri].iPrev; - terraInt iNext = g_pTris[iTri].iNext; + terraInt iPrev = g_pTris[iTri].iPrev; + terraInt iNext = g_pTris[iTri].iNext; - g_pTris[iPrev].iNext = iNext; - g_pTris[iNext].iPrev = iPrev; + g_pTris[iPrev].iNext = iNext; + g_pTris[iNext].iPrev = iPrev; - if (g_tri.iCur == iTri) - { - g_tri.iCur = iNext; - } + if (g_tri.iCur == iTri) { + g_tri.iCur = iNext; + } - assert(patch->drawinfo.nTris > 0); - patch->drawinfo.nTris--; + assert(patch->drawinfo.nTris > 0); + patch->drawinfo.nTris--; - if (patch->drawinfo.iTriHead == iTri) - { - patch->drawinfo.iTriHead = iNext; - } + if (patch->drawinfo.iTriHead == iTri) { + patch->drawinfo.iTriHead = iNext; + } - if (patch->drawinfo.iTriTail == iTri) - { - patch->drawinfo.iTriTail = iPrev; - } + if (patch->drawinfo.iTriTail == iTri) { + patch->drawinfo.iTriTail = iPrev; + } - g_pTris[iTri].iPrev = 0; - g_pTris[iTri].iNext = patch->drawinfo.iMergeHead; - g_pTris[patch->drawinfo.iMergeHead].iPrev = iTri; - patch->drawinfo.iMergeHead = iTri; + g_pTris[iTri].iPrev = 0; + g_pTris[iTri].iNext = patch->drawinfo.iMergeHead; + g_pTris[patch->drawinfo.iMergeHead].iPrev = iTri; + patch->drawinfo.iMergeHead = iTri; } static void R_TerrainHeapInit() { - g_tri.iFreeHead = 1; - g_tri.nFree = g_nTris - 1; - g_vert.iFreeHead = 1; - g_vert.nFree = g_nVerts - 1; + g_tri.iFreeHead = 1; + g_tri.nFree = g_nTris - 1; + g_vert.iFreeHead = 1; + g_vert.nFree = g_nVerts - 1; - for (size_t i = 0; i < g_nTris; i++) - { - g_pTris[i].iPrev = (terraInt)i - 1; - g_pTris[i].iNext = (terraInt)i + 1; - } + for (size_t i = 0; i < g_nTris; i++) { + g_pTris[i].iPrev = (terraInt)i - 1; + g_pTris[i].iNext = (terraInt)i + 1; + } - g_pTris[0].iPrev = 0; - g_pTris[g_nTris - 1].iNext = 0; + g_pTris[0].iPrev = 0; + g_pTris[g_nTris - 1].iNext = 0; - for (size_t i = 0; i < g_nVerts; i++) - { - g_pVert[i].iPrev = (terraInt)i - 1; - g_pVert[i].iNext = (terraInt)i + 1; - } + for (size_t i = 0; i < g_nVerts; i++) { + g_pVert[i].iPrev = (terraInt)i - 1; + g_pVert[i].iNext = (terraInt)i + 1; + } - g_pVert[0].iPrev = 0; - g_pVert[g_nVerts - 1].iNext = 0; + g_pVert[0].iPrev = 0; + g_pVert[g_nVerts - 1].iNext = 0; } static void R_TerrainPatchesInit() { - int i; + int i; - for (i = 0; i < tr.world->numTerraPatches; i++) - { - cTerraPatchUnpacked_t* patch = &tr.world->terraPatches[i]; - patch->drawinfo.iTriHead = 0; - patch->drawinfo.iTriTail = 0; - patch->drawinfo.iMergeHead = 0; - patch->drawinfo.iVertHead = 0; - patch->drawinfo.nTris = 0; - patch->drawinfo.nVerts = 0; - } + for (i = 0; i < tr.world->numTerraPatches; i++) { + cTerraPatchUnpacked_t *patch = &tr.world->terraPatches[i]; + patch->drawinfo.iTriHead = 0; + patch->drawinfo.iTriTail = 0; + patch->drawinfo.iMergeHead = 0; + patch->drawinfo.iVertHead = 0; + patch->drawinfo.nTris = 0; + patch->drawinfo.nVerts = 0; + } } -void R_SplitTri(terraInt iSplit, terraInt iNewPt, terraInt iLeft, terraInt iRight, terraInt iRightOfLeft, terraInt iLeftOfRight) +void R_SplitTri( + terraInt iSplit, terraInt iNewPt, terraInt iLeft, terraInt iRight, terraInt iRightOfLeft, terraInt iLeftOfRight +) { - terraTri_t* pSplit = &g_pTris[iSplit]; + terraTri_t *pSplit = &g_pTris[iSplit]; - terraTri_t* pLeft; - if (iLeft) { - pLeft = &g_pTris[iLeft]; - } else { - pLeft = NULL; - } + terraTri_t *pLeft; + if (iLeft) { + pLeft = &g_pTris[iLeft]; + } else { + pLeft = NULL; + } - terraTri_t* pRight; - if (iRight) { - pRight = &g_pTris[iRight]; - } else { - pRight = NULL; - } + terraTri_t *pRight; + if (iRight) { + pRight = &g_pTris[iRight]; + } else { + pRight = NULL; + } - int iNextLod = pSplit->lod + 1; - int index = pSplit->index; - varnodeUnpacked_t* varnode = &pSplit->varnode[index]; + int iNextLod = pSplit->lod + 1; + int index = pSplit->index; + varnodeUnpacked_t *varnode = &pSplit->varnode[index]; - if (pLeft) - { - pLeft->patch = pSplit->patch; - pLeft->index = index * 2; - pLeft->varnode = varnode; - pLeft->lod = iNextLod; - pLeft->iLeft = iRight; - pLeft->iRight = iRightOfLeft; - pLeft->iBase = pSplit->iLeft; - pLeft->iPt[0] = pSplit->iPt[1]; - pLeft->iPt[1] = pSplit->iPt[2]; - pLeft->iPt[2] = iNewPt; + if (pLeft) { + pLeft->patch = pSplit->patch; + pLeft->index = index * 2; + pLeft->varnode = varnode; + pLeft->lod = iNextLod; + pLeft->iLeft = iRight; + pLeft->iRight = iRightOfLeft; + pLeft->iBase = pSplit->iLeft; + pLeft->iPt[0] = pSplit->iPt[1]; + pLeft->iPt[1] = pSplit->iPt[2]; + pLeft->iPt[2] = iNewPt; - R_ValidateHeightmapForVertex(pLeft); - pLeft->byConstChecks |= R_ConstChecksForTri(pLeft); + R_ValidateHeightmapForVertex(pLeft); + pLeft->byConstChecks |= R_ConstChecksForTri(pLeft); - g_pVert[pLeft->iPt[0]].nRef++; - g_pVert[pLeft->iPt[1]].nRef++; - g_pVert[pLeft->iPt[2]].nRef++; - g_pTris[pSplit->iParent].nSplit++; - pLeft->nSplit = 0; - } + g_pVert[pLeft->iPt[0]].nRef++; + g_pVert[pLeft->iPt[1]].nRef++; + g_pVert[pLeft->iPt[2]].nRef++; + g_pTris[pSplit->iParent].nSplit++; + pLeft->nSplit = 0; + } - if (pSplit->iLeft) - { - if (g_pTris[pSplit->iLeft].lod == iNextLod) - { - g_pTris[pSplit->iLeft].iBase = iLeft; - } - else - { - g_pTris[pSplit->iLeft].iRight = iLeft; - } - } + if (pSplit->iLeft) { + if (g_pTris[pSplit->iLeft].lod == iNextLod) { + g_pTris[pSplit->iLeft].iBase = iLeft; + } else { + g_pTris[pSplit->iLeft].iRight = iLeft; + } + } - if (pRight) - { - pRight->patch = pSplit->patch; - pRight->index = index * 2 + 1; - pRight->varnode = varnode + 1; - pRight->lod = iNextLod; - pRight->iLeft = iLeftOfRight; - pRight->iRight = iLeft; - pRight->iBase = pSplit->iRight; - pRight->iPt[0] = pSplit->iPt[2]; - pRight->iPt[1] = pSplit->iPt[0]; - pRight->iPt[2] = iNewPt; + if (pRight) { + pRight->patch = pSplit->patch; + pRight->index = index * 2 + 1; + pRight->varnode = varnode + 1; + pRight->lod = iNextLod; + pRight->iLeft = iLeftOfRight; + pRight->iRight = iLeft; + pRight->iBase = pSplit->iRight; + pRight->iPt[0] = pSplit->iPt[2]; + pRight->iPt[1] = pSplit->iPt[0]; + pRight->iPt[2] = iNewPt; - R_ValidateHeightmapForVertex(pRight); - pRight->byConstChecks |= R_ConstChecksForTri(pRight); + R_ValidateHeightmapForVertex(pRight); + pRight->byConstChecks |= R_ConstChecksForTri(pRight); - g_pVert[pRight->iPt[0]].nRef++; - g_pVert[pRight->iPt[1]].nRef++; - g_pVert[pRight->iPt[2]].nRef++; - g_pTris[pSplit->iParent].nSplit++; - pRight->nSplit = 0; - } + g_pVert[pRight->iPt[0]].nRef++; + g_pVert[pRight->iPt[1]].nRef++; + g_pVert[pRight->iPt[2]].nRef++; + g_pTris[pSplit->iParent].nSplit++; + pRight->nSplit = 0; + } - if (pSplit->iRight) - { - if (g_pTris[pSplit->iRight].lod == iNextLod) - { - g_pTris[pSplit->iRight].iBase = iRight; - } - else - { - g_pTris[pSplit->iRight].iLeft = iRight; - } - } + if (pSplit->iRight) { + if (g_pTris[pSplit->iRight].lod == iNextLod) { + g_pTris[pSplit->iRight].iBase = iRight; + } else { + g_pTris[pSplit->iRight].iLeft = iRight; + } + } } static void R_ForceSplit(terraInt iTri) { - terraTri_t* pTri = &g_pTris[iTri]; + terraTri_t *pTri = &g_pTris[iTri]; - g_nSplit++; + g_nSplit++; - terraInt iBase = pTri->iBase; - terraTri_t* pBase = &g_pTris[iBase]; - if (iBase && pBase->lod != pTri->lod) - { + terraInt iBase = pTri->iBase; + terraTri_t *pBase = &g_pTris[iBase]; + if (iBase && pBase->lod != pTri->lod) { assert(g_pTris[pTri->iBase].iBase != iTri); assert(g_tri.nFree >= 8); - R_ForceSplit(iBase); + R_ForceSplit(iBase); - assert(g_tri.nFree >= 4); + assert(g_tri.nFree >= 4); - iBase = pTri->iBase; - pBase = &g_pTris[iBase]; - } + iBase = pTri->iBase; + pBase = &g_pTris[iBase]; + } - uint8_t flags = pTri->varnode->s.flags; + uint8_t flags = pTri->varnode->s.flags; - terraInt iTriLeft = R_AllocateTri(pTri->patch, (flags & 2)); - terraInt iTriRight = R_AllocateTri(pTri->patch, (flags & 1)); + terraInt iTriLeft = R_AllocateTri(pTri->patch, (flags & 2)); + terraInt iTriRight = R_AllocateTri(pTri->patch, (flags & 1)); - terraInt iNewPt = R_AllocateVert(pTri->patch); - R_InterpolateVert(pTri, &g_pVert[iNewPt]); + terraInt iNewPt = R_AllocateVert(pTri->patch); + R_InterpolateVert(pTri, &g_pVert[iNewPt]); - g_pVert[iNewPt].fVariance = pTri->varnode->fVariance; + g_pVert[iNewPt].fVariance = pTri->varnode->fVariance; - terraInt iBaseLeft = 0; - terraInt iBaseRight = 0; + terraInt iBaseLeft = 0; + terraInt iBaseRight = 0; - if (iBase) - { - uint8_t flags2 = pBase->varnode->s.flags; - flags |= flags2; + if (iBase) { + uint8_t flags2 = pBase->varnode->s.flags; + flags |= flags2; - iBaseLeft = R_AllocateTri(pBase->patch, (flags2 & 2)); - iBaseRight = R_AllocateTri(pBase->patch, (flags2 & 1)); + iBaseLeft = R_AllocateTri(pBase->patch, (flags2 & 2)); + iBaseRight = R_AllocateTri(pBase->patch, (flags2 & 1)); - terraInt iNewBasePt = iNewPt; - if (pBase->patch != pTri->patch) - { - iNewBasePt = R_AllocateVert(pBase->patch); - terrainVert_t* pVert = &g_pVert[iNewBasePt]; - R_InterpolateVert(pBase, pVert); + terraInt iNewBasePt = iNewPt; + if (pBase->patch != pTri->patch) { + iNewBasePt = R_AllocateVert(pBase->patch); + terrainVert_t *pVert = &g_pVert[iNewBasePt]; + R_InterpolateVert(pBase, pVert); - pVert->fVariance = g_pVert[iNewPt].fVariance; - if (flags & 8) - { - pVert->fHgtAvg += pVert->fHgtAdd; - pVert->fHgtAdd = 0.0; - pVert->fVariance = 0.0; - pVert->xyz[2] = pVert->fHgtAvg; - } - } + pVert->fVariance = g_pVert[iNewPt].fVariance; + if (flags & 8) { + pVert->fHgtAvg += pVert->fHgtAdd; + pVert->fHgtAdd = 0.0; + pVert->fVariance = 0.0; + pVert->xyz[2] = pVert->fHgtAvg; + } + } - R_SplitTri(iBase, iNewBasePt, iBaseLeft, iBaseRight, iTriRight, iTriLeft); + R_SplitTri(iBase, iNewBasePt, iBaseLeft, iBaseRight, iTriRight, iTriLeft); - pBase->iLeftChild = iBaseLeft; - pBase->iRightChild = iBaseRight; - g_pTris[iBaseLeft].iParent = iBase; - g_pTris[iBaseRight].iParent = iBase; - R_DemoteInAncestry(pBase->patch, iBase); - } + pBase->iLeftChild = iBaseLeft; + pBase->iRightChild = iBaseRight; + g_pTris[iBaseLeft].iParent = iBase; + g_pTris[iBaseRight].iParent = iBase; + R_DemoteInAncestry(pBase->patch, iBase); + } - if (flags & 8) - { - terrainVert_t* pVert = &g_pVert[iNewPt]; - pVert->fHgtAvg += pVert->fHgtAdd; - pVert->fHgtAdd = 0.0; - pVert->fVariance = 0.0; - pVert->xyz[2] = pVert->fHgtAvg; - } + if (flags & 8) { + terrainVert_t *pVert = &g_pVert[iNewPt]; + pVert->fHgtAvg += pVert->fHgtAdd; + pVert->fHgtAdd = 0.0; + pVert->fVariance = 0.0; + pVert->xyz[2] = pVert->fHgtAvg; + } - R_SplitTri(iTri, iNewPt, iTriLeft, iTriRight, iBaseRight, iBaseLeft); + R_SplitTri(iTri, iNewPt, iTriLeft, iTriRight, iBaseRight, iBaseLeft); - pTri->iLeftChild = iTriLeft; - pTri->iRightChild = iTriRight; - g_pTris[iTriLeft].iParent = iTri; - g_pTris[iTriRight].iParent = iTri; - R_DemoteInAncestry(pTri->patch, iTri); + pTri->iLeftChild = iTriLeft; + pTri->iRightChild = iTriRight; + g_pTris[iTriLeft].iParent = iTri; + g_pTris[iTriRight].iParent = iTri; + R_DemoteInAncestry(pTri->patch, iTri); } static void R_ForceMerge(terraInt iTri) { - terraTri_t* pTri = &g_pTris[iTri]; - cTerraPatchUnpacked_t* patch = pTri->patch; - terraInt iPrev = pTri->iPrev; - terraInt iNext = pTri->iNext; + terraTri_t *pTri = &g_pTris[iTri]; + cTerraPatchUnpacked_t *patch = pTri->patch; + terraInt iPrev = pTri->iPrev; + terraInt iNext = pTri->iNext; - g_nMerge++; + g_nMerge++; - if (pTri->iLeftChild) - { - terraInt iLeft = g_pTris[pTri->iLeftChild].iBase; + if (pTri->iLeftChild) { + terraInt iLeft = g_pTris[pTri->iLeftChild].iBase; - pTri->iLeft = iLeft; - if (iLeft) - { - if (g_pTris[iLeft].lod == pTri->lod) - { - g_pTris[iLeft].iRight = iTri; - } - else - { - g_pTris[iLeft].iBase = iTri; - } - } + pTri->iLeft = iLeft; + if (iLeft) { + if (g_pTris[iLeft].lod == pTri->lod) { + g_pTris[iLeft].iRight = iTri; + } else { + g_pTris[iLeft].iBase = iTri; + } + } - R_ReleaseTri(pTri->patch, pTri->iLeftChild); + R_ReleaseTri(pTri->patch, pTri->iLeftChild); - pTri->iLeftChild = 0; - g_pTris[pTri->iParent].nSplit--; - } + pTri->iLeftChild = 0; + g_pTris[pTri->iParent].nSplit--; + } - if (pTri->iRightChild) - { - terraInt iRight = g_pTris[pTri->iRightChild].iBase; + if (pTri->iRightChild) { + terraInt iRight = g_pTris[pTri->iRightChild].iBase; - pTri->iRight = iRight; - if (iRight) - { - if (g_pTris[iRight].lod == pTri->lod) - { - g_pTris[iRight].iLeft = iTri; - } - else - { - g_pTris[iRight].iBase = iTri; - } - } + pTri->iRight = iRight; + if (iRight) { + if (g_pTris[iRight].lod == pTri->lod) { + g_pTris[iRight].iLeft = iTri; + } else { + g_pTris[iRight].iBase = iTri; + } + } - R_ReleaseTri(pTri->patch, pTri->iRightChild); + R_ReleaseTri(pTri->patch, pTri->iRightChild); - pTri->iLeftChild = 0; - g_pTris[pTri->iParent].nSplit--; - } + pTri->iLeftChild = 0; + g_pTris[pTri->iParent].nSplit--; + } - g_pTris[iPrev].iNext = iNext; - g_pTris[iNext].iPrev = iPrev; + g_pTris[iPrev].iNext = iNext; + g_pTris[iNext].iPrev = iPrev; - if (g_tri.iCur == iTri) - { - g_tri.iCur = iNext; - } + if (g_tri.iCur == iTri) { + g_tri.iCur = iNext; + } - patch->drawinfo.nTris++; - if (patch->drawinfo.iMergeHead == iTri) - { - patch->drawinfo.iMergeHead = iNext; - } + patch->drawinfo.nTris++; + if (patch->drawinfo.iMergeHead == iTri) { + patch->drawinfo.iMergeHead = iNext; + } - g_pTris[iTri].iPrev = patch->drawinfo.iTriTail; - g_pTris[iTri].iNext = 0; + g_pTris[iTri].iPrev = patch->drawinfo.iTriTail; + g_pTris[iTri].iNext = 0; - g_pTris[patch->drawinfo.iTriTail].iNext = iTri; + g_pTris[patch->drawinfo.iTriTail].iNext = iTri; - patch->drawinfo.iTriTail = iTri; - if (!patch->drawinfo.iTriHead) - { - patch->drawinfo.iTriHead = iTri; - } + patch->drawinfo.iTriTail = iTri; + if (!patch->drawinfo.iTriHead) { + patch->drawinfo.iTriHead = iTri; + } } -static int R_TerraTriNeighbor(cTerraPatchUnpacked_t* terraPatches, int iPatch, int dir) +static int R_TerraTriNeighbor(cTerraPatchUnpacked_t *terraPatches, int iPatch, int dir) { - int iNeighbor; + int iNeighbor; - if (iPatch < 0) { - return 0; - } + if (iPatch < 0) { + return 0; + } iNeighbor = 2 * iPatch + 1; @@ -598,756 +557,654 @@ static int R_TerraTriNeighbor(cTerraPatchUnpacked_t* terraPatches, int iPatch, i case 0: return iNeighbor; case 1: - if (terraPatches[iPatch].flags & 0x80) - { + if (terraPatches[iPatch].flags & 0x80) { return iNeighbor; - } - else - { + } else { return iNeighbor + 1; } break; case 2: return iNeighbor + 1; case 3: - if (terraPatches[iPatch].flags & 0x80) - { + if (terraPatches[iPatch].flags & 0x80) { return iNeighbor + 1; - } - else - { + } else { return iNeighbor; } break; } - return 0; + return 0; } static void R_PreTessellateTerrain() { - size_t numTerrainPatches = tr.world->numTerraPatches; + size_t numTerrainPatches = tr.world->numTerraPatches; - if (!numTerrainPatches) { - return; - } + if (!numTerrainPatches) { + return; + } - R_SyncRenderThread(); + R_SyncRenderThread(); - if (ter_maxtris->integer < 4 * numTerrainPatches) { - Cvar_SetValue("ter_maxtris", 4 * numTerrainPatches); - } - else if (ter_maxtris->integer > 65535) { - Cvar_SetValue("ter_maxtris", 65535); - } + if (ter_maxtris->integer < 4 * numTerrainPatches) { + Cvar_SetValue("ter_maxtris", 4 * numTerrainPatches); + } else if (ter_maxtris->integer > 65535) { + Cvar_SetValue("ter_maxtris", 65535); + } - Com_DPrintf("Using ter_maxtris = %d\n", ter_maxtris->integer); + Com_DPrintf("Using ter_maxtris = %d\n", ter_maxtris->integer); - g_nTris = ter_maxtris->integer * 2 + 1; - g_nVerts = ter_maxtris->integer + 1; - g_pTris = ri.Hunk_Alloc(g_nTris * sizeof(terraTri_t), h_dontcare); - g_pVert = ri.Hunk_Alloc(g_nVerts * sizeof(terrainVert_t), h_dontcare); + g_nTris = ter_maxtris->integer * 2 + 1; + g_nVerts = ter_maxtris->integer + 1; + g_pTris = ri.Hunk_Alloc(g_nTris * sizeof(terraTri_t), h_dontcare); + g_pVert = ri.Hunk_Alloc(g_nVerts * sizeof(terrainVert_t), h_dontcare); - // Init triangles & vertices - R_TerrainHeapInit(); - R_TerrainPatchesInit(); + // Init triangles & vertices + R_TerrainHeapInit(); + R_TerrainPatchesInit(); - for (size_t i = 0; i < numTerrainPatches; i++) - { - cTerraPatchUnpacked_t* patch = &tr.world->terraPatches[i]; + for (size_t i = 0; i < numTerrainPatches; i++) { + cTerraPatchUnpacked_t *patch = &tr.world->terraPatches[i]; - patch->drawinfo.surfaceType = SF_TERRAIN_PATCH; - patch->drawinfo.nTris = 0; - patch->drawinfo.nVerts = 0; - patch->drawinfo.iTriHead = 0; - patch->drawinfo.iTriTail = 0; - patch->drawinfo.iVertHead = 0; + patch->drawinfo.surfaceType = SF_TERRAIN_PATCH; + patch->drawinfo.nTris = 0; + patch->drawinfo.nVerts = 0; + patch->drawinfo.iTriHead = 0; + patch->drawinfo.iTriTail = 0; + patch->drawinfo.iVertHead = 0; - float sMin, tMin; + float sMin, tMin; - if (patch->texCoord[0][0][0] < patch->texCoord[0][1][0]) - { - sMin = patch->texCoord[0][0][0]; - } - else - { - sMin = patch->texCoord[0][1][0]; - } + if (patch->texCoord[0][0][0] < patch->texCoord[0][1][0]) { + sMin = patch->texCoord[0][0][0]; + } else { + sMin = patch->texCoord[0][1][0]; + } - float sMin2; - if (patch->texCoord[1][0][0] < patch->texCoord[1][1][0]) - { - sMin2 = patch->texCoord[1][0][0]; - } - else - { - sMin2 = patch->texCoord[1][1][0]; - } + float sMin2; + if (patch->texCoord[1][0][0] < patch->texCoord[1][1][0]) { + sMin2 = patch->texCoord[1][0][0]; + } else { + sMin2 = patch->texCoord[1][1][0]; + } - if (sMin >= sMin2) - { - if (patch->texCoord[1][0][0] >= patch->texCoord[1][1][0]) - { - sMin = floor(patch->texCoord[1][1][0]); - } - else - { - sMin = floor(patch->texCoord[1][0][0]); - } - } - else if (patch->texCoord[0][0][0] >= patch->texCoord[0][1][0]) - { - sMin = floor(patch->texCoord[0][1][0]); - } - else - { - sMin = floor(patch->texCoord[0][0][0]); - } + if (sMin >= sMin2) { + if (patch->texCoord[1][0][0] >= patch->texCoord[1][1][0]) { + sMin = floor(patch->texCoord[1][1][0]); + } else { + sMin = floor(patch->texCoord[1][0][0]); + } + } else if (patch->texCoord[0][0][0] >= patch->texCoord[0][1][0]) { + sMin = floor(patch->texCoord[0][1][0]); + } else { + sMin = floor(patch->texCoord[0][0][0]); + } - if (patch->texCoord[0][0][1] < patch->texCoord[0][1][1]) - { - tMin = patch->texCoord[0][0][1]; - } - else - { - tMin = patch->texCoord[0][1][1]; - } + if (patch->texCoord[0][0][1] < patch->texCoord[0][1][1]) { + tMin = patch->texCoord[0][0][1]; + } else { + tMin = patch->texCoord[0][1][1]; + } - float tMin2; - if (patch->texCoord[1][0][1] < patch->texCoord[1][1][1]) - { - tMin2 = patch->texCoord[1][0][1]; - } - else - { - tMin2 = patch->texCoord[1][1][1]; - } + float tMin2; + if (patch->texCoord[1][0][1] < patch->texCoord[1][1][1]) { + tMin2 = patch->texCoord[1][0][1]; + } else { + tMin2 = patch->texCoord[1][1][1]; + } - if (tMin >= tMin2) - { - if (patch->texCoord[1][0][1] >= patch->texCoord[1][1][1]) - { - tMin = floor(patch->texCoord[1][1][1]); - } - else - { - tMin = floor(patch->texCoord[1][0][1]); - } - } - else if (patch->texCoord[0][0][1] >= patch->texCoord[0][1][1]) - { - tMin = floor(patch->texCoord[0][1][1]); - } - else - { - tMin = floor(patch->texCoord[0][0][1]); - } + if (tMin >= tMin2) { + if (patch->texCoord[1][0][1] >= patch->texCoord[1][1][1]) { + tMin = floor(patch->texCoord[1][1][1]); + } else { + tMin = floor(patch->texCoord[1][0][1]); + } + } else if (patch->texCoord[0][0][1] >= patch->texCoord[0][1][1]) { + tMin = floor(patch->texCoord[0][1][1]); + } else { + tMin = floor(patch->texCoord[0][0][1]); + } - const float s00 = patch->texCoord[0][0][0] - sMin; - const float s01 = patch->texCoord[0][1][0] - sMin; - const float s10 = patch->texCoord[1][0][0] - sMin; - const float s11 = patch->texCoord[1][1][0] - sMin; + const float s00 = patch->texCoord[0][0][0] - sMin; + const float s01 = patch->texCoord[0][1][0] - sMin; + const float s10 = patch->texCoord[1][0][0] - sMin; + const float s11 = patch->texCoord[1][1][0] - sMin; - const float t00 = patch->texCoord[0][0][1] - tMin; - const float t01 = patch->texCoord[0][1][1] - tMin; - const float t10 = patch->texCoord[1][0][1] - tMin; - const float t11 = patch->texCoord[1][1][1] - tMin; + const float t00 = patch->texCoord[0][0][1] - tMin; + const float t01 = patch->texCoord[0][1][1] - tMin; + const float t10 = patch->texCoord[1][0][1] - tMin; + const float t11 = patch->texCoord[1][1][1] - tMin; - const float lmapSize = (float)(patch->drawinfo.lmapSize - 1) / TERRAIN_LIGHTMAP_SIZE; - const float ls = patch->s + lmapSize; - const float lt = patch->t + lmapSize; + const float lmapSize = (float)(patch->drawinfo.lmapSize - 1) / TERRAIN_LIGHTMAP_SIZE; + const float ls = patch->s + lmapSize; + const float lt = patch->t + lmapSize; - terraInt iTri0 = R_AllocateTri(patch, qfalse); - terraInt iTri1 = R_AllocateTri(patch, qfalse); - terraInt i00 = R_AllocateVert(patch); - terraInt i01 = R_AllocateVert(patch); - terraInt i10 = R_AllocateVert(patch); - terraInt i11 = R_AllocateVert(patch); + terraInt iTri0 = R_AllocateTri(patch, qfalse); + terraInt iTri1 = R_AllocateTri(patch, qfalse); + terraInt i00 = R_AllocateVert(patch); + terraInt i01 = R_AllocateVert(patch); + terraInt i10 = R_AllocateVert(patch); + terraInt i11 = R_AllocateVert(patch); - terrainVert_t* pVert; - pVert = &g_pVert[i00]; - pVert->xyz[0] = patch->x0; - pVert->xyz[1] = patch->y0; - pVert->xyz[2] = (float)(patch->heightmap[0] * 2) + patch->z0; - pVert->pHgt = &patch->heightmap[0]; - pVert->fHgtAvg = pVert->xyz[2]; - pVert->texCoords[0][0] = s00; - pVert->texCoords[0][1] = t00; - pVert->texCoords[1][0] = patch->s; - pVert->texCoords[1][1] = patch->t; - pVert->fVariance = 0.0f; - pVert->nRef = 4; + terrainVert_t *pVert; + pVert = &g_pVert[i00]; + pVert->xyz[0] = patch->x0; + pVert->xyz[1] = patch->y0; + pVert->xyz[2] = (float)(patch->heightmap[0] * 2) + patch->z0; + pVert->pHgt = &patch->heightmap[0]; + pVert->fHgtAvg = pVert->xyz[2]; + pVert->texCoords[0][0] = s00; + pVert->texCoords[0][1] = t00; + pVert->texCoords[1][0] = patch->s; + pVert->texCoords[1][1] = patch->t; + pVert->fVariance = 0.0f; + pVert->nRef = 4; - pVert = &g_pVert[i01]; - pVert->xyz[0] = patch->x0; - pVert->xyz[1] = patch->y0 + 512.0f; - pVert->xyz[2] = (float)(patch->heightmap[72] * 2) + patch->z0; - pVert->pHgt = &patch->heightmap[72]; - pVert->fHgtAvg = pVert->xyz[2]; - pVert->texCoords[0][0] = s01; - pVert->texCoords[0][1] = t01; - pVert->texCoords[1][0] = patch->s; - pVert->texCoords[1][1] = lt; - pVert->fVariance = 0.0f; - pVert->nRef = 4; + pVert = &g_pVert[i01]; + pVert->xyz[0] = patch->x0; + pVert->xyz[1] = patch->y0 + 512.0f; + pVert->xyz[2] = (float)(patch->heightmap[72] * 2) + patch->z0; + pVert->pHgt = &patch->heightmap[72]; + pVert->fHgtAvg = pVert->xyz[2]; + pVert->texCoords[0][0] = s01; + pVert->texCoords[0][1] = t01; + pVert->texCoords[1][0] = patch->s; + pVert->texCoords[1][1] = lt; + pVert->fVariance = 0.0f; + pVert->nRef = 4; - pVert = &g_pVert[i10]; - pVert->xyz[0] = patch->x0 + 512.0f; - pVert->xyz[1] = patch->y0; - pVert->xyz[2] = (float)(patch->heightmap[8] * 2) + patch->z0; - pVert->pHgt = &patch->heightmap[8]; - pVert->fHgtAvg = pVert->xyz[2]; - pVert->texCoords[0][0] = s10; - pVert->texCoords[0][1] = t10; - pVert->texCoords[1][0] = ls; - pVert->texCoords[1][1] = patch->t; - pVert->fVariance = 0.0f; - pVert->nRef = 4; + pVert = &g_pVert[i10]; + pVert->xyz[0] = patch->x0 + 512.0f; + pVert->xyz[1] = patch->y0; + pVert->xyz[2] = (float)(patch->heightmap[8] * 2) + patch->z0; + pVert->pHgt = &patch->heightmap[8]; + pVert->fHgtAvg = pVert->xyz[2]; + pVert->texCoords[0][0] = s10; + pVert->texCoords[0][1] = t10; + pVert->texCoords[1][0] = ls; + pVert->texCoords[1][1] = patch->t; + pVert->fVariance = 0.0f; + pVert->nRef = 4; - pVert = &g_pVert[i11]; - pVert->xyz[0] = patch->x0 + 512.0f; - pVert->xyz[1] = patch->y0 + 512.0f; - pVert->xyz[2] = (float)(patch->heightmap[80] * 2) + patch->z0; - pVert->pHgt = &patch->heightmap[80]; - pVert->fHgtAvg = pVert->xyz[2]; - pVert->texCoords[0][0] = s11; - pVert->texCoords[0][1] = t11; - pVert->texCoords[1][0] = ls; - pVert->texCoords[1][1] = lt; - pVert->fVariance = 0.0f; - pVert->nRef = 4; + pVert = &g_pVert[i11]; + pVert->xyz[0] = patch->x0 + 512.0f; + pVert->xyz[1] = patch->y0 + 512.0f; + pVert->xyz[2] = (float)(patch->heightmap[80] * 2) + patch->z0; + pVert->pHgt = &patch->heightmap[80]; + pVert->fHgtAvg = pVert->xyz[2]; + pVert->texCoords[0][0] = s11; + pVert->texCoords[0][1] = t11; + pVert->texCoords[1][0] = ls; + pVert->texCoords[1][1] = lt; + pVert->fVariance = 0.0f; + pVert->nRef = 4; - terraTri_t* pTri = &g_pTris[iTri0]; - pTri->patch = patch; - pTri->varnode = &patch->varTree[0][0]; - pTri->index = 1; - pTri->lod = 0; - pTri->byConstChecks |= R_ConstChecksForTri(pTri); + terraTri_t *pTri = &g_pTris[iTri0]; + pTri->patch = patch; + pTri->varnode = &patch->varTree[0][0]; + pTri->index = 1; + pTri->lod = 0; + pTri->byConstChecks |= R_ConstChecksForTri(pTri); - pTri->iBase = iTri1; - if ((patch->flags & 0x80u) == 0) - { - pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iWest, 1); - pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iNorth, 2); - if (patch->flags & 0x40) - { - pTri->iPt[0] = i00; - pTri->iPt[1] = i11; - } - else - { - pTri->iPt[0] = i11; - pTri->iPt[1] = i00; - } - pTri->iPt[2] = i01; - } - else - { - pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iNorth, 2); - pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iEast, 3); - if (patch->flags & 0x40) - { - pTri->iPt[0] = i01; - pTri->iPt[1] = i10; - } - else - { - pTri->iPt[0] = i10; - pTri->iPt[1] = i01; - } - pTri->iPt[2] = i11; - } + pTri->iBase = iTri1; + if ((patch->flags & 0x80u) == 0) { + pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iWest, 1); + pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iNorth, 2); + if (patch->flags & 0x40) { + pTri->iPt[0] = i00; + pTri->iPt[1] = i11; + } else { + pTri->iPt[0] = i11; + pTri->iPt[1] = i00; + } + pTri->iPt[2] = i01; + } else { + pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iNorth, 2); + pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iEast, 3); + if (patch->flags & 0x40) { + pTri->iPt[0] = i01; + pTri->iPt[1] = i10; + } else { + pTri->iPt[0] = i10; + pTri->iPt[1] = i01; + } + pTri->iPt[2] = i11; + } - R_ValidateHeightmapForVertex(pTri); + R_ValidateHeightmapForVertex(pTri); - pTri = &g_pTris[iTri1]; - pTri->patch = patch; - pTri->varnode = &patch->varTree[1][0]; - pTri->index = 1; - pTri->lod = 0; - pTri->byConstChecks |= R_ConstChecksForTri(pTri); + pTri = &g_pTris[iTri1]; + pTri->patch = patch; + pTri->varnode = &patch->varTree[1][0]; + pTri->index = 1; + pTri->lod = 0; + pTri->byConstChecks |= R_ConstChecksForTri(pTri); - pTri->iBase = iTri0; - if ((patch->flags & 0x80u) == 0) - { - pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iEast, 3); - pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iSouth, 0); - if (patch->flags & 0x40) - { - pTri->iPt[0] = i11; - pTri->iPt[1] = i00; - } - else - { - pTri->iPt[0] = i00; - pTri->iPt[1] = i11; - } - pTri->iPt[2] = i10; - } - else - { - pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iSouth, 0); - pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iWest, 1); - if (patch->flags & 0x40) - { - pTri->iPt[0] = i10; - pTri->iPt[1] = i01; - } - else - { - pTri->iPt[0] = i01; - pTri->iPt[1] = i10; - } - pTri->iPt[2] = i00; - } + pTri->iBase = iTri0; + if ((patch->flags & 0x80u) == 0) { + pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iEast, 3); + pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iSouth, 0); + if (patch->flags & 0x40) { + pTri->iPt[0] = i11; + pTri->iPt[1] = i00; + } else { + pTri->iPt[0] = i00; + pTri->iPt[1] = i11; + } + pTri->iPt[2] = i10; + } else { + pTri->iLeft = R_TerraTriNeighbor(tr.world->terraPatches, patch->iSouth, 0); + pTri->iRight = R_TerraTriNeighbor(tr.world->terraPatches, patch->iWest, 1); + if (patch->flags & 0x40) { + pTri->iPt[0] = i10; + pTri->iPt[1] = i01; + } else { + pTri->iPt[0] = i01; + pTri->iPt[1] = i10; + } + pTri->iPt[2] = i00; + } - R_ValidateHeightmapForVertex(pTri); - } + R_ValidateHeightmapForVertex(pTri); + } } -static qboolean R_NeedSplitTri(terraTri_t * pTri) +static qboolean R_NeedSplitTri(terraTri_t *pTri) { - uint8_t byConstChecks = pTri->byConstChecks; - if (byConstChecks & 2) { - return byConstChecks & 1; - } + uint8_t byConstChecks = pTri->byConstChecks; + if (byConstChecks & 2) { + return byConstChecks & 1; + } - if (pTri->uiDistRecalc > g_uiTerDist) { - return qfalse; - } + if (pTri->uiDistRecalc > g_uiTerDist) { + return qfalse; + } - float fRatio = ((g_pVert[pTri->iPt[0]].xyz[0] + g_pVert[pTri->iPt[1]].xyz[0]) * g_vViewVector[0] - + (g_pVert[pTri->iPt[0]].xyz[1] + g_pVert[pTri->iPt[1]].xyz[1]) * g_vViewVector[1]) - * 0.5 - + g_vViewVector[2] - - pTri->varnode->fVariance * g_fCheck; + float fRatio = ((g_pVert[pTri->iPt[0]].xyz[0] + g_pVert[pTri->iPt[1]].xyz[0]) * g_vViewVector[0] + + (g_pVert[pTri->iPt[0]].xyz[1] + g_pVert[pTri->iPt[1]].xyz[1]) * g_vViewVector[1]) + * 0.5 + + g_vViewVector[2] - pTri->varnode->fVariance * g_fCheck; - if (fRatio > 0) - { - pTri->uiDistRecalc = floor(fRatio) + g_uiTerDist; - return qfalse; - } + if (fRatio > 0) { + pTri->uiDistRecalc = floor(fRatio) + g_uiTerDist; + return qfalse; + } - return qtrue; + return qtrue; } -static void R_CalcVertMorphHeight(terrainVert_t* pVert) +static void R_CalcVertMorphHeight(terrainVert_t *pVert) { - float dot; + float dot; - pVert->xyz[2] = pVert->fHgtAvg; - pVert->uiDistRecalc = g_uiTerDist + 1; - dot = (pVert->fVariance * g_fCheck) - (g_vViewVector[0] * pVert->xyz[0] + g_vViewVector[1] * pVert->xyz[1] + g_vViewVector[2]); + pVert->xyz[2] = pVert->fHgtAvg; + pVert->uiDistRecalc = g_uiTerDist + 1; + dot = (pVert->fVariance * g_fCheck) + - (g_vViewVector[0] * pVert->xyz[0] + g_vViewVector[1] * pVert->xyz[1] + g_vViewVector[2]); - if (dot > 0.0) - { - float calc = dot / 400.0; + if (dot > 0.0) { + float calc = dot / 400.0; - if (calc > 1.0) - { - pVert->uiDistRecalc = (unsigned int)((g_uiTerDist - 400) + floor(dot)); - calc = 1.0; - } + if (calc > 1.0) { + pVert->uiDistRecalc = (unsigned int)((g_uiTerDist - 400) + floor(dot)); + calc = 1.0; + } - pVert->xyz[2] += pVert->fHgtAdd * calc; - } - else - { - pVert->uiDistRecalc = g_uiTerDist - (int)ceil(dot); - } + pVert->xyz[2] += pVert->fHgtAdd * calc; + } else { + pVert->uiDistRecalc = g_uiTerDist - (int)ceil(dot); + } } -static void R_UpdateVertMorphHeight(terrainVert_t* pVert) +static void R_UpdateVertMorphHeight(terrainVert_t *pVert) { - if (pVert->uiDistRecalc <= g_uiTerDist) { - R_CalcVertMorphHeight(pVert); - } + if (pVert->uiDistRecalc <= g_uiTerDist) { + R_CalcVertMorphHeight(pVert); + } } static void R_DoTriSplitting() { - cTerraPatchUnpacked_t* patch; + cTerraPatchUnpacked_t *patch; - for (patch = tr.world->activeTerraPatches; patch; patch = patch->pNextActive) - { - if (patch->uiDistRecalc > g_uiTerDist) { - continue; - } + for (patch = tr.world->activeTerraPatches; patch; patch = patch->pNextActive) { + if (patch->uiDistRecalc > g_uiTerDist) { + continue; + } - patch->uiDistRecalc = -1; - g_tri.iCur = patch->drawinfo.iTriHead; - while (g_tri.iCur != 0) - { - terraTri_t* pTri = &g_pTris[g_tri.iCur]; + patch->uiDistRecalc = -1; + g_tri.iCur = patch->drawinfo.iTriHead; + while (g_tri.iCur != 0) { + terraTri_t *pTri = &g_pTris[g_tri.iCur]; - if (R_NeedSplitTri(pTri)) - { - // - // make sure there are sufficient number of tris - // - if (g_tri.nFree < 14 || g_vert.nFree < 14) { - Com_DPrintf("WARNING: aborting terrain tessellation -- insufficient tris\n"); - return; - } + if (R_NeedSplitTri(pTri)) { + // + // make sure there are sufficient number of tris + // + if (g_tri.nFree < 14 || g_vert.nFree < 14) { + Com_DPrintf("WARNING: aborting terrain tessellation -- insufficient tris\n"); + return; + } - patch->uiDistRecalc = 0; - R_ForceSplit(g_tri.iCur); + patch->uiDistRecalc = 0; + R_ForceSplit(g_tri.iCur); - if (&g_pTris[g_tri.iCur] == pTri) - { - g_tri.iCur = g_pTris[g_tri.iCur].iNext; - } - } - else - { - if ((pTri->byConstChecks & 3) != 2) - { - if (patch->uiDistRecalc > pTri->uiDistRecalc) - { - patch->uiDistRecalc = pTri->uiDistRecalc; - } - } + if (&g_pTris[g_tri.iCur] == pTri) { + g_tri.iCur = g_pTris[g_tri.iCur].iNext; + } + } else { + if ((pTri->byConstChecks & 3) != 2) { + if (patch->uiDistRecalc > pTri->uiDistRecalc) { + patch->uiDistRecalc = pTri->uiDistRecalc; + } + } - g_tri.iCur = g_pTris[g_tri.iCur].iNext; - } - } - } + g_tri.iCur = g_pTris[g_tri.iCur].iNext; + } + } + } } static void R_DoGeomorphs() { - for (size_t n = 0; n < tr.world->numTerraPatches; n++) - { - cTerraPatchUnpacked_t* patch = &tr.world->terraPatches[n]; + for (size_t n = 0; n < tr.world->numTerraPatches; n++) { + cTerraPatchUnpacked_t *patch = &tr.world->terraPatches[n]; - g_vert.iCur = patch->drawinfo.iVertHead; + g_vert.iCur = patch->drawinfo.iVertHead; - if (patch->visCountDraw == g_terVisCount) - { - if (patch->byDirty) - { - while (g_vert.iCur) - { - terrainVert_t* pVert = &g_pVert[g_vert.iCur]; - R_CalcVertMorphHeight(pVert); - g_vert.iCur = pVert->iNext; - } + if (patch->visCountDraw == g_terVisCount) { + if (patch->byDirty) { + while (g_vert.iCur) { + terrainVert_t *pVert = &g_pVert[g_vert.iCur]; + R_CalcVertMorphHeight(pVert); + g_vert.iCur = pVert->iNext; + } - patch->byDirty = qfalse; - } - else - { - while (g_vert.iCur) - { - terrainVert_t* pVert = &g_pVert[g_vert.iCur]; - R_UpdateVertMorphHeight(pVert); - g_vert.iCur = pVert->iNext; - } - } - } - else - { - if (!patch->byDirty) - { - patch->byDirty = qtrue; - while (g_vert.iCur) - { - terrainVert_t* pVert = &g_pVert[g_vert.iCur]; - pVert->xyz[2] = pVert->fHgtAvg + pVert->fHgtAdd; - g_vert.iCur = pVert->iNext; - } - } - } - } + patch->byDirty = qfalse; + } else { + while (g_vert.iCur) { + terrainVert_t *pVert = &g_pVert[g_vert.iCur]; + R_UpdateVertMorphHeight(pVert); + g_vert.iCur = pVert->iNext; + } + } + } else { + if (!patch->byDirty) { + patch->byDirty = qtrue; + while (g_vert.iCur) { + terrainVert_t *pVert = &g_pVert[g_vert.iCur]; + pVert->xyz[2] = pVert->fHgtAvg + pVert->fHgtAdd; + g_vert.iCur = pVert->iNext; + } + } + } + } } static qboolean R_MergeInternalAggressive() { - terraTri_t* pTri = &g_pTris[g_tri.iCur]; - terraTri_t* pBase; + terraTri_t *pTri = &g_pTris[g_tri.iCur]; + terraTri_t *pBase; - if (pTri->nSplit) { - return qfalse; - } + if (pTri->nSplit) { + return qfalse; + } - if (g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].xyz[2] != g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].fHgtAvg) { - return qfalse; - } + if (g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].xyz[2] != g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].fHgtAvg) { + return qfalse; + } - if (pTri->iBase) - { - pBase = &g_pTris[pTri->iBase]; - if (pBase->nSplit) { - return qfalse; - } + if (pTri->iBase) { + pBase = &g_pTris[pTri->iBase]; + if (pBase->nSplit) { + return qfalse; + } - R_ForceMerge(pTri->iBase); - } + R_ForceMerge(pTri->iBase); + } - R_ForceMerge(g_tri.iCur); - return qtrue; + R_ForceMerge(g_tri.iCur); + return qtrue; } static qboolean R_MergeInternalCautious() { - terraTri_t* pTri; - terraTri_t* pBase; + terraTri_t *pTri; + terraTri_t *pBase; - pTri = &g_pTris[g_tri.iCur]; + pTri = &g_pTris[g_tri.iCur]; - if (pTri->nSplit) { - return qfalse; - } + if (pTri->nSplit) { + return qfalse; + } - if (pTri->varnode->s.flags & 8) { - return qfalse; - } + if (pTri->varnode->s.flags & 8) { + return qfalse; + } - if (g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].xyz[2] != g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].fHgtAvg) { - return qfalse; - } + if (g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].xyz[2] != g_pVert[g_pTris[pTri->iLeftChild].iPt[2]].fHgtAvg) { + return qfalse; + } - if (pTri->iBase) - { - pBase = &g_pTris[pTri->iBase]; - if (pBase->nSplit || (pBase->varnode->s.flags & 8)) { - return qfalse; - } + if (pTri->iBase) { + pBase = &g_pTris[pTri->iBase]; + if (pBase->nSplit || (pBase->varnode->s.flags & 8)) { + return qfalse; + } - R_ForceMerge(pTri->iBase); - } + R_ForceMerge(pTri->iBase); + } - R_ForceMerge(g_tri.iCur); - return qtrue; + R_ForceMerge(g_tri.iCur); + return qtrue; } static void R_DoTriMerging() { - int iCautiousFrame = g_terVisCount - ter_cautiousframes->integer; + int iCautiousFrame = g_terVisCount - ter_cautiousframes->integer; - for (size_t n = 0; n < tr.world->numTerraPatches; n++) - { - const cTerraPatchUnpacked_t* patch = &tr.world->terraPatches[n]; + for (size_t n = 0; n < tr.world->numTerraPatches; n++) { + const cTerraPatchUnpacked_t *patch = &tr.world->terraPatches[n]; - g_tri.iCur = patch->drawinfo.iMergeHead; - if (patch->visCountDraw >= iCautiousFrame) - { - while (g_tri.iCur) - { - if (!R_MergeInternalCautious()) - { - g_tri.iCur = g_pTris[g_tri.iCur].iNext; - } - } - } - else if(patch->visCountDraw > iCautiousFrame - 10) - { - while (g_tri.iCur) - { - if (!R_MergeInternalAggressive()) - { - g_tri.iCur = g_pTris[g_tri.iCur].iNext; - } - } - } - } + g_tri.iCur = patch->drawinfo.iMergeHead; + if (patch->visCountDraw >= iCautiousFrame) { + while (g_tri.iCur) { + if (!R_MergeInternalCautious()) { + g_tri.iCur = g_pTris[g_tri.iCur].iNext; + } + } + } else if (patch->visCountDraw > iCautiousFrame - 10) { + while (g_tri.iCur) { + if (!R_MergeInternalAggressive()) { + g_tri.iCur = g_pTris[g_tri.iCur].iNext; + } + } + } + } } void R_TessellateTerrain() { - if (glConfig.smpActive) { - R_SyncRenderThread(); - } + if (glConfig.smpActive) { + R_SyncRenderThread(); + } - R_DoTriSplitting(); - // Morph geometry according to the view - R_DoGeomorphs(); - // Merge vertices - R_DoTriMerging(); + R_DoTriSplitting(); + // Morph geometry according to the view + R_DoGeomorphs(); + // Merge vertices + R_DoTriMerging(); } void R_TerrainPrepareFrame() { - float distance; - int index; - float fFov; - float fCheck; - float fDistBound; + float distance; + int index; + float fFov; + float fCheck; + float fDistBound; - if (ter_lock->integer) { - return; - } + if (ter_lock->integer) { + return; + } - if (tr.viewParms.isPortalSky) { - return; - } + if (tr.viewParms.isPortalSky) { + return; + } - g_terVisCount++; - tr.world->activeTerraPatches = NULL; + g_terVisCount++; + tr.world->activeTerraPatches = NULL; - if (ter_error->value < 0.1) { - ri.Cvar_Set("ter_error", "0.1"); - } + if (ter_error->value < 0.1) { + ri.Cvar_Set("ter_error", "0.1"); + } - distance = 1.0; - fFov = tr.refdef.fov_x; - if (fFov < 1.0) { - fFov = 1.0; - } + distance = 1.0; + fFov = tr.refdef.fov_x; + if (fFov < 1.0) { + fFov = 1.0; + } - fCheck = 1.0 / (tan(fFov / 114.0) * ter_error->value / 320.0); - if (g_terVisCount) - { - float fFarPlane = tr.viewParms.farplane_distance; - if (fFarPlane == 0.0) { - fFarPlane = 4096.0; - } + fCheck = 1.0 / (tan(fFov / 114.0) * ter_error->value / 320.0); + if (g_terVisCount) { + float fFarPlane = tr.viewParms.farplane_distance; + if (fFarPlane == 0.0) { + fFarPlane = 4096.0; + } - fDistBound = fabs((fCheck - g_fCheck) * 510.0) - + fabs((tr.refdef.vieworg[0] - g_vTerOrg[0]) * g_vTerFwd[0]) - + fabs((tr.refdef.vieworg[1] - g_vTerOrg[1]) * g_vTerFwd[1]) - + fabs((tr.refdef.viewaxis[0][0] - g_vTerFwd[0]) * fFarPlane) - + fabs((tr.refdef.viewaxis[0][1] - g_vTerFwd[1]) * fFarPlane); + fDistBound = fabs((fCheck - g_fCheck) * 510.0) + fabs((tr.refdef.vieworg[0] - g_vTerOrg[0]) * g_vTerFwd[0]) + + fabs((tr.refdef.vieworg[1] - g_vTerOrg[1]) * g_vTerFwd[1]) + + fabs((tr.refdef.viewaxis[0][0] - g_vTerFwd[0]) * fFarPlane) + + fabs((tr.refdef.viewaxis[0][1] - g_vTerFwd[1]) * fFarPlane); - g_uiTerDist = (ceil(fDistBound) + (float)g_uiTerDist); - if (g_uiTerDist > 0xF0000000) - { - for (index = 0; index < tr.world->numTerraPatches; index++) { - tr.world->terraPatches[index].uiDistRecalc = 0; - } + g_uiTerDist = (ceil(fDistBound) + (float)g_uiTerDist); + if (g_uiTerDist > 0xF0000000) { + for (index = 0; index < tr.world->numTerraPatches; index++) { + tr.world->terraPatches[index].uiDistRecalc = 0; + } - for (index = 0; index < g_nTris; index++) { - g_pTris[index].uiDistRecalc = 0; - } + for (index = 0; index < g_nTris; index++) { + g_pTris[index].uiDistRecalc = 0; + } - for (index = 0; index < g_nVerts; index++) { - g_pVert[index].uiDistRecalc = 0; - } + for (index = 0; index < g_nVerts; index++) { + g_pVert[index].uiDistRecalc = 0; + } - g_uiTerDist = 0; - } - } - else - { - fDistBound = 0.0; - g_uiTerDist = 0; - } + g_uiTerDist = 0; + } + } else { + fDistBound = 0.0; + g_uiTerDist = 0; + } + VectorCopy2D(tr.refdef.vieworg, g_vTerOrg); + VectorCopy(tr.refdef.viewaxis[0], g_vTerFwd); + g_fCheck = fCheck; - VectorCopy2D(tr.refdef.vieworg, g_vTerOrg); - VectorCopy(tr.refdef.viewaxis[0], g_vTerFwd); - g_fCheck = fCheck; + if (fDistBound != 0.0) { + index = (int)tr.refdef.fov_x; + distance = g_fDistanceTable[index]; - if (fDistBound != 0.0) - { - index = (int)tr.refdef.fov_x; - distance = g_fDistanceTable[index]; + g_fClipDotSquared = g_fClipDotSquaredTable[index]; + g_fClipDotProduct = g_fClipDotProductTable[index]; + VectorCopy(tr.refdef.viewaxis[0], g_vClipVector); + g_vClipOrigin[0] = tr.refdef.vieworg[0] - distance * tr.refdef.viewaxis[0][0] - 256.0; + g_vClipOrigin[1] = tr.refdef.vieworg[1] - distance * tr.refdef.viewaxis[0][1] - 256.0; + g_vClipOrigin[2] = tr.refdef.vieworg[2] - distance * tr.refdef.viewaxis[0][2] - 255.0; + g_vViewVector[0] = tr.refdef.viewaxis[0][0]; + g_vViewVector[1] = tr.refdef.viewaxis[0][1]; + g_vViewVector[2] = + -(tr.refdef.viewaxis[0][0] * tr.refdef.vieworg[0] + tr.refdef.viewaxis[0][1] * tr.refdef.vieworg[1]); + VectorCopy(tr.refdef.vieworg, g_vViewOrigin); - g_fClipDotSquared = g_fClipDotSquaredTable[index]; - g_fClipDotProduct = g_fClipDotProductTable[index]; - VectorCopy(tr.refdef.viewaxis[0], g_vClipVector); - g_vClipOrigin[0] = tr.refdef.vieworg[0] - distance * tr.refdef.viewaxis[0][0] - 256.0; - g_vClipOrigin[1] = tr.refdef.vieworg[1] - distance * tr.refdef.viewaxis[0][1] - 256.0; - g_vClipOrigin[2] = tr.refdef.vieworg[2] - distance * tr.refdef.viewaxis[0][2] - 255.0; - g_vViewVector[0] = tr.refdef.viewaxis[0][0]; - g_vViewVector[1] = tr.refdef.viewaxis[0][1]; - g_vViewVector[2] = -(tr.refdef.viewaxis[0][0] * tr.refdef.vieworg[0] + tr.refdef.viewaxis[0][1] * tr.refdef.vieworg[1]); - VectorCopy(tr.refdef.vieworg, g_vViewOrigin); - - if (tr.viewParms.farplane_distance > 0) { - g_fFogDistance = distance + tr.viewParms.farplane_distance + 768.0; - } else { - g_fFogDistance = 999999.0; - } - } + if (tr.viewParms.farplane_distance > 0) { + g_fFogDistance = distance + tr.viewParms.farplane_distance + 768.0; + } else { + g_fFogDistance = 999999.0; + } + } } -void R_MarkTerrainPatch(cTerraPatchUnpacked_t* pPatch) +void R_MarkTerrainPatch(cTerraPatchUnpacked_t *pPatch) { - if (pPatch->visCountCheck == g_terVisCount) { - return; - } + if (pPatch->visCountCheck == g_terVisCount) { + return; + } - pPatch->visCountCheck = g_terVisCount; - if (ter_cull->integer) - { - vec3_t v; - float dot; + pPatch->visCountCheck = g_terVisCount; + if (ter_cull->integer) { + vec3_t v; + float dot; - v[0] = pPatch->x0 - g_vClipOrigin[0]; - v[1] = pPatch->y0 - g_vClipOrigin[1]; - v[2] = pPatch->z0 - g_vClipOrigin[2]; + v[0] = pPatch->x0 - g_vClipOrigin[0]; + v[1] = pPatch->y0 - g_vClipOrigin[1]; + v[2] = pPatch->z0 - g_vClipOrigin[2]; - dot = DotProduct(v, g_vClipVector); - if (dot > g_fFogDistance) { - return; - } + dot = DotProduct(v, g_vClipVector); + if (dot > g_fFogDistance) { + return; + } - if (VectorLengthSquared(v) * g_fClipDotSquared > dot * dot) { - return; - } - } + if (VectorLengthSquared(v) * g_fClipDotSquared > dot * dot) { + return; + } + } - pPatch->visCountDraw = g_terVisCount; - pPatch->pNextActive = tr.world->activeTerraPatches; - tr.world->activeTerraPatches = pPatch; + pPatch->visCountDraw = g_terVisCount; + pPatch->pNextActive = tr.world->activeTerraPatches; + tr.world->activeTerraPatches = pPatch; } void R_AddTerrainSurfaces() { - int i; - int dlight; - cTerraPatchUnpacked_t* patch; + int i; + int dlight; + cTerraPatchUnpacked_t *patch; - if (tr.world->numTerraPatches < 0) { - return; - } + if (tr.world->numTerraPatches < 0) { + return; + } - if (!ter_lock->integer) { - R_TessellateTerrain(); - } + if (!ter_lock->integer) { + R_TessellateTerrain(); + } - if (ter_count->integer || ter_lock->integer == 2) - { - for (i = 0; i < tr.world->numTerraPatches; i++) - { - patch = &tr.world->terraPatches[i]; + if (ter_count->integer || ter_lock->integer == 2) { + for (i = 0; i < tr.world->numTerraPatches; i++) { + patch = &tr.world->terraPatches[i]; - if (ter_lock->integer == 2 || patch->visCountDraw == g_terVisCount) - { - assert(patch->shader); + if (ter_lock->integer == 2 || patch->visCountDraw == g_terVisCount) { + assert(patch->shader); - dlight = R_CheckDlightTerrain(patch, (1 << (tr.refdef.num_dlights)) - 1); - R_AddDrawSurf((surfaceType_t*)&patch->drawinfo, patch->shader, dlight); - } + dlight = R_CheckDlightTerrain(patch, (1 << (tr.refdef.num_dlights)) - 1); + R_AddDrawSurf((surfaceType_t *)&patch->drawinfo, patch->shader, dlight); + } - if (ter_count->integer && (g_nSplit || g_nMerge)) - { - if (ter_count->integer == 1 || g_nSplit * 2 != g_nMerge) - { - Com_DPrintf( - "%5d tris / %5d verts / %4d splits / %4d merges\n", - g_nTris - g_tri.nFree, - g_nVerts - g_vert.nFree, - g_nSplit, - g_nMerge); - } + if (ter_count->integer && (g_nSplit || g_nMerge)) { + if (ter_count->integer == 1 || g_nSplit * 2 != g_nMerge) { + Com_DPrintf( + "%5d tris / %5d verts / %4d splits / %4d merges\n", + g_nTris - g_tri.nFree, + g_nVerts - g_vert.nFree, + g_nSplit, + g_nMerge + ); + } - g_nSplit = 0; - g_nMerge = 0; - } - } - } - else - { - for (patch = tr.world->activeTerraPatches; patch; patch = patch->pNextActive) - { - assert(patch->shader); + g_nSplit = 0; + g_nMerge = 0; + } + } + } else { + for (patch = tr.world->activeTerraPatches; patch; patch = patch->pNextActive) { + assert(patch->shader); - dlight = R_CheckDlightTerrain(patch, (1 << (tr.refdef.num_dlights)) - 1); - R_AddDrawSurf((surfaceType_t*)&patch->drawinfo, patch->shader, dlight); - } - } + dlight = R_CheckDlightTerrain(patch, (1 << (tr.refdef.num_dlights)) - 1); + R_AddDrawSurf((surfaceType_t *)&patch->drawinfo, patch->shader, dlight); + } + } } /** @@ -1359,178 +1216,182 @@ void R_AddTerrainSurfaces() * * ToDo: try to use the Vector*(?) macros for the math operations below from q_shared.h and q_math.h, not sure which ones would be a good fit */ -qboolean R_TerrainHeightForPoly(cTerraPatchUnpacked_t* pPatch, polyVert_t* pVerts, int nVerts) +qboolean R_TerrainHeightForPoly(cTerraPatchUnpacked_t *pPatch, polyVert_t *pVerts, int nVerts) { - float x0 = 0; - float y0 = 0; - float x1 = 0; - float y1 = 0; - float x2 = 0; - float y2 = 0; - float fKx[3] = { 0 }, fKy[3] = { 0 }, fKz[3] = { 0 }, fArea[3] = { 0 }; - float fAreaTotal = 0; + float x0 = 0; + float y0 = 0; + float x1 = 0; + float y1 = 0; + float x2 = 0; + float y2 = 0; + float fKx[3] = {0}, fKy[3] = {0}, fKz[3] = {0}, fArea[3] = {0}; + float fAreaTotal = 0; - float x = pVerts->xyz[0]; - float y = pVerts->xyz[1]; + float x = pVerts->xyz[0]; + float y = pVerts->xyz[1]; - // Calculate the average of the x and y coordinates of all vertices - if (nVerts > 1) - { - for (int i = 1; i < nVerts; i++) - { - x += pVerts[i].xyz[0]; - y += pVerts[i].xyz[1]; - } + // Calculate the average of the x and y coordinates of all vertices + if (nVerts > 1) { + for (int i = 1; i < nVerts; i++) { + x += pVerts[i].xyz[0]; + y += pVerts[i].xyz[1]; + } - // Use the averaged values from this point onwards - x = x / nVerts; - y = y / nVerts; - } + // Use the averaged values from this point onwards + x = x / nVerts; + y = y / nVerts; + } - // Get the first valid triangle in the patch - terraInt iTri = pPatch->drawinfo.iTriHead; - if (!iTri) - { - assert(!pPatch->drawinfo.iTriHead && - va("R_TerrainHeightForPoly: point(%f %f) not in patch(%f %f %f)\n", - x, y, pPatch->x0, pPatch->y0, pPatch->z0)); - return qfalse; - } + // Get the first valid triangle in the patch + terraInt iTri = pPatch->drawinfo.iTriHead; + if (!iTri) { + assert( + !pPatch->drawinfo.iTriHead + && va( + "R_TerrainHeightForPoly: point(%f %f) not in patch(%f %f %f)\n", + x, + y, + pPatch->x0, + pPatch->y0, + pPatch->z0 + ) + ); + return qfalse; + } - // Find a triangle that contains the point (x, y) - while (qtrue) - { - if (g_pTris[iTri].byConstChecks & 4) - { - // Get all three x-y coordinates of the current triangle's vertices - x0 = g_pVert[g_pTris[iTri].iPt[0]].xyz[0]; - y0 = g_pVert[g_pTris[iTri].iPt[0]].xyz[1]; - x1 = g_pVert[g_pTris[iTri].iPt[1]].xyz[0]; - y1 = g_pVert[g_pTris[iTri].iPt[1]].xyz[1]; - x2 = g_pVert[g_pTris[iTri].iPt[2]].xyz[0]; - y2 = g_pVert[g_pTris[iTri].iPt[2]].xyz[1]; + // Find a triangle that contains the point (x, y) + while (qtrue) { + if (g_pTris[iTri].byConstChecks & 4) { + // Get all three x-y coordinates of the current triangle's vertices + x0 = g_pVert[g_pTris[iTri].iPt[0]].xyz[0]; + y0 = g_pVert[g_pTris[iTri].iPt[0]].xyz[1]; + x1 = g_pVert[g_pTris[iTri].iPt[1]].xyz[0]; + y1 = g_pVert[g_pTris[iTri].iPt[1]].xyz[1]; + x2 = g_pVert[g_pTris[iTri].iPt[2]].xyz[0]; + y2 = g_pVert[g_pTris[iTri].iPt[2]].xyz[1]; - // Calculate the signed areas of the three sub-triangles - fArea[0] = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1); - if (fArea[0] < -0.1) - { - // The point is outside the triangle - continue; - } + // Calculate the signed areas of the three sub-triangles + fArea[0] = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1); + if (fArea[0] < -0.1) { + // The point is outside the triangle + continue; + } - fArea[1] = (x - x2) * (y0 - y2) - (y - y2) * (x0 - x2); - if (fArea[1] < -0.1) - { - // The point is outside the triangle - continue; - } + fArea[1] = (x - x2) * (y0 - y2) - (y - y2) * (x0 - x2); + if (fArea[1] < -0.1) { + // The point is outside the triangle + continue; + } - fArea[2] = (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0); - if (fArea[2] < -0.1) - { - // The point is outside the triangle - continue; - } + fArea[2] = (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0); + if (fArea[2] < -0.1) { + // The point is outside the triangle + continue; + } - fAreaTotal = fArea[0] + fArea[1] + fArea[2]; - if (fAreaTotal > 0.0) - { - // Found it - the point is inside the triangle - break; - } - } + fAreaTotal = fArea[0] + fArea[1] + fArea[2]; + if (fAreaTotal > 0.0) { + // Found it - the point is inside the triangle + break; + } + } - iTri = g_pTris[iTri].iNext; - if (!iTri) - { - // There's no triangle that contains point (x, y) - bail out - assert(!g_pTris[iTri].iNext && - va("R_TerrainHeightForPoly: point(%f %f) not in patch(%f %f %f)\n", - x, y, pPatch->x0, pPatch->y0, pPatch->z0)); - return qfalse; - } - } + iTri = g_pTris[iTri].iNext; + if (!iTri) { + // There's no triangle that contains point (x, y) - bail out + assert( + !g_pTris[iTri].iNext + && va( + "R_TerrainHeightForPoly: point(%f %f) not in patch(%f %f %f)\n", + x, + y, + pPatch->x0, + pPatch->y0, + pPatch->z0 + ) + ); + return qfalse; + } + } - // Calculate the barycentric coordinates (fKx, fKy, fKz) of the triangle - float z0 = g_pVert[g_pTris[iTri].iPt[0]].xyz[2] / fAreaTotal; - float z1 = g_pVert[g_pTris[iTri].iPt[1]].xyz[2] / fAreaTotal; - float z2 = g_pVert[g_pTris[iTri].iPt[2]].xyz[2] / fAreaTotal; + // Calculate the barycentric coordinates (fKx, fKy, fKz) of the triangle + float z0 = g_pVert[g_pTris[iTri].iPt[0]].xyz[2] / fAreaTotal; + float z1 = g_pVert[g_pTris[iTri].iPt[1]].xyz[2] / fAreaTotal; + float z2 = g_pVert[g_pTris[iTri].iPt[2]].xyz[2] / fAreaTotal; - fKy[0] = z0 * (x2 - x1); - fKy[1] = z1 * (x0 - x2); - fKy[2] = z2 * (x1 - x0); + fKy[0] = z0 * (x2 - x1); + fKy[1] = z1 * (x0 - x2); + fKy[2] = z2 * (x1 - x0); - fKx[0] = z0 * (y2 - y1); - fKx[1] = z1 * (y0 - y2); - fKx[2] = z2 * (y1 - y0); + fKx[0] = z0 * (y2 - y1); + fKx[1] = z1 * (y0 - y2); + fKx[2] = z2 * (y1 - y0); - // Note: this could be done with the CrossProduct macro if everything were in a vector - fKz[0] = fKx[0] * x1 - y1 * fKy[0]; - fKz[1] = fKx[1] * x2 - y2 * fKy[1]; - fKz[2] = fKx[2] * x0 - y0 * fKy[2]; + // Note: this could be done with the CrossProduct macro if everything were in a vector + fKz[0] = fKx[0] * x1 - y1 * fKy[0]; + fKz[1] = fKx[1] * x2 - y2 * fKy[1]; + fKz[2] = fKx[2] * x0 - y0 * fKy[2]; - // Calculate the height for each vertex - for (int i = 0; i < nVerts; i++) - { - float fScaleX = pVerts[i].xyz[0] * (fKx[0] + fKx[1] + fKx[2]); - float fScaleY = pVerts[i].xyz[1] * (fKy[0] + fKy[1] + fKy[2]); - float fConstZ = fKz[0] + fKz[1] + fKz[2]; + // Calculate the height for each vertex + for (int i = 0; i < nVerts; i++) { + float fScaleX = pVerts[i].xyz[0] * (fKx[0] + fKx[1] + fKx[2]); + float fScaleY = pVerts[i].xyz[1] * (fKy[0] + fKy[1] + fKy[2]); + float fConstZ = fKz[0] + fKz[1] + fKz[2]; - // Write back the calculated height into the vertex - pVerts[i].xyz[2] = fScaleY - fScaleX - fConstZ; - } + // Write back the calculated height into the vertex + pVerts[i].xyz[2] = fScaleY - fScaleX - fConstZ; + } - return qtrue; + return qtrue; } void R_TerrainRestart_f(void) { - if (tr.world->numTerraPatches < 0) { - return; - } + if (tr.world->numTerraPatches < 0) { + return; + } - ri.Free(g_pVert); - g_pVert = NULL; - ri.Free(g_pTris); - g_pTris = NULL; + ri.Free(g_pVert); + g_pVert = NULL; + ri.Free(g_pTris); + g_pTris = NULL; - R_PreTessellateTerrain(); + R_PreTessellateTerrain(); } -void R_CraterTerrain(vec_t* pos /* 0x8 */, vec_t* dir, float fDepth, float fRadius) +void R_CraterTerrain(vec_t *pos /* 0x8 */, vec_t *dir, float fDepth, float fRadius) { - // FIXME: unimplemented + // FIXME: unimplemented } void R_TerrainCrater_f() { - vec3_t dir; - VectorNegate(tr.refdef.viewaxis[2], dir); + vec3_t dir; + VectorNegate(tr.refdef.viewaxis[2], dir); - R_CraterTerrain(tr.refdef.vieworg, dir, 256.0, 256.0); - R_TerrainRestart_f(); + R_CraterTerrain(tr.refdef.vieworg, dir, 256.0, 256.0); + R_TerrainRestart_f(); } void R_InitTerrain() { - int i; + int i; - ter_maxlod = ri.Cvar_Get("ter_maxlod", "3", CVAR_ARCHIVE | CVAR_TERRAIN_LATCH); - ter_cull = ri.Cvar_Get("ter_cull", "1", 0); - ter_lock = ri.Cvar_Get("ter_lock", "0", 0); - ter_error = ri.Cvar_Get("ter_error", "10", CVAR_ARCHIVE); - ter_cautiousframes = ri.Cvar_Get("ter_cautiousframes", "1", CVAR_ARCHIVE); - ter_maxtris = ri.Cvar_Get("ter_maxtris", "16384", CVAR_TERRAIN_LATCH); - ter_count = ri.Cvar_Get("ter_count", "0", 0); + ter_maxlod = ri.Cvar_Get("ter_maxlod", "3", CVAR_ARCHIVE | CVAR_TERRAIN_LATCH); + ter_cull = ri.Cvar_Get("ter_cull", "1", 0); + ter_lock = ri.Cvar_Get("ter_lock", "0", 0); + ter_error = ri.Cvar_Get("ter_error", "10", CVAR_ARCHIVE); + ter_cautiousframes = ri.Cvar_Get("ter_cautiousframes", "1", CVAR_ARCHIVE); + ter_maxtris = ri.Cvar_Get("ter_maxtris", "16384", CVAR_TERRAIN_LATCH); + ter_count = ri.Cvar_Get("ter_count", "0", 0); - Cmd_AddCommand("ter_restart", R_TerrainRestart_f); - R_PreTessellateTerrain(); + Cmd_AddCommand("ter_restart", R_TerrainRestart_f); + R_PreTessellateTerrain(); - for (i = 0; i < TERRAIN_TABLE_SIZE; i++) - { - float dot = (1.0 / (0.82 - cos((float)i / 57.29) * 0.18) - 1.0) * (16.0 / 9.0); - g_fClipDotSquaredTable[i] = dot; - g_fClipDotProductTable[i] = sqrt(dot); - g_fDistanceTable[i] = 443.5 / sqrt(1.0 - dot); - } + for (i = 0; i < TERRAIN_TABLE_SIZE; i++) { + float dot = (1.0 / (0.82 - cos((float)i / 57.29) * 0.18) - 1.0) * (16.0 / 9.0); + g_fClipDotSquaredTable[i] = dot; + g_fClipDotProductTable[i] = sqrt(dot); + g_fDistanceTable[i] = 443.5 / sqrt(1.0 - dot); + } } From 5fa1b98d34f49f369efb520f41362155033e6a73 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 17:52:29 +0100 Subject: [PATCH 0275/2040] Fixed vert Z coord not matching average height This caused issue where verts would never be merged. This should fix #232 --- code/renderer/tr_terrain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 0c787b73..3151d781 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -934,7 +934,7 @@ static void R_DoGeomorphs() patch->byDirty = qtrue; while (g_vert.iCur) { terrainVert_t *pVert = &g_pVert[g_vert.iCur]; - pVert->xyz[2] = pVert->fHgtAvg + pVert->fHgtAdd; + pVert->xyz[2] = pVert->fHgtAvg; g_vert.iCur = pVert->iNext; } } From fe35e02ed49c552d0d9eb393794e1ecfd35d8e20 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 18:09:19 +0100 Subject: [PATCH 0276/2040] Fixed weapon pickup logic, like player picking up the weapon indefinitely when reaching max ammo --- code/fgame/weapon.cpp | 134 +++++++++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 53 deletions(-) diff --git a/code/fgame/weapon.cpp b/code/fgame/weapon.cpp index 805fbd40..c03c777c 100644 --- a/code/fgame/weapon.cpp +++ b/code/fgame/weapon.cpp @@ -2889,70 +2889,98 @@ void Weapon::PickupWeapon(Event *ev) "print \"" HUD_MESSAGE_YELLOW "%s\n\"", gi.LV_ConvertString(va("Picked Up %s", item_name.c_str())) ); - - if (!(spawnflags & DROPPED_PLAYER_ITEM) && !(spawnflags & DROPPED_ITEM)) { - ItemPickup(other); - return; - } - - if (Pickupable(other)) { - setMoveType(MOVETYPE_NONE); - setSolidType(SOLID_NOT); - - hideModel(); - - velocity = vec_zero; - avelocity = vec_zero; - - CancelEventsOfType(EV_Remove); - CancelEventsOfType(EV_Weapon_FallingAngleAdjust); - - DetachFromOwner(); - current_attachToTag = ""; - lastValid = qfalse; - edict->s.tag_num = -1; - edict->s.attach_use_angles = qfalse; - VectorClear(edict->s.attach_offset); - - setOrigin(vec_zero); - setAngles(vec_zero); - SetOwner(sen); - - sen->AddItem(this); - sen->ReceivedItem(this); - - Sound(sPickupSound); - } } + + if (!(spawnflags & DROPPED_PLAYER_ITEM) && !(spawnflags & DROPPED_ITEM)) { + ItemPickup(other); + return; + } + + if (!Pickupable(other)) { + return; + } + + setMoveType(MOVETYPE_NONE); + setSolidType(SOLID_NOT); + + hideModel(); + + velocity = vec_zero; + avelocity = vec_zero; + + CancelEventsOfType(EV_Remove); + CancelEventsOfType(EV_Weapon_FallingAngleAdjust); + + DetachFromOwner(); + current_attachToTag = ""; + lastValid = qfalse; + edict->s.tag_num = -1; + edict->s.attach_use_angles = qfalse; + VectorClear(edict->s.attach_offset); + + setOrigin(vec_zero); + setAngles(vec_zero); + SetOwner(sen); + + sen->AddItem(this); + sen->ReceivedItem(this); + + iGiveAmmo = startammo[FIRE_PRIMARY]; + + Sound(sPickupSound); } else { - str sAmmoName = ammo_type[FIRE_PRIMARY]; + bool bSameAmmo[MAX_FIREMODES] = { false }; - if (sen->AmmoCount(sAmmoName) != sen->MaxAmmoCount(sAmmoName)) { - setSolidType(SOLID_NOT); - hideModel(); - - CancelEventsOfType(EV_Item_DropToFloor); - CancelEventsOfType(EV_Item_Respawn); - CancelEventsOfType(EV_FadeOut); - CancelEventsOfType(EV_Remove); - CancelEventsOfType(EV_Weapon_FallingAngleAdjust); - - if (Respawnable()) { - PostEvent(EV_Item_Respawn, 0); - } else { - PostEvent(EV_Remove, 0); + if (sen->AmmoCount(ammo_type[FIRE_PRIMARY]) == sen->MaxAmmoCount(ammo_type[FIRE_PRIMARY])) { + bSameAmmo[FIRE_PRIMARY] = true; + if (ammo_type[0] == ammo_type[1]) { + bSameAmmo[FIRE_SECONDARY] = true; } - - Sound(m_sAmmoPickupSound); } + + if (!bSameAmmo[FIRE_SECONDARY]) { + if (sen->AmmoCount(ammo_type[FIRE_SECONDARY]) == sen->MaxAmmoCount(ammo_type[FIRE_SECONDARY])) { + bSameAmmo[FIRE_SECONDARY] = true; + } + } + + if (bSameAmmo[FIRE_PRIMARY] && bSameAmmo[FIRE_SECONDARY]) { + return; + } + + if (bSameAmmo[FIRE_PRIMARY]) { + startammo[FIRE_PRIMARY] = 0; + } + + if (bSameAmmo[FIRE_SECONDARY]) { + startammo[FIRE_SECONDARY] = 0; + } + + setSolidType(SOLID_NOT); + hideModel(); + + CancelEventsOfType(EV_Item_DropToFloor); + CancelEventsOfType(EV_Item_Respawn); + CancelEventsOfType(EV_FadeOut); + CancelEventsOfType(EV_Remove); + CancelEventsOfType(EV_Weapon_FallingAngleAdjust); + + if (Respawnable()) { + PostEvent(EV_Item_Respawn, 0); + } + else { + PostEvent(EV_Remove, 0); + } + + iGiveAmmo = ammo_in_clip[FIRE_PRIMARY] + startammo[FIRE_PRIMARY]; + + Sound(m_sAmmoPickupSound); } if (startammo[FIRE_PRIMARY] && ammo_type[FIRE_PRIMARY].length() && other->isClient()) { str sMessage; const str& sAmmoType = ammo_type[FIRE_PRIMARY]; - iGiveAmmo = startammo[FIRE_PRIMARY]; - sen->GiveAmmo(sAmmoType, iGiveAmmo); /* From 4cf4ca29434429ac5b1fb92da42acf99a3e48bcc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 18:53:22 +0100 Subject: [PATCH 0277/2040] Fixed crash on pSoundAlias --- code/client/snd_dma_new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index 8458bd18..fbe46aed 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -568,7 +568,7 @@ void S_StartLocalSoundChannel(const char *sound_name, qboolean force_load, sound { sfxHandle_t sfxHandle; const char *name; - AliasListNode_t *pSoundAlias; + AliasListNode_t *pSoundAlias = NULL; if (!s_bSoundStarted) { return; From 302f06f8d2d711e84a4cee2594e2414d3a3675d6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 18:54:22 +0100 Subject: [PATCH 0278/2040] Clear the variable if the field cannot be found --- code/script/scriptvm.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/script/scriptvm.cpp b/code/script/scriptvm.cpp index c3251dd2..a2bcb5fd 100644 --- a/code/script/scriptvm.cpp +++ b/code/script/scriptvm.cpp @@ -1590,6 +1590,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) } } catch (...) { skipField(); + m_VMStack.GetTop().Clear(); throw; } @@ -1616,6 +1617,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) } } catch (...) { skipField(); + m_VMStack.GetTop().Clear(); throw; } From d04ed0aace6d6258dca42a49205082370d391a5f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:46:32 +0100 Subject: [PATCH 0279/2040] Made M_PI double --- code/qcommon/q_shared.h | 2 +- code/qcommon/vector.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index a435874b..c053806c 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -421,7 +421,7 @@ typedef int fixed8_t; typedef int fixed16_t; #ifndef M_PI -#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h #endif #ifndef M_SQRT2 diff --git a/code/qcommon/vector.h b/code/qcommon/vector.h index e4dfa120..b533f849 100644 --- a/code/qcommon/vector.h +++ b/code/qcommon/vector.h @@ -975,15 +975,15 @@ inline void Vector::AngleVectorsLeft(Vector *forward, Vector *left, Vector *up) float angle; static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs - angle = yaw() * (M_PI * 2.0f / 360.0f); + angle = yaw() * (M_PI * 2 / 360); sy = sin(angle); cy = cos(angle); - angle = pitch() * (M_PI * 2.0f / 360.0f); + angle = pitch() * (M_PI * 2 / 360); sp = sin(angle); cp = cos(angle); - angle = roll() * (M_PI * 2.0f / 360.0f); + angle = roll() * (M_PI * 2 / 360); sr = sin(angle); cr = cos(angle); From 2e32395cf22b3a973a50d63c11e5cd4cedf13214 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:51:56 +0100 Subject: [PATCH 0280/2040] VectorNormalize optimization --- code/qcommon/q_math.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index 1459f69a..c5fe665e 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -36,6 +36,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define Z 2 #define W 3 +#ifndef FLT_EPSILON +#define FLT_EPSILON 1.19209290E-07F +#endif + vec3_t vec3_origin = {0,0,0}; vec3_t axisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; matrix_t matrixIdentity = { 1, 0, 0, 0, @@ -1827,13 +1831,13 @@ vec_t VectorNormalize( vec3_t v ) { float length, ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); + if (length > FLT_EPSILON) { + length = sqrt(length); - if ( length ) { - ilength = 1/length; - v[0] *= ilength; - v[1] *= ilength; - v[2] *= ilength; + ilength = 1 / length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; } return length; @@ -2921,9 +2925,6 @@ void MatrixMultiplyShear(matrix_t m, vec_t x, vec_t y) Matrix4x4Multiply(tmp, shear, m); } -#ifndef FLT_EPSILON -#define FLT_EPSILON 1.19209290E-07F -#endif void MatrixToAngles(const matrix_t m, vec3_t angles) { #if 1 From 63456beeb0c2bc13621ea611d1aee44f73caec7d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 3 Mar 2024 22:47:31 +0100 Subject: [PATCH 0281/2040] Code clarity --- code/fgame/vehicle.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index fb6c53b1..6392bfa1 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -3465,23 +3465,24 @@ void Vehicle::SetupPath(cVehicleSpline *pPath, SimpleEntity *se) Vector vDelta = vLastOrigin - ent->origin; float vTmp[4]; - if (vDelta.length() == 0.0f && i > 1) { + if (vDelta.length() == 0 && i > 1) { Com_Printf("^~^~^Warning: Vehicle Driving with a Path that contains 2 equal points\n"); - } else { - fCurLength += vDelta.length(); - - vTmp[0] = fCurLength; - VectorCopy(ent->origin, vTmp + 1); - - if (ent->IsSubclassOfVehiclePoint()) { - pPath->Add(vTmp, static_cast(ent)->spawnflags); - } else { - pPath->Add(vTmp, 0); - } - - vLastOrigin = ent->origin; + continue; } + fCurLength += vDelta.length(); + + vTmp[0] = fCurLength; + VectorCopy(ent->origin, vTmp + 1); + + if (ent->IsSubclassOfVehiclePoint()) { + pPath->Add(vTmp, static_cast(ent)->spawnflags); + } else { + pPath->Add(vTmp, 0); + } + + vLastOrigin = ent->origin; + if (ent == se && i > 1) { break; } From 25bbc1793d6f48b00fb07c26160ecaaa2bb5fcf3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 20:06:35 +0100 Subject: [PATCH 0282/2040] Fixed AngleNormalize360 --- code/qcommon/q_math.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index c5fe665e..222b31e0 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -1129,7 +1129,12 @@ returns angle normalized to the range [0 <= angle < 360] ================= */ float AngleNormalize360 ( float angle ) { - return (360.0 / 65536) * ((int)(angle * (65536 / 360.0)) & 65535); + if (angle >= 360) { + return angle - 360 * (int)(angle / 360.0); + } else if (angle < 0) { + return 360 * ((int)(-angle / 360) + 1) + angle; + } + return angle; } From 3acb796b59e4f059eb7eabd74c3f2530c4592ad2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 20:06:50 +0100 Subject: [PATCH 0283/2040] Call VectorNormalize() directly in Vector::normalize() --- code/qcommon/vector.h | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/code/qcommon/vector.h b/code/qcommon/vector.h index b533f849..49400ad3 100644 --- a/code/qcommon/vector.h +++ b/code/qcommon/vector.h @@ -604,17 +604,7 @@ inline float Vector::lengthXYSquared() const //---------------------------------------------------------------- inline float Vector::normalize(void) { - float length, ilength; - - length = this->length(); - if (length) { - ilength = 1.0f / length; - x *= ilength; - y *= ilength; - z *= ilength; - } - - return length; + return VectorNormalize(*this); } //---------------------------------------------------------------- @@ -927,7 +917,7 @@ inline float Vector::toPitch(void) const float pitch; forward = (float)sqrt((x * x) + (y * y)); - pitch = (float)((int)(atan2(z, forward) * 180.0f / M_PI)); + pitch = (float)((int)(atan2(z, forward) * 180 / M_PI)); if (pitch < 0.0f) { pitch += 360.0f; } From 7b07be15023308b3cf40de5a79b33c60f6e368b5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:25:31 +0100 Subject: [PATCH 0284/2040] use double instead of float --- code/fgame/spline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/spline.h b/code/fgame/spline.h index 83ef4520..a32dc460 100644 --- a/code/fgame/spline.h +++ b/code/fgame/spline.h @@ -197,7 +197,7 @@ float *cSpline::GetByNode(float x, int *flags) static float r[cGrids]; double delta[cGrids]; - rp = (int)(floor(x) + 1.0f); + rp = (int)(floor(x) + 1.0); if (rp <= 0) { if (flags) { From 5d3b76b24970d149c310e723aff901928899802e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:26:06 +0100 Subject: [PATCH 0285/2040] Cleaned up SetMoveInfo() / SetCEMoveInfo() --- code/fgame/vehicle.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 6392bfa1..361ed6f6 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -3301,12 +3301,12 @@ void Vehicle::AutoPilot(void) moveimpulse = -m_fIdealSpeed; } } - } else if (m_fIdealSpeed > moveimpulse) { + } else if (moveimpulse < m_fIdealSpeed) { moveimpulse += m_fIdealAccel * level.frametime; if (moveimpulse > m_fIdealSpeed) { moveimpulse = m_fIdealSpeed; } - } else if (m_fIdealSpeed < moveimpulse) { + } else if (moveimpulse > m_fIdealSpeed) { moveimpulse -= m_fIdealAccel * level.frametime; if (moveimpulse < m_fIdealSpeed) { moveimpulse = m_fIdealSpeed; @@ -3849,15 +3849,15 @@ void Vehicle::SetMoveInfo(vmove_t *vm) { memset(vm, 0, sizeof(vmove_t)); - VectorCopy(origin, vs.origin); + origin.copyTo(vs.origin); vs.useGravity = false; vs.entityNum = entnum; vm->vs = &vs; vm->frametime = level.frametime; vm->tracemask = edict->clipmask; - VectorCopy(mins, vm->mins); - VectorCopy(maxs, vm->maxs); + mins.copyTo(vm->mins); + maxs.copyTo(vm->maxs); vs.entityNum = edict->s.number; vs.desired_dir[0] = velocity[0]; @@ -3894,14 +3894,17 @@ Vehicle::SetCEMoveInfo */ void Vehicle::SetCEMoveInfo(vmove_t *vm) { + Vector mins, maxs; + SetMoveInfo(vm); - vm->mins[0] = m_pCollisionEntity->mins[0] - 24.0f; - vm->mins[1] = m_pCollisionEntity->mins[1] - 24.0f; - vm->mins[2] = m_pCollisionEntity->mins[2]; - vm->maxs[0] = m_pCollisionEntity->maxs[0] + 24.0f; - vm->maxs[1] = m_pCollisionEntity->maxs[1] + 24.0f; - vm->maxs[2] = m_pCollisionEntity->maxs[2]; + mins = m_pCollisionEntity->mins; + maxs = m_pCollisionEntity->maxs; + mins -= Vector(24, 24, 0); + maxs += Vector(24, 24, 0); + + mins.copyTo(vm->mins); + maxs.copyTo(vm->maxs); } /* @@ -4688,8 +4691,8 @@ void Vehicle::Postthink(void) velocity.z = drivespeed * jumpimpulse; avelocity *= 0.05f; - if (steerinplace && drivespeed < 350.0f) { - drivespeed = 350.0f; + if (steerinplace && drivespeed < 350) { + drivespeed = 350; } avelocity.y += turn * drivespeed; From 22d279073506634ece23cfac9de03b239bf44f52 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:27:00 +0100 Subject: [PATCH 0286/2040] Fixed vehicle stepping --- code/fgame/g_vmove.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/code/fgame/g_vmove.cpp b/code/fgame/g_vmove.cpp index ec762b88..85b8e638 100644 --- a/code/fgame/g_vmove.cpp +++ b/code/fgame/g_vmove.cpp @@ -179,18 +179,16 @@ qboolean VM_SlideMove(qboolean gravity) break; } - if (trace.plane.normal[2] >= 0.7f) { + if (trace.plane.normal[2] >= MIN_WALK_NORMAL) { memcpy(&vm->vs->groundTrace, &trace, sizeof(vm->vs->groundTrace)); vml.validGroundTrace = qtrue; - } else if (trace.plane.normal[2] > -0.999f) { - if (vm->vs->groundPlane) { - if (!vm->vs->hit_obstacle) { - vm->vs->hit_obstacle = qtrue; - VectorCopy(vm->vs->origin, vm->vs->hit_origin); - } - - VectorAdd(vm->vs->obstacle_normal, trace.plane.normal, vm->vs->obstacle_normal); + } else if (trace.plane.normal[2] > -0.999f && vm->vs->groundPlane) { + if (!vm->vs->hit_obstacle) { + vm->vs->hit_obstacle = qtrue; + VectorCopy(vm->vs->origin, vm->vs->hit_origin); } + + VectorAdd(vm->vs->obstacle_normal, trace.plane.normal, vm->vs->obstacle_normal); } // save entity for contact @@ -439,11 +437,14 @@ void VM_StepSlideMove(void) bWasOnGoodGround = qfalse; } + VectorCopy(start_o, up); + up[2] += STEPSIZE; + VectorCopy(vm->vs->origin, nostep_o); VectorCopy(vm->vs->velocity, nostep_v); memcpy(&nostep_groundTrace, &vm->vs->groundTrace, sizeof(trace_t)); - VectorCopy(start_o, vm->vs->origin); + VectorCopy(up, vm->vs->origin); VectorCopy(start_v, vm->vs->velocity); first_hit_wall = vm->vs->hit_obstacle; @@ -453,7 +454,7 @@ void VM_StepSlideMove(void) vm->vs->hit_obstacle = start_hit_wall; VectorCopy(start_hit_origin, vm->vs->hit_origin); VectorCopy(start_wall_normal, vm->vs->obstacle_normal); - VM_SlideMove(qtrue); + VM_SlideMove(vm->vs->useGravity); VectorCopy(vm->vs->origin, down); down[2] -= STEPSIZE * 2; From c6e3dfdbe684b889a11c645169915bf264ee9db7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:40:49 +0100 Subject: [PATCH 0287/2040] Fixed velocity clip (sliding along plane) This fixes the issue where vehicles would not be moving precisely where it should be moving (incorrect clipping of the velocity). For example, the minesweeper tank in e1l2 kept getting stuck because it didn't move appropriately (fixes #261) --- code/fgame/g_vmove.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/g_vmove.cpp b/code/fgame/g_vmove.cpp index 85b8e638..1cdbb4a8 100644 --- a/code/fgame/g_vmove.cpp +++ b/code/fgame/g_vmove.cpp @@ -237,8 +237,8 @@ qboolean VM_SlideMove(qboolean gravity) } // slide along the plane - VM_ClipVelocity(vm->vs->velocity, planes[j], clipVelocity, OVERCLIP); - VM_ClipVelocity(endVelocity, planes[j], endClipVelocity, OVERCLIP); + VM_ClipVelocity(clipVelocity, planes[j], clipVelocity, OVERCLIP); + VM_ClipVelocity(endClipVelocity, planes[j], endClipVelocity, OVERCLIP); if (DotProduct(clipVelocity, planes[j]) >= 0.0f) { continue; // move doesn't interact with the plane From b4bce3431b033e793b6ed41285456a4f6ecad8c4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:51:29 +0100 Subject: [PATCH 0288/2040] Archive LightClass object pointer instead of a Class object pointer --- code/script/scriptvariable.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/script/scriptvariable.cpp b/code/script/scriptvariable.cpp index ef74bee0..5f32a1b9 100644 --- a/code/script/scriptvariable.cpp +++ b/code/script/scriptvariable.cpp @@ -104,7 +104,7 @@ void ScriptArrayHolder::Archive(Archiver& arc, ScriptArrayHolder *& arrayValue) arrayValue->Archive(arc); return; } else { - arc.ArchiveObjectPointer((Class **)&arrayValue); + arc.ArchiveObjectPointer((LightClass **)&arrayValue); } } @@ -142,7 +142,7 @@ void ScriptConstArrayHolder::Archive(Archiver& arc, ScriptConstArrayHolder *& co constArrayValue->Archive(arc); return; } else { - arc.ArchiveObjectPointer((Class **)&constArrayValue); + arc.ArchiveObjectPointer((LightClass **)&constArrayValue); } } @@ -171,7 +171,7 @@ void ScriptPointer::Archive(Archiver& arc, ScriptPointer *& pointerValue) pointerValue->Archive(arc); return; } else { - arc.ArchiveObjectPointer((Class **)&pointerValue); + arc.ArchiveObjectPointer((LightClass **)&pointerValue); } } @@ -194,7 +194,7 @@ void ScriptVariable::Archive(Archiver& arc) void ScriptVariable::Archive(Archiver& arc, ScriptVariable **obj) { - arc.ArchiveObjectPointer((Class **)obj); + arc.ArchiveObjectPointer((LightClass **)obj); } void ScriptVariable::ArchiveInternal(Archiver& arc) @@ -254,7 +254,7 @@ void ScriptVariable::ArchiveInternal(Archiver& arc) case VARIABLE_REF: case VARIABLE_CONTAINER: - arc.ArchiveObjectPointer((Class **)&m_data.refValue); + arc.ArchiveObjectPointer((LightClass **)&m_data.refValue); break; case VARIABLE_SAFECONTAINER: From cebb351505777d335367fe2f682b31da19fc45de Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:07:16 +0100 Subject: [PATCH 0289/2040] Added and implemented TargetList --- code/fgame/worldspawn.cpp | 46 +++++++++++++++++++++++++++++++++++++++ code/fgame/worldspawn.h | 19 ++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/code/fgame/worldspawn.cpp b/code/fgame/worldspawn.cpp index cd677728..e15f6047 100644 --- a/code/fgame/worldspawn.cpp +++ b/code/fgame/worldspawn.cpp @@ -1197,3 +1197,49 @@ bool WithinFarplaneDistance(const Vector& org) return org.lengthSquared() < (Square(distance) * Square(0.828f)); } + +CLASS_DECLARATION(Class, TargetList, NULL) { + {NULL, NULL} +}; + +TargetList::TargetList() {} + +TargetList::TargetList(const str& tname) + : targetname(tname) +{} + +void TargetList::AddEntity(Listener *ent) +{ + list.AddObject(static_cast(ent)); +} + +void TargetList::AddEntityAt(Listener *ent, int i) +{ + list.AddObjectAt(i, static_cast(ent)); +} + +int TargetList::GetEntityIndex(Listener *ent) +{ + return list.IndexOfObject(static_cast(ent)); +} + +void TargetList::RemoveEntity(Listener *ent) +{ + list.RemoveObject(static_cast(ent)); +} + +SimpleEntity *TargetList::GetNextEntity(SimpleEntity *ent) +{ + int index; + + for (index = list.IndexOfObject(ent); index <= list.NumObjects(); index++) { + Listener *objptr; + + objptr = list.ObjectAt(index); + if (objptr->isSubclassOf(SimpleEntity)) { + return static_cast(objptr); + } + } + + return NULL; +} diff --git a/code/fgame/worldspawn.h b/code/fgame/worldspawn.h index 3e1a05f9..15a3fadf 100644 --- a/code/fgame/worldspawn.h +++ b/code/fgame/worldspawn.h @@ -39,6 +39,25 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA typedef Container> ConSimple; +class TargetList : public Class { +public: + CLASS_PROTOTYPE(TargetList); + +public: + ConSimple list; + str targetname; + +public: + TargetList(); + TargetList(const str& tname); + + void AddEntity(Listener* ent); + void AddEntityAt(Listener* ent, int i); + int GetEntityIndex(Listener* ent); + void RemoveEntity(Listener* ent); + SimpleEntity* GetNextEntity(SimpleEntity* ent); +}; + class World : public Entity { con_set m_targetList; // moh could have used con_set instead of TargetList From 7b8be9fed1d7f2d95e7be284afe8c7b84034dc82 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:34:31 +0100 Subject: [PATCH 0290/2040] Added ArchiveObject() that accepts a SafePtr --- code/fgame/archive.cpp | 5 +++++ code/fgame/archive.h | 1 + 2 files changed, 6 insertions(+) diff --git a/code/fgame/archive.cpp b/code/fgame/archive.cpp index 99bc9b53..fbeb14aa 100644 --- a/code/fgame/archive.cpp +++ b/code/fgame/archive.cpp @@ -938,6 +938,11 @@ void Archiver::ArchiveObject(Class *obj) } } +void Archiver::ArchiveObject(SafePtrBase* obj) +{ + ArchiveSafePointer(obj); +} + void Archiver::ArchiveObjectPosition(LightClass *obj) { int index = 0; diff --git a/code/fgame/archive.h b/code/fgame/archive.h index c2c7b120..42e38602 100644 --- a/code/fgame/archive.h +++ b/code/fgame/archive.h @@ -154,6 +154,7 @@ public: void ArchiveRaw(void *data, size_t size); void ArchiveObject(Class *obj); + void ArchiveObject(SafePtrBase* obj); // Added in OPM qboolean ObjectPositionExists(void *obj); From 897c2322b90a503f84aeff1271f93e30db507616 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:35:22 +0100 Subject: [PATCH 0291/2040] Archive the target list This fixes crashes related to scripts using entities by target name --- code/fgame/worldspawn.cpp | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/code/fgame/worldspawn.cpp b/code/fgame/worldspawn.cpp index e15f6047..65085c3a 100644 --- a/code/fgame/worldspawn.cpp +++ b/code/fgame/worldspawn.cpp @@ -542,6 +542,43 @@ CLASS_DECLARATION(Entity, World, "worldspawn") { {NULL, NULL } }; +template<> +class con_set_Entry +{ + friend con_set; + friend con_set_enum; + +private: + con_set_Entry *next; + +public: + const_str key; + ConSimple value; + +public: + void *operator new(size_t size) { return con_set::NewEntry(size); } + + void operator delete(void *ptr) { con_set::DeleteEntry(ptr); } + + void Archive(Archiver& arc) { + int num; + + arc.ArchiveUnsigned(&key); + arc.ArchiveObjectPosition((LightClass*)&value); + + if (arc.Loading()) { + arc.ArchiveInteger(&num); + value.Resize(num); + } else { + num = value.NumObjects(); + arc.ArchiveInteger(&num); + } + } + const_str& GetKey() { return key; } + + void SetKey(const const_str& newKey) { key = newKey; } +}; + World::World() { world = this; @@ -1146,6 +1183,9 @@ void World::FreeTargetList() void World::Archive(Archiver& arc) { + // FIXME: this is not the original way of archiving target list + m_targetList.Archive(arc); + Entity::Archive(arc); arc.ArchiveFloat(&farplane_distance); From 61e9146385ec1bc01bc43a1a2efd488cfedaf2d8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 5 Mar 2024 18:30:31 +0100 Subject: [PATCH 0292/2040] Moved con_set entry to the header file This fixes compilation issue with GCC (fixes #288) --- code/fgame/worldspawn.cpp | 37 ------------------------------------- code/fgame/worldspawn.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/code/fgame/worldspawn.cpp b/code/fgame/worldspawn.cpp index 65085c3a..14fe1548 100644 --- a/code/fgame/worldspawn.cpp +++ b/code/fgame/worldspawn.cpp @@ -542,43 +542,6 @@ CLASS_DECLARATION(Entity, World, "worldspawn") { {NULL, NULL } }; -template<> -class con_set_Entry -{ - friend con_set; - friend con_set_enum; - -private: - con_set_Entry *next; - -public: - const_str key; - ConSimple value; - -public: - void *operator new(size_t size) { return con_set::NewEntry(size); } - - void operator delete(void *ptr) { con_set::DeleteEntry(ptr); } - - void Archive(Archiver& arc) { - int num; - - arc.ArchiveUnsigned(&key); - arc.ArchiveObjectPosition((LightClass*)&value); - - if (arc.Loading()) { - arc.ArchiveInteger(&num); - value.Resize(num); - } else { - num = value.NumObjects(); - arc.ArchiveInteger(&num); - } - } - const_str& GetKey() { return key; } - - void SetKey(const const_str& newKey) { key = newKey; } -}; - World::World() { world = this; diff --git a/code/fgame/worldspawn.h b/code/fgame/worldspawn.h index 15a3fadf..ce260537 100644 --- a/code/fgame/worldspawn.h +++ b/code/fgame/worldspawn.h @@ -58,6 +58,43 @@ public: SimpleEntity* GetNextEntity(SimpleEntity* ent); }; +template<> +class con_set_Entry +{ + friend con_set; + friend con_set_enum; + +private: + con_set_Entry *next; + +public: + const_str key; + ConSimple value; + +public: + void *operator new(size_t size) { return con_set::NewEntry(size); } + + void operator delete(void *ptr) { con_set::DeleteEntry(ptr); } + + void Archive(Archiver& arc) { + int num; + + arc.ArchiveUnsigned(&key); + arc.ArchiveObjectPosition((LightClass*)&value); + + if (arc.Loading()) { + arc.ArchiveInteger(&num); + value.Resize(num); + } else { + num = value.NumObjects(); + arc.ArchiveInteger(&num); + } + } + const_str& GetKey() { return key; } + + void SetKey(const const_str& newKey) { key = newKey; } +}; + class World : public Entity { con_set m_targetList; // moh could have used con_set instead of TargetList From 9fb559bdb125606f390f22f7067b976bbfc6eb4f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:52:19 +0100 Subject: [PATCH 0293/2040] Added an assertion check for lastRadarTime --- code/server/sv_snapshot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index 1abafffe..f7503500 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -1031,7 +1031,8 @@ static void SV_BuildClientSnapshot( client_t *client ) { for ( i = 0 ; i < entityNumbers.numSnapshotEntities ; i++ ) { ent = SV_GentityNum(entityNumbers.snapshotEntities[i]); if (ent->client) { - client->lastRadarTime[ent->s.number + 1] = svs.time; + assert(ent->s.number < MAX_CLIENTS); + client->lastRadarTime[ent->s.number] = svs.time; } state = &svs.snapshotEntities[svs.nextSnapshotEntities % svs.numSnapshotEntities]; From e970e29953b7feac81d6083bb9fcb3e7be9d14ae Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:57:57 +0100 Subject: [PATCH 0294/2040] Use a constant expression for clarity --- code/server/sv_init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 40209cd7..3145e386 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -421,9 +421,9 @@ void SV_ClientsAlloc( void ) svs.clients = Z_Malloc( svs.iNumClients * sizeof( client_t ) ); Com_Memset( svs.clients, 0, svs.iNumClients * sizeof( client_t ) ); if( g_gametype->integer != GT_SINGLE_PLAYER ) { - svs.numSnapshotEntities = svs.iNumClients * PACKET_BACKUP * 64; + svs.numSnapshotEntities = svs.iNumClients * PACKET_BACKUP * MAX_CLIENTS; } else { - svs.numSnapshotEntities = 1 * 32 * 64; + svs.numSnapshotEntities = 1 * PACKET_BACKUP * MAX_CLIENTS; } SV_InitAllCGMessages(); @@ -515,9 +515,9 @@ void SV_ChangeMaxClients( void ) { Z_Free( oldClients ); if( g_gametype->integer != GT_SINGLE_PLAYER ) { - svs.numSnapshotEntities = svs.iNumClients * PACKET_BACKUP * 64; + svs.numSnapshotEntities = svs.iNumClients * PACKET_BACKUP * MAX_CLIENTS; } else { - svs.numSnapshotEntities = 1 * 32 * 64; + svs.numSnapshotEntities = 1 * PACKET_BACKUP * MAX_CLIENTS; } } From 9f5df368d145033a088ed8b75e986758a537f237 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:30:25 +0100 Subject: [PATCH 0295/2040] Fixed infinite player team spectate --- code/fgame/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 57da2398..683e7be2 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -4686,7 +4686,7 @@ void Player::Think(void) if (!ent->inuse || !ent->entity) { // Invalid spectate entity SetPlayerSpectateRandom(); - } else if (ent->entity->deadflag >= DEAD_DEAD || static_cast(ent->entity)->IsSpectator() || IsValidSpectatePlayer(static_cast(ent->entity))) { + } else if (ent->entity->deadflag >= DEAD_DEAD || static_cast(ent->entity)->IsSpectator() || !IsValidSpectatePlayer(static_cast(ent->entity))) { SetPlayerSpectateRandom(); } } From b6485ad7dbd0c187c0d3ef3f038d4c2ebd4a396e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 6 Mar 2024 18:54:25 +0100 Subject: [PATCH 0296/2040] Configstring optimization so that there is only one occurence of a configstring index in pending server commands This fixes configstring overflow in big maps like t1l2 (fixes #289) --- code/server/sv_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 259e0ea0..95c73afc 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -159,9 +159,9 @@ void SV_AddServerCommand( client_t *client, const char *cmd ) { // this is very ugly but it's also a waste to for instance send multiple config string updates // for the same config string index in one snapshot -// if ( SV_ReplacePendingServerCommands( client, cmd ) ) { -// return; -// } + if ( !strncmp(cmd, "cs ", 3) && SV_ReplacePendingServerCommands(client, cmd) ) { + return; + } // do not send commands until the gamestate has been sent if( client->state < CS_PRIMED ) From 6675a491be04bfa530253eba3a74927a76000a05 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:29:07 +0100 Subject: [PATCH 0297/2040] Fixed the model name when archiving persistant data This fixes a crash when the next mission map is loaded and then saving/loading afterwards (fixes #237) --- code/fgame/player.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 683e7be2..6dcac54d 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -7911,6 +7911,7 @@ painDirection_t Player::Pain_string_to_int(str pain) void Player::ArchivePersistantData(Archiver& arc) { str model_name; + str name; Sentient::ArchivePersistantData(arc); @@ -7922,11 +7923,9 @@ void Player::ArchivePersistantData(Archiver& arc) // set the cvar gi.cvar_set("g_playermodel", model_name.c_str()); - model_name += ".tik"; - setModel(model_name.c_str()); + setModel("models/player/" + model_name + ".tik"); } - str name; if (arc.Saving()) { if (holsteredWeapon) { name = holsteredWeapon->getName(); @@ -7934,11 +7933,10 @@ void Player::ArchivePersistantData(Archiver& arc) name = "none"; } } + arc.ArchiveString(&name); - if (arc.Loading()) { - if (name != "none") { - holsteredWeapon = (Weapon *)FindItem(name); - } + if (arc.Loading() && name != "none") { + holsteredWeapon = (Weapon*)FindItem(name); } UpdateWeapons(); From 98c61529b9a470896282e4d8046a84fc35c6a8cc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:33:39 +0100 Subject: [PATCH 0298/2040] Archive the weapon clip amount in persistent data --- code/fgame/sentient.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index 1f6d6213..1603fa6f 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -2214,11 +2214,25 @@ void Sentient::ArchivePersistantData(Archiver& arc) error("ArchivePersistantData", "Non Item in inventory\n"); } } + arc.ArchiveString(&name); arc.ArchiveInteger(&amount); if (arc.Loading()) { item = giveItem(name, amount); + } + + if (item && item->IsSubclassOfWeapon()) { + Weapon* pWeap = static_cast(item); + item->CancelEventsOfType(EV_Weapon_GiveStartingAmmo); + if (arc.Saving()) { + amount = pWeap->ClipAmmo(FIRE_PRIMARY); + } + arc.ArchiveInteger(&amount); + + if (arc.Loading()) { + pWeap->SetAmmoAmount(amount, FIRE_PRIMARY); + } } } From cacf1ca1b7cf3d00c28168668097e42864049aef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:35:15 +0100 Subject: [PATCH 0299/2040] Set the unarmed flag when archiving persistent data --- code/fgame/sentient.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index 1603fa6f..ea046b2f 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -2287,6 +2287,12 @@ void Sentient::ArchivePersistantData(Archiver& arc) } } + if (GetActiveWeapon(WEAPON_MAIN)) { + edict->s.eFlags &= ~EF_UNARMED; + } else { + edict->s.eFlags |= EF_UNARMED; + } + arc.ArchiveFloat(&health); arc.ArchiveFloat(&max_health); } From b4de0b53e4182e4240ddc5ed4c0ffc83b8d2b55f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:43:37 +0100 Subject: [PATCH 0300/2040] Special items must not be archived in persistent data --- code/fgame/sentient.cpp | 45 +++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index ea046b2f..94305ef4 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -2184,11 +2184,27 @@ static bool IsItemName(const char *name) void Sentient::ArchivePersistantData(Archiver& arc) { - int i; - int num; + int i; + int num; + str name; + int amount; + Item *item; + Entity *ent; // archive the inventory if (arc.Saving()) { + // remove all special items before persistence + for (i = inventory.NumObjects(); i > 0; i--) { + int index; + + index = inventory.ObjectAt(i); + ent = G_GetEntity(index); + name = ent->model; + + if (IsItemName(name)) { + ent->Delete(); + } + } // count up the total number num = inventory.NumObjects(); } else { @@ -2198,10 +2214,6 @@ void Sentient::ArchivePersistantData(Archiver& arc) arc.ArchiveInteger(&num); // archive each item for (i = 1; i <= num; i++) { - str name; - int amount; - Item *item; - if (arc.Saving()) { Entity *ent; @@ -2217,12 +2229,13 @@ void Sentient::ArchivePersistantData(Archiver& arc) arc.ArchiveString(&name); arc.ArchiveInteger(&amount); + if (arc.Loading()) { item = giveItem(name, amount); } if (item && item->IsSubclassOfWeapon()) { - Weapon* pWeap = static_cast(item); + Weapon *pWeap = static_cast(item); item->CancelEventsOfType(EV_Weapon_GiveStartingAmmo); if (arc.Saving()) { @@ -2258,16 +2271,17 @@ void Sentient::ArchivePersistantData(Archiver& arc) amount = ptr->getAmount(); maxamount = ptr->getMaxAmount(); } + arc.ArchiveString(&name); arc.ArchiveInteger(&amount); arc.ArchiveInteger(&maxamount); + if (arc.Loading()) { GiveAmmo(name, amount, maxamount); } } for (i = 0; i < MAX_ACTIVE_WEAPONS; i++) { - str name; if (arc.Saving()) { if (activeWeaponList[i]) { name = activeWeaponList[i]->getName(); @@ -2275,14 +2289,15 @@ void Sentient::ArchivePersistantData(Archiver& arc) name = "none"; } } + arc.ArchiveString(&name); - if (arc.Loading()) { - if (name != "none") { - Weapon *weapon; - weapon = (Weapon *)FindItem(name); - if (weapon) { - ChangeWeapon(weapon, (weaponhand_t)i); - } + + if (arc.Loading() && name != "none") { + Weapon *weapon; + + weapon = (Weapon *)FindItem(name); + if (weapon) { + ChangeWeapon(weapon, (weaponhand_t)i); } } } From 25418b7857edd7adf2dc05ef36f37e0c49cc64f9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:45:03 +0100 Subject: [PATCH 0301/2040] Ammo name must be case-insensitive This fixes some maps like t1l3 where the player would have a pistol with 6 bullets and no ammo --- code/fgame/sentient_combat.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/code/fgame/sentient_combat.cpp b/code/fgame/sentient_combat.cpp index 4aef186e..adc0241d 100644 --- a/code/fgame/sentient_combat.cpp +++ b/code/fgame/sentient_combat.cpp @@ -74,7 +74,6 @@ void Sentient::EventGiveAmmo(Event *ev) } int Sentient::AmmoIndex(str type) - { Ammo *ammo; @@ -146,7 +145,6 @@ void Sentient::GiveAmmo(str type, int amount, int maxamount) } int Sentient::UseAmmo(str type, int amount) - { int count, i; @@ -154,7 +152,7 @@ int Sentient::UseAmmo(str type, int amount) for (i = 1; i <= count; i++) { Ammo *ammo = ammo_inventory.ObjectAt(i); - if (type == ammo->getName()) { + if (!str::icmp(type, ammo->getName())) { int ammo_amount = ammo->getAmount(); // Less ammo than what we specified to use @@ -180,7 +178,9 @@ void Sentient::AmmoAmountInClipChanged(str type, int amount_in_clip) for (i = 1; i <= count; i++) { Ammo *ammo = ammo_inventory.ObjectAt(i); - if (type == ammo->getName()) { + // Fixed in OPM + // Original uses strcmp + if (!str::icmp(type, ammo->getName())) { AmmoAmountChanged(ammo, amount_in_clip); } } @@ -1035,7 +1035,6 @@ Weapon *Sentient::GetActiveWeapon(weaponhand_t hand) const } qboolean Sentient::IsActiveWeapon(Weapon *weapon) - { int i; @@ -1246,7 +1245,7 @@ Ammo *Sentient::FindAmmoByName(str name) for (i = 1; i <= count; i++) { Ammo *ammo = ammo_inventory.ObjectAt(i); - if (name == ammo->getName()) { + if (!str::icmp(name, ammo->getName())) { return ammo; } } From 6fdc756b590cecaff1786450b2dfaba071336688 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 17 Mar 2024 22:38:44 +0100 Subject: [PATCH 0302/2040] Set terrain rendering settings to max detail by default --- code/renderer/tr_terrain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 3151d781..2e921216 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -1377,12 +1377,12 @@ void R_InitTerrain() { int i; - ter_maxlod = ri.Cvar_Get("ter_maxlod", "3", CVAR_ARCHIVE | CVAR_TERRAIN_LATCH); + ter_maxlod = ri.Cvar_Get("ter_maxlod", "6", CVAR_ARCHIVE | CVAR_TERRAIN_LATCH); ter_cull = ri.Cvar_Get("ter_cull", "1", 0); ter_lock = ri.Cvar_Get("ter_lock", "0", 0); - ter_error = ri.Cvar_Get("ter_error", "10", CVAR_ARCHIVE); + ter_error = ri.Cvar_Get("ter_error", "4", CVAR_ARCHIVE); ter_cautiousframes = ri.Cvar_Get("ter_cautiousframes", "1", CVAR_ARCHIVE); - ter_maxtris = ri.Cvar_Get("ter_maxtris", "16384", CVAR_TERRAIN_LATCH); + ter_maxtris = ri.Cvar_Get("ter_maxtris", "24576", CVAR_TERRAIN_LATCH); ter_count = ri.Cvar_Get("ter_count", "0", 0); Cmd_AddCommand("ter_restart", R_TerrainRestart_f); From 724aeb22ed51f768d333bddf2b8b729688c3bd26 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 31 Mar 2024 22:15:19 +0200 Subject: [PATCH 0303/2040] Fixed MM_SlideMove() velocity clip and interaction --- code/fgame/g_mmove.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/code/fgame/g_mmove.cpp b/code/fgame/g_mmove.cpp index 9bdcdb90..a17ee607 100644 --- a/code/fgame/g_mmove.cpp +++ b/code/fgame/g_mmove.cpp @@ -211,6 +211,8 @@ qboolean MM_SlideMove(qboolean gravity) // // modify velocity so it parallels all of the clip planes // + VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; // find a plane that it enters for (i = 0; i < numplanes; i++) { @@ -227,10 +229,14 @@ qboolean MM_SlideMove(qboolean gravity) continue; } - // slide along the plane - MM_ClipVelocity(mm->velocity, planes[j], clipVelocity, OVERCLIP); + if (DotProduct(clipVelocity, planes[j]) >= 0.1) { + continue; // move doesn't interact with the plane + } - if (DotProduct(clipVelocity, planes[j]) >= 0.0f) { + // slide along the plane + MM_ClipVelocity(clipVelocity, planes[j], clipVelocity, OVERCLIP); + + if (DotProduct(clipVelocity, planes[i]) >= 0) { continue; // move doesn't interact with the plane } @@ -246,7 +252,7 @@ qboolean MM_SlideMove(qboolean gravity) continue; } - if (DotProduct(clipVelocity, planes[k]) >= 0.1f) { + if (DotProduct(clipVelocity, planes[k]) >= 0.1) { continue; // move doesn't interact with the plane } From 5a8cc83e6ed2a3d16b8d125326662d69e09dcef2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 31 Mar 2024 22:52:30 +0200 Subject: [PATCH 0304/2040] Fixed MM stepping This fixes actors being slow and it also fixes actors going under the map --- code/fgame/g_mmove.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code/fgame/g_mmove.cpp b/code/fgame/g_mmove.cpp index a17ee607..3bb107c5 100644 --- a/code/fgame/g_mmove.cpp +++ b/code/fgame/g_mmove.cpp @@ -404,12 +404,14 @@ void MM_StepSlideMove(void) bWasOnGoodGround = qfalse; } - start_o[2] += 18; + VectorCopy(start_o, up); + up[2] += 18; + VectorCopy(mm->origin, nostep_o); VectorCopy(mm->velocity, nostep_v); memcpy(&nostep_groundTrace, &mml.groundTrace, sizeof(trace_t)); - VectorCopy(start_o, mm->origin); + VectorCopy(up, mm->origin); VectorCopy(start_v, mm->velocity); first_hit_wall = mm->hit_obstacle; @@ -425,7 +427,7 @@ void MM_StepSlideMove(void) down[2] -= STEPSIZE * 2; // test the player position if they were a stepheight higher - gi.trace(&trace, start_o, mm->mins, mm->maxs, down, mm->entityNum, mm->tracemask, qtrue, qfalse); + gi.trace(&trace, mm->origin, mm->mins, mm->maxs, down, mm->entityNum, mm->tracemask, qtrue, qfalse); if (trace.entityNum != ENTITYNUM_WORLD && trace.entityNum != ENTITYNUM_NONE) { VectorCopy(nostep_o, mm->origin); VectorCopy(nostep_v, mm->velocity); From 9eec50d69fcfc7cc8f62d1f76ab63a64809a6556 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:52:58 +0200 Subject: [PATCH 0305/2040] Fixed script model animation issues, especially when they're looping This fixes #220. --- code/fgame/scriptslave.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 4633b8a9..b99d1e06 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1957,6 +1957,7 @@ void ScriptModel::SetAnimEvent(Event *ev) animnum = gi.Anim_NumForName(edict->tiki, animname); if (animnum >= 0) { NewAnim(animnum, EV_ScriptModel_AnimDone); + RestartAnimSlot(0); } } } From e3beec985e6a69b885781725545ed242a859f9e5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:00:48 +0200 Subject: [PATCH 0306/2040] When parsing and compiling a script, return the length in an output parameter instead so the method can return a boolean to indicate success. This fixes #221 where a script with no code would fail. --- code/fgame/gamescript.cpp | 45 +++++++++++++++++++--------------- code/script/scriptcompiler.cpp | 24 ++++++++++-------- code/script/scriptcompiler.h | 4 +-- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/code/fgame/gamescript.cpp b/code/fgame/gamescript.cpp index fd3a18eb..cad742e0 100644 --- a/code/fgame/gamescript.cpp +++ b/code/fgame/gamescript.cpp @@ -104,7 +104,7 @@ void AbstractScript::PrintSourcePos(sourceinfo_t *sourcePos, bool dev) if (GetSourceAt(sourcePos->sourcePos, &sourceLine, column, line)) { PrintSourcePos(sourceLine, column, line, dev); } else { - glbs.DPrintf( + gi.DPrintf( "file '%s', source pos %d line %d column %d:\n", Filename().c_str(), sourcePos->sourcePos, @@ -123,7 +123,7 @@ void AbstractScript::PrintSourcePos(size_t sourcePos, bool dev) if (GetSourceAt(sourcePos, &sourceLine, column, line)) { PrintSourcePos(sourceLine, column, line, dev); } else { - glbs.DPrintf("file '%s', source pos %d:\n", Filename().c_str(), sourcePos); + gi.DPrintf("file '%s', source pos %d:\n", Filename().c_str(), sourcePos); } } @@ -153,7 +153,7 @@ void AbstractScript::PrintSourcePos(str sourceLine, int column, int line, bool d markerLine.append("^"); - glbs.DPrintf("(%s, %d):\n%s\n%s\n", Filename().c_str(), line, sourceLine.c_str(), markerLine.c_str()); + gi.DPrintf("(%s, %d):\n%s\n%s\n", Filename().c_str(), line, sourceLine.c_str(), markerLine.c_str()); } AbstractScript::AbstractScript() @@ -493,7 +493,7 @@ void GameScript::Archive(Archiver& arc) } else { - m_ProgBuffer = ( unsigned char * )glbs.Malloc( m_ProgLength ); + m_ProgBuffer = ( unsigned char * )gi.Malloc( m_ProgLength ); code_pos = m_ProgBuffer; code_end = m_ProgBuffer + m_ProgLength; @@ -591,14 +591,14 @@ void GameScript::Archive(Archiver& arc) { fileHandle_t filehandle = NULL; - m_SourceLength = glbs.FS_ReadFile( Filename().c_str(), ( void ** )&m_SourceBuffer, true ); + m_SourceLength = gi.FS_ReadFile( Filename().c_str(), ( void ** )&m_SourceBuffer, true ); if( m_SourceLength > 0 ) { - m_SourceBuffer = ( char * )glbs.Malloc( m_SourceLength ); + m_SourceBuffer = ( char * )gi.Malloc( m_SourceLength ); - glbs.FS_Read( m_SourceBuffer, m_SourceLength, filehandle ); - glbs.FS_FCloseFile( filehandle ); + gi.FS_Read( m_SourceBuffer, m_SourceLength, filehandle ); + gi.FS_FCloseFile( filehandle ); } } @@ -661,12 +661,12 @@ void GameScript::Close(void) } if (m_ProgBuffer) { - glbs.Free(m_ProgBuffer); + gi.Free(m_ProgBuffer); m_ProgBuffer = NULL; } if (m_SourceBuffer) { - glbs.Free(m_SourceBuffer); + gi.Free(m_SourceBuffer); m_SourceBuffer = NULL; } @@ -680,7 +680,7 @@ void GameScript::Load(const void *sourceBuffer, size_t sourceLength) size_t nodeLength; char *m_PreprocessedBuffer; - m_SourceBuffer = (char *)glbs.Malloc(sourceLength + 2); + m_SourceBuffer = (char *)gi.Malloc(sourceLength + 2); m_SourceLength = sourceLength; // Original mohaa doesn't reallocate the input string to append a newline @@ -694,19 +694,24 @@ void GameScript::Load(const void *sourceBuffer, size_t sourceLength) Compiler.Reset(); m_PreprocessedBuffer = Compiler.Preprocess(m_SourceBuffer); - nodeLength = Compiler.Parse(this, m_PreprocessedBuffer, "script"); - Compiler.Preclean(m_PreprocessedBuffer); - - if (!nodeLength) { - glbs.DPrintf2("^~^~^ Script file compile error: Couldn't parse '%s'\n", Filename().c_str()); + if (!Compiler.Parse(this, m_PreprocessedBuffer, "script", nodeLength)) { + gi.DPrintf2("^~^~^ Script file compile error: Couldn't parse '%s'\n", Filename().c_str()); return Close(); } - m_ProgBuffer = (unsigned char *)glbs.Malloc(nodeLength); - m_ProgLength = Compiler.Compile(this, m_ProgBuffer); + if (nodeLength == 0) { + // No code, assume success + requiredStackSize = 0; + successCompile = true; + return; + } - if (!m_ProgLength) { - glbs.DPrintf2("^~^~^ Script file compile error: Couldn't compile '%s'\n", Filename().c_str()); + Compiler.Preclean(m_PreprocessedBuffer); + + m_ProgBuffer = (unsigned char *)gi.Malloc(nodeLength); + + if (!Compiler.Compile(this, m_ProgBuffer, m_ProgLength)) { + gi.DPrintf2("^~^~^ Script file compile error: Couldn't compile '%s'\n", Filename().c_str()); return Close(); } diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index 807fc1dc..9e6eeaeb 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -1497,7 +1497,7 @@ int yyerror(const char *msg) return 1; } -size_t ScriptCompiler::Parse(GameScript *gameScript, char *sourceBuffer, const char *type) +bool ScriptCompiler::Parse(GameScript *gameScript, char *sourceBuffer, const char *type, size_t& outLength) { parsedata = yyparsedata(); @@ -1515,6 +1515,8 @@ size_t ScriptCompiler::Parse(GameScript *gameScript, char *sourceBuffer, const c script = gameScript; stateScript = &gameScript->m_State; + outLength = 0; + yy_init_script(); parsetree_init(); @@ -1531,22 +1533,23 @@ size_t ScriptCompiler::Parse(GameScript *gameScript, char *sourceBuffer, const c } yylex_destroy(); - return 0; + return false; } } catch (ScriptException& exc) { yylex_destroy(); exc; - return 0; + return false; } yylex_destroy(); - return parsedata.total_length; + outLength = parsedata.total_length; + return true; } -size_t ScriptCompiler::Compile(GameScript *gameScript, unsigned char *progBuffer) +bool ScriptCompiler::Compile(GameScript *gameScript, unsigned char *progBuffer, size_t& outLength) { - size_t length; + bool success = false; if (progBuffer == NULL) { glbs.DPrintf("Invalid program buffer\n"); @@ -1570,21 +1573,22 @@ size_t ScriptCompiler::Compile(GameScript *gameScript, unsigned char *progBuffer if (compileSuccess) { stateScript->AddLabel("", code_ptr); - length = code_pos - code_ptr; + outLength = code_pos - code_ptr; + success = true; } else { - length = 0; + outLength = 0; } prog_end_ptr = code_pos; } catch (ScriptException& exc) { exc; - length = 0; + outLength = 0; prog_end_ptr = code_pos; } parsetree_freeall(); - return length; + return success; } str ScriptCompiler::GetLine(str content, int line) diff --git a/code/script/scriptcompiler.h b/code/script/scriptcompiler.h index 0dce5227..48592872 100644 --- a/code/script/scriptcompiler.h +++ b/code/script/scriptcompiler.h @@ -163,8 +163,8 @@ public: char *Preprocess(char *sourceBuffer); void Preclean(char *processedBuffer); - size_t Parse(GameScript *m_GameScript, char *sourceBuffer, const char *type); - size_t Compile(GameScript *m_GameScript, unsigned char *progBuffer); + bool Parse(GameScript *m_GameScript, char *sourceBuffer, const char *type, size_t& outLength); + bool Compile(GameScript *m_GameScript, unsigned char *progBuffer, size_t& outLength); static str GetLine(str content, int line); From e859bba61de976f1d09987c12e0faa0a1ee19778 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:30:52 +0200 Subject: [PATCH 0307/2040] Added a forgotten call to SetupNextCycle when turning on the projectile generator and fixed the uninitialized delay before beginning the cycle. This fixes artillery system not working on t2l3, t2l4, e1l1... (fixes #224) --- code/fgame/Entities.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/fgame/Entities.cpp b/code/fgame/Entities.cpp index 139d6e8f..95990fe7 100644 --- a/code/fgame/Entities.cpp +++ b/code/fgame/Entities.cpp @@ -492,6 +492,7 @@ void ProjectileGenerator::TurnOn(Event *ev) if (!m_bIsTurnedOn) { CancelEventsOfType(EV_PG_BeginCycle); CancelEventsOfType(EV_TickCycle); + SetupNextCycle(); m_bIsTurnedOn = true; } } @@ -519,6 +520,7 @@ void ProjectileGenerator::SetupNextCycle() // get a random delay m_fShotsPerSec = numShots / m_fCycleTime; + delay = 0.01f; if (m_bIsTurnedOn || !m_bFireOnStartUp) { delay = G_Random(m_fMaxDelay - m_fMinDelay) + m_fMinDelay; } From 881df7193bcf07be3b9a83953d231f5fbc458c05 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:47:24 +0200 Subject: [PATCH 0308/2040] Fixed ThrowObject not usable when spawned from script. This fixes #218 --- code/fgame/object.cpp | 4 ++-- code/fgame/object.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/code/fgame/object.cpp b/code/fgame/object.cpp index fdf81e4a..b4ff17b7 100644 --- a/code/fgame/object.cpp +++ b/code/fgame/object.cpp @@ -213,7 +213,7 @@ Event EV_ThrowObject_ThrowSound EV_NORMAL ); -CLASS_DECLARATION(Object, ThrowObject, "func_throwobject") { +CLASS_DECLARATION(Animate, ThrowObject, "func_throwobject") { {&EV_Touch, &ThrowObject::Touch }, {&EV_ThrowObject_Pickup, &ThrowObject::Pickup }, {&EV_ThrowObject_Throw, &ThrowObject::Throw }, @@ -385,7 +385,7 @@ void ThrowObject::Pickup(Event *ev) void ThrowObject::Archive(Archiver& arc) { - Object::Archive(arc); + Animate::Archive(arc); arc.ArchiveInteger(&owner); arc.ArchiveVector(&pickup_offset); diff --git a/code/fgame/object.h b/code/fgame/object.h index 310edf76..24cefb0a 100644 --- a/code/fgame/object.h +++ b/code/fgame/object.h @@ -56,7 +56,10 @@ public: extern Event EV_ThrowObject_Pickup; extern Event EV_ThrowObject_Throw; -class ThrowObject : public Object +// Fixed in 2.0 +// Before 2.0, ThrowObject was inheriting from Object. +// This caused issue when spawning the ThrowObject from script. +class ThrowObject : public Animate { private: int owner; From 52424f63f0686d9ae8766531f28b93f6ddadde48 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:51:03 +0200 Subject: [PATCH 0309/2040] Make ThrowObject::Throw throws an exception when the owner and targetent is NULL, also use centroid if the target entity is not a sentient --- code/fgame/object.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/code/fgame/object.cpp b/code/fgame/object.cpp index b4ff17b7..0cd08c65 100644 --- a/code/fgame/object.cpp +++ b/code/fgame/object.cpp @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "specialfx.h" #include "g_phys.h" #include "game.h" +#include "../script/scriptexception.h" Event EV_Object_HandleSetModel ( @@ -46,7 +47,14 @@ CLASS_DECLARATION(Animate, Object, NULL) { {NULL, NULL} }; -Event EV_InteractObject_Setup("_setup", EV_DEFAULT, NULL, NULL, "Sets up an object."); +Event EV_InteractObject_Setup +( + "_setup", + EV_DEFAULT, + NULL, + NULL, + "Sets up an object." +); Event EV_InteractObject_KilledEffect ( @@ -118,10 +126,10 @@ void InteractObject::Damaged(Event *ev) void InteractObject::Killed(Event *ev) { - Entity *ent; - Entity *attacker; - Vector dir; - const char *name; + Entity *ent; + Entity *attacker; + Vector dir; + const char *name; takedamage = DAMAGE_NO; deadflag = DEAD_NO; @@ -242,7 +250,6 @@ void ThrowObject::ThrowSound(Event *ev) } void ThrowObject::Touch(Event *ev) - { Entity *other; @@ -283,7 +290,6 @@ void ThrowObject::Touch(Event *ev) } void ThrowObject::Throw(Event *ev) - { Entity *owner; Sentient *targetent; @@ -300,6 +306,7 @@ void ThrowObject::Throw(Event *ev) assert(owner); if (!owner) { + ScriptError("owner == NULL"); return; } @@ -311,6 +318,7 @@ void ThrowObject::Throw(Event *ev) targetent = (Sentient *)ev->GetEntity(3); assert(targetent); if (!targetent) { + ScriptError("targetent == NULL"); return; } @@ -328,8 +336,12 @@ void ThrowObject::Throw(Event *ev) gravity = grav; - target = targetent->origin; - target.z += targetent->viewheight; + if (targetent->IsSubclassOfSentient()) { + target = targetent->origin; + target.z += targetent->viewheight; + } else { + target = targetent->centroid; + } setMoveType(MOVETYPE_BOUNCE); setSolidType(SOLID_BBOX); @@ -359,7 +371,6 @@ void ThrowObject::Throw(Event *ev) } void ThrowObject::Pickup(Event *ev) - { Entity *ent; Event *e; From ccc98e4c62348c83e023cf10ffbab4492db558ee Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:38:51 +0200 Subject: [PATCH 0310/2040] Implemented missing ThrobbingBox_Stickybomb() --- code/fgame/Entities.cpp | 20 +++++++++++++ code/fgame/Entities.h | 62 +++++++++++++++++++++-------------------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/code/fgame/Entities.cpp b/code/fgame/Entities.cpp index 95990fe7..67d59f00 100644 --- a/code/fgame/Entities.cpp +++ b/code/fgame/Entities.cpp @@ -1988,6 +1988,26 @@ CLASS_DECLARATION(ThrobbingBox_Explosive, ThrobbingBox_Stickybomb, "ThrobbingBox {NULL, NULL } }; +ThrobbingBox_Stickybomb::ThrobbingBox_Stickybomb() +{ + if (LoadingSavegame) { + return; + } + + setModel("items/pulse_stickybomb.tik"); + m_sUsedModel = "items/stickybomb.tik"; + m_sSound = "explode_flak88"; + m_sActivateSound = "stickybomb_plant"; + m_sTickSound = "stickybomb_fuse"; + + health = 10; + m_fStopwatchStartTime = 0; + + setSolidType(SOLID_BBOX); + takedamage = DAMAGE_NO; + setContents(CONTENTS_WEAPONCLIP); +} + void ThrobbingBox_Stickybomb::OnStickyBombWet(Event *ev) { Player *player; diff --git a/code/fgame/Entities.h b/code/fgame/Entities.h index c08365f8..75fce27c 100644 --- a/code/fgame/Entities.h +++ b/code/fgame/Entities.h @@ -26,19 +26,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "animate.h" typedef enum { - CONTROLLER_ALLIES, - CONTROLLER_AXIS, + CONTROLLER_ALLIES, + CONTROLLER_AXIS, CONTROLLER_DRAW } eController; -#define PT_SPAWNFLAG_PLAY_FIRE_SOUND 1 -#define PT_SPAWNFLAG_PLAY_MOTION_SOUND 2 -#define PT_SPAWNFLAG_TARGET_RANDOM 4 -#define PT_SPAWNFLAG_TURN_ON 8 -#define PT_SPAWNFLAG_ROTATE_YAW 16 -#define PT_SPAWNFLAG_ROTATE_ROLL 32 -#define PT_SPAWNFLAG_TARGET_PLAYER 64 -#define PT_SPAWNFLAG_HIDDEN 128 +#define PT_SPAWNFLAG_PLAY_FIRE_SOUND 1 +#define PT_SPAWNFLAG_PLAY_MOTION_SOUND 2 +#define PT_SPAWNFLAG_TARGET_RANDOM 4 +#define PT_SPAWNFLAG_TURN_ON 8 +#define PT_SPAWNFLAG_ROTATE_YAW 16 +#define PT_SPAWNFLAG_ROTATE_ROLL 32 +#define PT_SPAWNFLAG_TARGET_PLAYER 64 +#define PT_SPAWNFLAG_HIDDEN 128 void ClearProjectileTargets(); @@ -53,7 +53,7 @@ public: ProjectileTarget(); void EventSetId(Event *ev); - int GetTarget() const; + int GetTarget() const; }; #define MAX_PROJECTILE_GENERATOR_TARGETS 16 @@ -106,16 +106,16 @@ public: bool ShouldRotateYaw() const; bool ShouldRotateRoll() const; - void EventIsTurnedOn(Event *ev); - void EventGetTargetEntity(Event *ev); - void EventLaunchSound(Event *ev); - void SetTarget(Event *ev); - void SetTarget(Entity* ent); - void OnInitialize(Event *ev); - void TurnOff(Event *ev); - void TurnOn(Event *ev); - bool ShouldTargetRandom() const; - Entity* ChooseTarget(); + void EventIsTurnedOn(Event *ev); + void EventGetTargetEntity(Event *ev); + void EventLaunchSound(Event *ev); + void SetTarget(Event *ev); + void SetTarget(Entity *ent); + void OnInitialize(Event *ev); + void TurnOff(Event *ev); + void TurnOn(Event *ev); + bool ShouldTargetRandom() const; + Entity *ChooseTarget(); void GetLocalTargets(); bool ShouldTargetPlayer() const; @@ -123,7 +123,7 @@ public: void GetMuzzlePos(Vector& pos); void Fire(); void TryLaunchSound(); - void SetWeaponAnim(const char* name, Event* ev); + void SetWeaponAnim(const char *name, Event *ev); void EventAccuracy(Event *ev); void EventMaxDelay(Event *ev); void EventMinDelay(Event *ev); @@ -134,11 +134,11 @@ public: void EventMaxDuration(Event *ev); void EventMinDuration(Event *ev); void SetWeaponModel(Event *ev); - void EventSetId(Event* ev); - void EventmaxDonut(Event* ev); - void EventminDonut(Event* ev); - void EventarcDonut(Event* ev); - void EventisDonut(Event* ev); + void EventSetId(Event *ev); + void EventmaxDonut(Event *ev); + void EventminDonut(Event *ev); + void EventarcDonut(Event *ev); + void EventisDonut(Event *ev); virtual bool Attack(int count); void Archive(Archiver& arc) override; @@ -164,8 +164,8 @@ public: void SetProjectileModel(Event *ev); float EstimateImpactTime(const Vector& targetOrigin, const Vector& fromOrigin, float speed) const; - bool Attack(int count) override; - void Archive(Archiver& arc) override; + bool Attack(int count) override; + void Archive(Archiver& arc) override; }; class ProjectileGenerator_Gun : public ProjectileGenerator @@ -306,6 +306,8 @@ private: public: CLASS_PROTOTYPE(ThrobbingBox_Stickybomb); + ThrobbingBox_Stickybomb(); + void OnStickyBombWet(Event *ev); void OnStickyBombUse(Event *ev); @@ -325,7 +327,7 @@ public: Objective(); - void Archive(Archiver &arc) override; + void Archive(Archiver& arc) override; void TurnOn(Event *ev); void TurnOff(Event *ev); void Complete(Event *ev); From ab5efa5a641ede393b2091bb903bd705eb6c48c1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:12:02 +0200 Subject: [PATCH 0311/2040] Fixed sentient being improperly attached/detached from/to the turret This fixes #255 --- code/fgame/vehicle.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 361ed6f6..0ce9fad1 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -3735,14 +3735,12 @@ void Vehicle::DriverUse(Event *ev) slot = FindTurretSlotByEntity(sent->GetTurret()); if (slot >= 0) { - if (bHasExitPosition) { - if (bHasExitAngles) { - AttachTurretSlot(slot, sentTurret, vExitPosition, &vExitAngles); - } else { - AttachTurretSlot(slot, sentTurret, vExitPosition, NULL); - } + if (!bHasExitPosition) { + AttachTurretSlot(slot, sent, vec_zero, NULL); + } else if (!bHasExitAngles) { + AttachTurretSlot(slot, sent, vExitPosition, NULL); } else { - AttachTurretSlot(slot, sentTurret, vec_zero, NULL); + AttachTurretSlot(slot, sent, vExitPosition, &vExitAngles); } sent->SetVehicle(NULL); @@ -3753,7 +3751,7 @@ void Vehicle::DriverUse(Event *ev) // Check for passengers slots for (slot = 0; slot < MAX_PASSENGERS; slot++) { - if (!(Passengers[0].flags & SLOT_FREE)) { + if (!(Passengers[slot].flags & SLOT_FREE)) { continue; } @@ -3771,7 +3769,7 @@ void Vehicle::DriverUse(Event *ev) // Check for turrets slots if (ent->IsSubclassOfWeapon()) { for (slot = 0; slot < MAX_TURRETS; slot++) { - if (!(Turrets[0].flags & SLOT_FREE)) { + if (!(Turrets[slot].flags & SLOT_FREE)) { continue; } @@ -3787,7 +3785,7 @@ void Vehicle::DriverUse(Event *ev) } } else { for (slot = 0; slot < MAX_TURRETS; slot++) { - if (!(Turrets[0].flags & SLOT_BUSY)) { + if (!(Turrets[slot].flags & SLOT_BUSY)) { continue; } @@ -6507,11 +6505,11 @@ void Vehicle::Archive(Archiver& arc) driver.Archive(arc); lastdriver.Archive(arc); - for (int i = MAX_PASSENGERS - 1; i >= 0; i--) { + for (int i = 0; i < MAX_PASSENGERS; i++) { Passengers[i].Archive(arc); } - for (int i = MAX_TURRETS - 1; i >= 0; i--) { + for (int i = 0; i < MAX_TURRETS; i++) { Turrets[i].Archive(arc); } From 2bf1144a14af9e5e5ff5c70c9a8460f1f55b45e1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:43:56 +0200 Subject: [PATCH 0312/2040] Removed unused source files --- code/fgame/g_bot.cpp | 49 +- cross-make-mingw.sh | 6 - make-macosx-ub.sh | 232 -- misc/build_increment.bat | 14 - misc/setup/MacOSX/SLA-dmg.sh | 73 - misc/setup/Makefile | 15 - misc/setup/Solaris_pkg.sh | 135 -- misc/setup/doit | 112 - misc/setup/ioq3demo.sh | 50 - misc/setup/ioquake3.SlackBuild | 77 - misc/setup/ioquake3.sh | 50 - misc/setup/pkg/ioq3ded.sh | 41 - misc/setup/pkg/ioquake3.sh | 41 - misc/setup/pkg/ioquake3/depend | 3 - misc/setup/pkg/ioquake3/pkginfo.template | 12 - misc/setup/pkg/ioquake3/postinstall | 21 - misc/setup/pkg/ioquake3/postremove | 21 - misc/setup/pkg/ioquake3/preinstall | 10 - misc/setup/pkg/ioquake3/preremove | 10 - misc/setup/pkg/ioquake3/prototype.template | 8 - misc/setup/pkg/ioquake3/space | 1 - misc/setup/pkg/ioquake3d/depend | 2 - misc/setup/pkg/ioquake3d/pkginfo.template | 12 - misc/setup/pkg/ioquake3d/postinstall | 10 - misc/setup/pkg/ioquake3d/postremove | 10 - misc/setup/pkg/ioquake3d/preinstall | 10 - misc/setup/pkg/ioquake3d/preremove | 10 - misc/setup/pkg/ioquake3d/prototype.template | 7 - misc/setup/pkg/ioquake3d/space | 1 - misc/setup/preuninstall.sh | 2 - misc/setup/setup.xml.in | 111 - misc/setup/slack-desc | 12 - misc/setup/splash.xpm | 2289 ------------------- 33 files changed, 43 insertions(+), 3414 deletions(-) delete mode 100644 cross-make-mingw.sh delete mode 100644 make-macosx-ub.sh delete mode 100644 misc/build_increment.bat delete mode 100644 misc/setup/MacOSX/SLA-dmg.sh delete mode 100644 misc/setup/Makefile delete mode 100644 misc/setup/Solaris_pkg.sh delete mode 100644 misc/setup/doit delete mode 100644 misc/setup/ioq3demo.sh delete mode 100644 misc/setup/ioquake3.SlackBuild delete mode 100644 misc/setup/ioquake3.sh delete mode 100644 misc/setup/pkg/ioq3ded.sh delete mode 100644 misc/setup/pkg/ioquake3.sh delete mode 100644 misc/setup/pkg/ioquake3/depend delete mode 100644 misc/setup/pkg/ioquake3/pkginfo.template delete mode 100644 misc/setup/pkg/ioquake3/postinstall delete mode 100644 misc/setup/pkg/ioquake3/postremove delete mode 100644 misc/setup/pkg/ioquake3/preinstall delete mode 100644 misc/setup/pkg/ioquake3/preremove delete mode 100644 misc/setup/pkg/ioquake3/prototype.template delete mode 100644 misc/setup/pkg/ioquake3/space delete mode 100644 misc/setup/pkg/ioquake3d/depend delete mode 100644 misc/setup/pkg/ioquake3d/pkginfo.template delete mode 100644 misc/setup/pkg/ioquake3d/postinstall delete mode 100644 misc/setup/pkg/ioquake3d/postremove delete mode 100644 misc/setup/pkg/ioquake3d/preinstall delete mode 100644 misc/setup/pkg/ioquake3d/preremove delete mode 100644 misc/setup/pkg/ioquake3d/prototype.template delete mode 100644 misc/setup/pkg/ioquake3d/space delete mode 100644 misc/setup/preuninstall.sh delete mode 100644 misc/setup/setup.xml.in delete mode 100644 misc/setup/slack-desc delete mode 100644 misc/setup/splash.xpm diff --git a/code/fgame/g_bot.cpp b/code/fgame/g_bot.cpp index 0942f0ce..a885390c 100644 --- a/code/fgame/g_bot.cpp +++ b/code/fgame/g_bot.cpp @@ -172,11 +172,11 @@ void G_AddBot(unsigned int num, saved_bot_t* saved) void G_RemoveBot(unsigned int num) { - num = Q_min(atoi(gi.Argv(1)), sv_maxbots->integer); + num = Q_min(num, sv_maxbots->integer); for( int n = 0; n < num; n++ ) { - gentity_t *e = &g_entities[ game.maxclients - 1 - n ]; + gentity_t *e = &g_entities[maxclients->integer + n]; if( e->inuse && e->client ) { G_ClientDisconnect( e ); @@ -230,6 +230,27 @@ void G_RestoreBots() { saved_bots = NULL; } +int G_CountClients() { + gentity_t* other; + unsigned int n; + unsigned int count = 0; + + for (n = 0; n < maxclients->integer; n++) { + other = &g_entities[n]; + if (other->inuse && other->client) { + Player* p = static_cast(other->entity); + if (p->GetTeam() == teamtype_t::TEAM_NONE || p->GetTeam() == teamtype_t::TEAM_SPECTATOR) { + // ignore spectators + continue; + } + + count++; + } + } + + return count; +} + void G_ResetBots() { G_SaveBots(); @@ -237,13 +258,29 @@ void G_ResetBots() { } void G_SpawnBots() { + unsigned int numClients; + unsigned int numBotsToSpawn; + if (saved_bots) { G_RestoreBots(); } - if (sv_numbots->integer > current_bot_count) { - G_AddBot(sv_numbots->integer - current_bot_count); - } else if (sv_numbots->integer < current_bot_count) { - G_RemoveBot(current_bot_count - sv_numbots->integer); + // + // Check the minimum bot count + // + numClients = G_CountClients() + sv_numbots->integer; + if (numClients < sv_minPlayers->integer) { + numBotsToSpawn = sv_minPlayers->integer - numClients; + } else { + numBotsToSpawn = sv_numbots->integer; + } + + // + // Spawn bots + // + if (numBotsToSpawn > current_bot_count) { + G_AddBot(numBotsToSpawn - current_bot_count); + } else if (numBotsToSpawn < current_bot_count) { + G_RemoveBot(current_bot_count - numBotsToSpawn); } } diff --git a/cross-make-mingw.sh b/cross-make-mingw.sh deleted file mode 100644 index c6dbe377..00000000 --- a/cross-make-mingw.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -export CC=i586-mingw32msvc-gcc -export WINDRES=i586-mingw32msvc-windres -export PLATFORM=mingw32 -exec make $* diff --git a/make-macosx-ub.sh b/make-macosx-ub.sh deleted file mode 100644 index a7833e2d..00000000 --- a/make-macosx-ub.sh +++ /dev/null @@ -1,232 +0,0 @@ -#!/bin/sh -APPBUNDLE=openmohaa.app -BINARY=openmohaa.ub -DEDBIN=omohaaded.ub -PKGINFO=APPLOMOHAA -ICNS=misc/openmohaa.icns -DESTDIR=build/release-darwin-ub -BASEDIR=main -MPACKDIR=missionpack -Q3_VERSION=`grep "\#define Q3_VERSION" code/qcommon/q_shared.h | \ - sed -e 's/.*".* \([^ ]*\)"/\1/'`; - -BIN_OBJ=" - build/release-darwin-ppc/openmohaa-smp.ppc - build/release-darwin-i386/openmohaa-smp.i386 -" -BIN_DEDOBJ=" - build/release-darwin-ub/omohaaded.ppc - build/release-darwin-i386/omohaaded.i386 -" -BASE_OBJ=" - build/release-darwin-ppc/$BASEDIR/cgameppc.dylib - build/release-darwin-i386/$BASEDIR/cgamei386.dylib - build/release-darwin-ppc/$BASEDIR/uippc.dylib - build/release-darwin-i386/$BASEDIR/uii386.dylib - build/release-darwin-ppc/$BASEDIR/qagameppc.dylib - build/release-darwin-i386/$BASEDIR/qagamei386.dylib -" -MPACK_OBJ=" - build/release-darwin-ppc/$MPACKDIR/cgameppc.dylib - build/release-darwin-i386/$MPACKDIR/cgamei386.dylib - build/release-darwin-ppc/$MPACKDIR/uippc.dylib - build/release-darwin-i386/$MPACKDIR/uii386.dylib - build/release-darwin-ppc/$MPACKDIR/qagameppc.dylib - build/release-darwin-i386/$MPACKDIR/qagamei386.dylib -" -if [ ! -f Makefile ]; then - echo "This script must be run from the openmohaa build directory"; -fi - -TIGERHOST=0 -if uname -r | grep ^8. > /dev/null; then - TIGERHOST=1 -fi - -# we want to use the oldest available SDK for max compatiblity -unset PPC_CLIENT_SDK -PPC_CLIENT_CC=gcc -unset PPC_CLIENT_CFLAGS -unset PPC_CLIENT_LDFLAGS -unset PPC_SERVER_SDK -unset PPC_SERVER_CFLAGS -unset PPC_SERVER_LDFLAGS -unset X86_SDK -unset X86_CFLAGS -unset X86_LDFLAGS -if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then - PPC_CLIENT_SDK=/Developer/SDKs/MacOSX10.5.sdk - PPC_CLIENT_CC=gcc-4.0 - PPC_CLIENT_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - PPC_CLIENT_LDFLAGS="-arch ppc \ - -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -mmacosx-version-min=10.5" - PPC_SERVER_SDK=/Developer/SDKs/MacOSX10.5.sdk - PPC_SERVER_CFLAGS=$PPC_CLIENT_CFLAGS - PPC_SERVER_LDFLAGS=$PPC_CLIENT_LDFLAGS - - X86_SDK=/Developer/SDKs/MacOSX10.5.sdk - X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - X86_LDFLAGS="-arch i386 \ - -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -mmacosx-version-min=10.5" - X86_ENV="CFLAGS=$CFLAGS LDFLAGS=$LDFLAGS" -fi - -if [ -d /Developer/SDKs/MacOSX10.4u.sdk ]; then - PPC_CLIENT_SDK=/Developer/SDKs/MacOSX10.4u.sdk - PPC_CLIENT_CC=gcc-4.0 - PPC_CLIENT_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1040" - PPC_CLIENT_LDFLAGS="-arch ppc \ - -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ - -mmacosx-version-min=10.4" - PPC_SERVER_SDK=/Developer/SDKs/MacOSX10.4u.sdk - PPC_SERVER_CFLAGS=$PPC_CLIENT_CFLAGS - PPC_SERVER_LDFLAGS=$PPC_CLIENT_LDFLAGS - - X86_SDK=/Developer/SDKs/MacOSX10.4u.sdk - X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1040" - X86_LDFLAGS="-arch i386 \ - -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ - -mmacosx-version-min=10.4" - X86_ENV="CFLAGS=$CFLAGS LDFLAGS=$LDFLAGS" -fi - -if [ -d /Developer/SDKs/MacOSX10.3.9.sdk ] && [ $TIGERHOST ]; then - PPC_CLIENT_SDK=/Developer/SDKs/MacOSX10.3.9.sdk - PPC_CLIENT_CC=gcc-4.0 - PPC_CLIENT_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.3.9.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1030" - PPC_CLIENT_LDFLAGS="-arch ppc \ - -isysroot /Developer/SDKs/MacOSX10.3.9.sdk \ - -mmacosx-version-min=10.3" - PPC_SERVER_SDK=/Developer/SDKs/MacOSX10.3.9.sdk - PPC_SERVER_CFLAGS=$PPC_CLIENT_CFLAGS - PPC_SERVER_LDFLAGS=$PPC_CLIENT_LDFLAGS -fi - -if [ -d /Developer/SDKs/MacOSX10.2.8.sdk ] && [ -x /usr/bin/gcc-3.3 ] && [ $TIGERHOST ]; then - PPC_CLIENT_SDK=/Developer/SDKs/MacOSX10.2.8.sdk - PPC_CLIENT_CC=gcc-3.3 - PPC_CLIENT_CFLAGS="-arch ppc \ - -nostdinc \ - -F/Developer/SDKs/MacOSX10.2.8.sdk/System/Library/Frameworks \ - -I/Developer/SDKs/MacOSX10.2.8.sdk/usr/include/gcc/darwin/3.3 \ - -isystem /Developer/SDKs/MacOSX10.2.8.sdk/usr/include \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1020" - PPC_CLIENT_LDFLAGS="-arch ppc \ - -L/Developer/SDKs/MacOSX10.2.8.sdk/usr/lib/gcc/darwin/3.3 \ - -F/Developer/SDKs/MacOSX10.2.8.sdk/System/Library/Frameworks \ - -Wl,-syslibroot,/Developer/SDKs/MacOSX10.2.8.sdk,-m" -fi - -echo "Building PPC Dedicated Server against \"$PPC_SERVER_SDK\"" -echo "Building PPC Client against \"$PPC_CLIENT_SDK\"" -echo "Building X86 Client/Dedicated Server against \"$X86_SDK\"" -if [ "$PPC_CLIENT_SDK" != "/Developer/SDKs/MacOSX10.2.8.sdk" ] || \ - [ "$PPC_SERVER_SDK" != "/Developer/SDKs/MacOSX10.3.9.sdk" ] || \ - [ "$X86_SDK" != "/Developer/SDKs/MacOSX10.4u.sdk" ]; then - echo "\ -WARNING: in order to build a binary with maximum compatibility you must - build on Mac OS X 10.4 using Xcode 2.3 or 2.5 and have the - MacOSX10.2.8, MacOSX10.3.9, and MacOSX10.4u SDKs installed - from the Xcode install disk Packages folder." -fi - -if [ -z $PPC_CLIENT_SDK ] || [ -z $PPC_SERVER_SDK ] || [ -z $X86_SDK ]; then - echo "\ -ERROR: This script is for building a Universal Binary. You cannot build - for a different architecture unless you have the proper Mac OS X SDKs - installed. If you just want to to compile for your own system run - 'make' instead of this script." - exit 1 -fi -sleep 3 - -if [ ! -d $DESTDIR ]; then - mkdir -p $DESTDIR -fi - -# ppc dedicated server -echo "Building Dedicated Server using $PPC_SERVER_SDK" -sleep 2 -if [ -d build/release-darwin-ppc ]; then - rm -r build/release-darwin-ppc -fi -(ARCH=ppc BUILD_CLIENT_SMP=0 BUILD_CLIENT=0 BUILD_GAME_VM=0 BUILD_GAME_SO=0 \ - CFLAGS=$PPC_SERVER_CFLAGS LDFLAGS=$PPC_SERVER_LDFLAGS make) || exit 1; -cp build/release-darwin-ppc/omohaaded.ppc $DESTDIR - -# ppc client -if [ -d build/release-darwin-ppc ]; then - rm -r build/release-darwin-ppc -fi -(ARCH=ppc USE_OPENAL_DLOPEN=1 BUILD_SERVER=0 CC=$PPC_CLIENT_CC \ - CFLAGS=$PPC_CLIENT_CFLAGS LDFLAGS=$PPC_CLIENT_LDFLAGS make) || exit 1; - -# intel client and server -if [ -d build/release-darwin-i386 ]; then - rm -r build/release-darwin-i386 -fi -(ARCH=i386 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make) || exit 1; - -echo "Creating .app bundle $DESTDIR/$APPBUNDLE" -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR || exit 1; -fi -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR || exit 1; -fi -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/Resources ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/Resources -fi -cp $ICNS $DESTDIR/$APPBUNDLE/Contents/Resources/openmohaa.icns || exit 1; -echo $PKGINFO > $DESTDIR/$APPBUNDLE/Contents/PkgInfo -echo " - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - $BINARY - CFBundleGetInfoString - openmohaa $Q3_VERSION - CFBundleIconFile - openmohaa.icns - CFBundleIdentifier - org.icculus.quake3 - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - opemohaa - CFBundlePackageType - APPL - CFBundleShortVersionString - $Q3_VERSION - CFBundleSignature - $PKGINFO - CFBundleVersion - $Q3_VERSION - NSExtensions - - NSPrincipalClass - NSApplication - - - " > $DESTDIR/$APPBUNDLE/Contents/Info.plist - -lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$BINARY $BIN_OBJ -lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$DEDBIN $BIN_DEDOBJ -rm $DESTDIR/omohaaded.ppc -cp $BASE_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR/ -cp $MPACK_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR/ -cp code/libs/macosx/*.dylib $DESTDIR/$APPBUNDLE/Contents/MacOS/ - diff --git a/misc/build_increment.bat b/misc/build_increment.bat deleted file mode 100644 index a0c38aaf..00000000 --- a/misc/build_increment.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off - -set BUILD= - -IF EXIST %1.txt ( - set /p BUILD=<%1.txt -) ELSE ( - set BUILD=0 -) - -set /a BUILD=%BUILD%+1 -@echo %BUILD% >%1.txt - -echo Successfully wrote build number to %1.txt. \ No newline at end of file diff --git a/misc/setup/MacOSX/SLA-dmg.sh b/misc/setup/MacOSX/SLA-dmg.sh deleted file mode 100644 index af268f32..00000000 --- a/misc/setup/MacOSX/SLA-dmg.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# -# This script appends the text from Q3A_EULA.txt to a .dmg as a SLA resource -# -# usage is './SLA-dmg.sh /path/to/Q3A_EULA.txt /path/to/ioquake3.dmg' -# - -if [ "x$1" = "x" ] || [ "x$2" = "x" ]; then - echo "usage: ./SLA-dmg.sh /path/to/Q3A_EULA.txt /path/to/ioquake3.dmg" - exit 1; -fi - -if [ ! -r $1 ]; then - echo "$1 is not a readable Q3A_EULA.txt file" - exit 1; -fi -if [ ! -w $2 ]; then - echo "$2 is not writable .dmg file" - exit 1; -fi -touch tmp.r -if [ ! -w tmp.r ]; then - echo "Could not create temporary file tmp.r for writing" - exit 1; -fi - -echo " -data 'LPic' (5000) { - \$\"0002 0011 0003 0001 0000 0000 0002 0000\" - \$\"0008 0003 0000 0001 0004 0000 0004 0005\" - \$\"0000 000E 0006 0001 0005 0007 0000 0007\" - \$\"0008 0000 0047 0009 0000 0034 000A 0001\" - \$\"0035 000B 0001 0020 000C 0000 0011 000D\" - \$\"0000 005B 0004 0000 0033 000F 0001 000C\" - \$\"0010 0000 000B 000E 0000\" -}; - -data 'TEXT' (5002, \"English\") { -" > tmp.r - -sed -e 's/"/\\"/g' -e 's/\(.*\)$/"\1\\n"/g' $1 >> tmp.r - -echo " -}; - -resource 'STR#' (5002, \"English\") { - { - \"English\", - \"Agree\", - \"Disagree\", - \"Print\", - \"Save...\", - \"IMPORTANT - Read this License Agreement carefully before clicking on \" - \"the \\\"Agree\\\" button. By clicking on the \\\"Agree\\\" button, you agree \" - \"to be bound by the terms of the License Agreement.\", - \"Software License Agreement\", - \"This text cannot be saved. This disk may be full or locked, or the \" - \"file may be locked.\", - \"Unable to print. Make sure you have selected a printer.\" - } -}; -" >> tmp.r - -hdiutil convert -format UDCO -o tmp.dmg $2 || exit 1 -hdiutil unflatten tmp.dmg || exit 1 -/Developer/Tools/Rez /Developer/Headers/FlatCarbon/*.r tmp.r -a -o tmp.dmg \ - || exit 1 -hdiutil flatten tmp.dmg || exit 1 -hdiutil internet-enable -yes tmp.dmg || exit 1 -mv tmp.dmg $2 || (echo "Could not copy tmp.dmg to $2" && exit 1) -rm tmp.dmg -rm tmp.r -echo "SLA $1 successfully added to $2" diff --git a/misc/setup/Makefile b/misc/setup/Makefile deleted file mode 100644 index 286831c7..00000000 --- a/misc/setup/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -VERSION=1.34 -RELEASE=svn - -all: - VERSION=$(VERSION) RELEASE=$(RELEASE) ./doit - -sign: - for i in *.run; do \ - gpg -bao $$i.asc $$i; \ - done - -clean: - rm -rf *.run image - -.PHONY: all sign clean diff --git a/misc/setup/Solaris_pkg.sh b/misc/setup/Solaris_pkg.sh deleted file mode 100644 index 6b64201f..00000000 --- a/misc/setup/Solaris_pkg.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/bin/bash - -# Source directory -MOUNT_DIR="../.." - -# Solaris stuff -PLATFORM=`uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'` -if [ "X`uname -m`" = "Xi86pc" ]; then - ARCH=i386 -else - ARCH=sparc -fi - -# Packages -PKG_SOLARIS_NAME=ioquake3 -PKG_DATA_NAME=ioquake3d -BUILD_DATE="`/usr/bin/date '+%Y%m%d%H%M%S'`" -SVNVERSION=/usr/local/bin/svnversion -if [ -x /usr/local/bin/svnversion ]; then - SVN_BANNER=`/usr/local/bin/svnversion ${MOUNT_DIR}|sed -e 's/S$//' -e 's/M$//' ` - BUILD_VERSION="1.34-r${SVN_BANNER}" -else - BUILD_VERSION="1.34-rSVN" -fi -PKG_VERSION="`date '+%Y%m%d%H%M'`" -PKG_MAINT_ID="quake@cojot.name" -SOLARIS_PKGFILE="${PKG_SOLARIS_NAME}-${BUILD_VERSION}-${PKG_VERSION}-${ARCH}.pkg" -DATA_PKGFILE="${PKG_DATA_NAME}-${BUILD_VERSION}-${PKG_VERSION}-${ARCH}.pkg" - -# build directories -BUILD_DIR="${MOUNT_DIR}/build/release-${PLATFORM}-${ARCH}" -PKG_SRC_DIR="${MOUNT_DIR}/misc/setup/pkg/${PKG_SOLARIS_NAME}" -PKG_BUILD_DIR="/tmp/ioquake3-build/${PKG_SOLARIS_NAME}-${BUILD_VERSION}" -PKG_DATA_SRC_DIR="${MOUNT_DIR}/misc/setup/pkg/${PKG_DATA_NAME}" -PKG_DATA_BUILD_DIR="/usr/local/src/quake3-data/quake3" - -# Tools -RM="/usr/bin/rm" -TOUCH="/usr/bin/touch" -SED="/usr/bin/sed" -CAT="/usr/bin/cat" -NAWK="/usr/bin/nawk" -MKDIR="gmkdir -v -p" -INSTALL_BIN="ginstall -D -m 755" -INSTALL_DATA="ginstall -D -m 644" -PKGPROTO="/usr/bin/pkgproto" -PKGMK="/usr/bin/pkgmk" -PKGTRANS="/usr/bin/pkgtrans" - -############################################################################# -# SOLARIS PACKAGE -############################################################################# - -if [ -d ${BUILD_DIR} ]; then - if [ ! -d ${BUILD_DIR}/pkg ]; then - ${MKDIR} ${BUILD_DIR}/pkg - fi - echo "Building ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE}" - ${RM} -f ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE} - ${TOUCH} ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE} - ${SED} -e "/VERSION=/s/.*/VERSION=${BUILD_VERSION}-${PKG_VERSION}/" \ - < ${PKG_SRC_DIR}/pkginfo.template \ - > ${PKG_SRC_DIR}/pkginfo - ${CAT} ${PKG_SRC_DIR}/prototype.template > ${PKG_SRC_DIR}/prototype - - ${INSTALL_DATA} ${MOUNT_DIR}/COPYING.txt ${PKG_SRC_DIR}/copyright - for EXEC_READ in README id-readme.txt - do - if [ -f ${MOUNT_DIR}/${EXEC_READ} ]; then - ${INSTALL_DATA} ${MOUNT_DIR}/${EXEC_READ} ${PKG_BUILD_DIR}/${EXEC_READ} - fi - done - - for EXEC_BIN in ioq3ded ioquake3-smp ioquake3 - do - if [ -f ${BUILD_DIR}/${EXEC_BIN}.${ARCH} ]; then - ${INSTALL_BIN} ${BUILD_DIR}/${EXEC_BIN}.${ARCH} ${PKG_BUILD_DIR}/${EXEC_BIN}.${ARCH} - fi - done - - for EXEC_SH in ioq3ded.sh ioquake3.sh - do - if [ -f ${MOUNT_DIR}/misc/setup/pkg/${EXEC_SH} ]; then - ${INSTALL_BIN} ${MOUNT_DIR}/misc/setup/pkg/${EXEC_SH} ${PKG_BUILD_DIR}/${EXEC_SH} - fi - done - - for EXEC_SO in cgamesparc.so qagamesparc.so uisparc.so - do - if [ -f ${BUILD_DIR}/baseq3/${EXEC_SO} ]; then - ${INSTALL_BIN} ${BUILD_DIR}/baseq3/${EXEC_SO} ${PKG_BUILD_DIR}/baseq3/${EXEC_SO} - fi - if [ -f ${BUILD_DIR}/missionpack/${EXEC_SO} ]; then - ${INSTALL_BIN} ${BUILD_DIR}/missionpack/${EXEC_SO} ${PKG_BUILD_DIR}/missionpack/${EXEC_SO} - fi - done - - ${PKGPROTO} ${PKG_BUILD_DIR}=quake3 | \ - ${NAWK} '{ print $1,$2,$3,$4 }' >> ${PKG_SRC_DIR}/prototype - ${PKGMK} -o -p "${PKG_MAINT_ID}${BUILD_DATE}" \ - -b ${PKG_SRC_DIR} -f ${PKG_SRC_DIR}/prototype \ - -d /tmp -a ${ARCH} owner=root group=bin mode=0755 - ${PKGTRANS} -s /tmp ${BUILD_DIR}/pkg/${SOLARIS_PKGFILE} ${PKG_SOLARIS_NAME} - - echo "Building ${BUILD_DIR}/pkg/${DATA_PKGFILE}" - ${RM} -f ${BUILD_DIR}/pkg/${DATA_PKGFILE} - ${TOUCH} ${BUILD_DIR}/pkg/${DATA_PKGFILE} - ${SED} -e "/VERSION=/s/.*/VERSION=${BUILD_VERSION}.${PKG_VERSION}/" \ - < ${PKG_DATA_SRC_DIR}/pkginfo.template \ - > ${PKG_DATA_SRC_DIR}/pkginfo - ${CAT} ${PKG_DATA_SRC_DIR}/prototype.template > ${PKG_DATA_SRC_DIR}/prototype - - if [ -d ${MOUNT_DIR}/../webspace/include ]; then - EULA_DIR=${MOUNT_DIR}/../webspace/include - else - if [ -d ${MOUNT_DIR}/../../webspace/include ]; then - EULA_DIR=${MOUNT_DIR}/../../webspace/include - fi - fi - if [ -f ${EULA_DIR}/id_patch_pk3s_Q3A_EULA.txt ]; then - ${INSTALL_DATA} ${EULA_DIR}/id_patch_pk3s_Q3A_EULA.txt ${PKG_DATA_SRC_DIR}/copyright - fi - - ${PKGPROTO} ${PKG_DATA_BUILD_DIR}=quake3 | \ - ${NAWK} '{ print $1,$2,$3,$4 }' >> ${PKG_DATA_SRC_DIR}/prototype - ${PKGMK} -o -p "${PKG_MAINT_ID}${BUILD_DATE}" \ - -b ${PKG_DATA_SRC_DIR} -f ${PKG_DATA_SRC_DIR}/prototype \ - -d /tmp -a ${ARCH} owner=root group=bin mode=0755 - ${PKGTRANS} -s /tmp ${BUILD_DIR}/pkg/${DATA_PKGFILE} ${PKG_DATA_NAME} -else - echo "Directory ${BUILD_DIR} not found!" - exit 1 -fi - - diff --git a/misc/setup/doit b/misc/setup/doit deleted file mode 100644 index 834cff90..00000000 --- a/misc/setup/doit +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash - -: ${MAKESELF:=/usr/share/loki-setup/makeself} -: ${SETUPIMAGE:=/usr/share/loki-setup/image} - -: ${VERSION:=0.0_`date +%Y%m%d%H%M`} -: ${RELEASE:=0} - -set -e -set -x - -shopt -s nullglob - -rm -rf image -mkdir image - -### loki-setup files -cp -a $SETUPIMAGE/{setup.data,setup.sh} image/ - -### splash -rm -f image/setup.data/splash.xpm -[ -e splash.xpm ] && cp splash.xpm image/setup.data/splash.xpm -rm -f image/quake3.png -cp ../quake3.png image/quake3.png - -### binaries -topdir="../.." - -echo "changequote(\`[', \`]')dnl" > defines.m4 -echo "define(VERSION,$VERSION)dnl" >> defines.m4 - -copystartscript() -{ - local arch="$1" - mkdir -p image/bin/Linux/$arch - if [ "$arch" = x86_64 ]; then - ln -s x86_64 image/bin/Linux/amd64 - fi - install -m 755 ioquake3.sh image/bin/Linux/$arch/ioquake3 - install -m 755 ioq3demo.sh image/bin/Linux/$arch/ioq3demo -} - -archs=() -for arch in $topdir/build/release-*; do - arch=${arch##*-} - case "$arch" in - i386) echo "define(HAVE_I386,yes)dnl" >> defines.m4 - copystartscript x86 - ;; - x86_64) echo "define(HAVE_X86_64,yes)dnl" >> defines.m4 - copystartscript $arch - ;; - ppc) echo "define(HAVE_PPC,yes)dnl" >> defines.m4 - copystartscript $arch - ;; - *) - echo "architecture $arch unsupported" - continue; - ;; - esac - archs[${#archs[@]}]=$arch -done - -for arch in "${archs[@]}"; do - dst=image/tmp - mkdir $dst - mkdir $dst/baseq3 $dst/demoq3 $dst/missionpack - install -m 755 $topdir/build/release-linux-$arch/ioquake3.$arch $dst/ioquake3.$arch - install -m 755 $topdir/build/release-linux-$arch/ioq3ded.$arch $dst/ioq3ded.$arch - install -m 644 $topdir/build/release-linux-$arch/baseq3/*.so $dst/baseq3 - install -m 644 $topdir/build/release-linux-$arch/missionpack/*.so $dst/missionpack - for i in cgame qagame ui; do - ln -s ../baseq3/$i$arch.so $dst/demoq3 - done - - tar --owner=root --group=root -C $dst -cf ./image/ioquake3.$arch.tar . - rm -rf ./image/tmp -done - -# patch pk3 files -if [ -e ./idpatchpk3s.tar -a -e ./idtapatchpk3s.tar ]; then - install -m 644 ./idpatchpk3s.tar image/idpatchpk3s.tar - install -m 644 ./idtapatchpk3s.tar image/idtapatchpk3s.tar - install -m 644 ./id_patch_pk3s_Q3A_EULA.txt image/id_patch_pk3s_Q3A_EULA.txt - echo "define(HAVE_PATCHPK3,yes)dnl" >> defines.m4 -elif [ -e quake3-latest-pk3s.zip ]; then - unzip quake3-latest-pk3s.zip - chmod 644 quake3-latest-pk3s/*/*.pk3 - tar -C quake3-latest-pk3s/baseq3 -cf image/idpatchpk3s.tar . - tar -C quake3-latest-pk3s/missionpack -cf image/idtapatchpk3s.tar . - rm -r quake3-latest-pk3s - install -m 644 id_patch_pk3s_Q3A_EULA.txt image/id_patch_pk3s_Q3A_EULA.txt - echo "define(HAVE_PATCHPK3,yes)dnl" >> defines.m4 -fi - -### uninstall script -install -m 755 ./preuninstall.sh image/preuninstall.sh - - -### README, COPYING and EULA -install -m 644 $topdir/README image/README -install -m 644 $topdir/COPYING.txt image/COPYING - -# create setup.xml -m4 defines.m4 setup.xml.in > image/setup.data/setup.xml - -### makeself installer -ARCH= -if [ "${#archs[@]}" -eq 1 ]; then - ARCH=.$arch -fi -$MAKESELF/makeself.sh image ioquake3-$VERSION-$RELEASE$ARCH.run "ioquake3 $VERSION-$RELEASE" ./setup.sh diff --git a/misc/setup/ioq3demo.sh b/misc/setup/ioq3demo.sh deleted file mode 100644 index 05df7ff8..00000000 --- a/misc/setup/ioq3demo.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -readlink() { - local path=$1 ll - - if [ -L "$path" ]; then - ll="$(LC_ALL=C ls -l "$path" 2> /dev/null)" && - echo "${ll/* -> }" - else - return 1 - fi -} - -script=$0 -count=0 -while [ -L "$script" ] -do - script=$(readlink "$script") - count=`expr $count + 1` - if [ $count -gt 100 ] - then - echo "Too many symbolic links" - exit 1 - fi -done -cd "`dirname $script`" - - -lib=lib -test -e lib64 && lib=lib64 - -if test "x$LD_LIBRARY_PATH" = x; then - LD_LIBRARY_PATH="`pwd`/$lib" -else - LD_LIBRARY_PATH="`pwd`/$lib:$LD_LIBRARY_PATH" -fi -export LD_LIBRARY_PATH - -archs=`uname -m` -case "$archs" in - i?86) archs=i386 ;; - x86_64) archs="x86_64 i386" ;; - ppc64) archs="ppc64 ppc" ;; -esac - -for arch in $archs; do - test -x ./ioquake3.$arch || continue - exec ./ioquake3.$arch +set sv_pure 0 +set vm_cgame 0 +set vm_game 0 +set vm_ui 0 +set fs_game demoq3 "$@" -done -echo "could not execute ioquake3" >&2 diff --git a/misc/setup/ioquake3.SlackBuild b/misc/setup/ioquake3.SlackBuild deleted file mode 100644 index af261b72..00000000 --- a/misc/setup/ioquake3.SlackBuild +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh - -CWD=`pwd` -BASE=$CWD/../.. -if [ "$TMP" = "" ]; then - TMP=/tmp -fi - -# clean, update -make -C $BASE clean || exit 1 -svn up $BASE || exit 1 - -# extract version info -VERSION=`grep "\#define *PRODUCT_VERSION" $BASE/code/qcommon/q_shared.h | \ - sed -e 's/[^"]*"\(.*\)"/\1/'` - -SVN_REV=`LANG=C svnversion $BASE` -if [ ! "$SVN_REV" = "" ]; then - VERSION=${VERSION}_SVN${SVN_REV} -fi - -PKG_VERSION=$VERSION - -ARCH=${ARCH:-i586} - -BUILD=${BUILD:-1_io} - -APP=ioquake3 - -PKG=$TMP/package-$APP - -rm -rf $PKG -mkdir -p $PKG - -# build -make -C $BASE release copyfiles COPYDIR="$PKG"/usr/games/$APP|| exit 1 - -# copy additional files -cp $BASE/BUGS $BASE/COPYING.txt $BASE/ChangeLog $BASE/README $PKG/usr/games/$APP/ -cat $CWD/$APP.SlackBuild > $PKG/usr/games/$APP/$APP.SlackBuild - -mkdir -p $PKG/usr/share/$APP/icons -cp $BASE/misc/quake3.png $PKG/usr/share/$APP/icons/ioquake3.png - -mkdir -p $PKG/usr/bin -cat >> $PKG/usr/bin/ioquake3 << EOF -#!/bin/sh -cd /usr/games/$APP/ -./ioquake3.i386 \$* -exit \$? -EOF -chmod 754 $PKG/usr/bin/ioquake3 - -mkdir -p $PKG/usr/bin -cat >> $PKG/usr/bin/ioq3ded << EOF -#!/bin/sh -cd /usr/games/$APP/ -./ioq3ded.i386 \$* -exit \$? -EOF -chmod 754 $PKG/usr/bin/ioq3ded - -mkdir -p $PKG/install -cat $CWD/slack-desc > $PKG/install/slack-desc - -cat >> $PKG/install/doinst.sh << EOF -chmod 754 /usr/games/$APP/*.i386 -chmod 754 /usr/bin/ioquake3 /usr/bin/ioq3ded -EOF -chmod +x $PKG/install/doinst.sh - -pushd $PKG -chown -R root:root install/ || exit 1 -chown -R root:games usr/ || exit 1 -/sbin/makepkg -l y -c n $TMP/$APP-$VERSION-$ARCH-$BUILD.tgz -popd - diff --git a/misc/setup/ioquake3.sh b/misc/setup/ioquake3.sh deleted file mode 100644 index fbef5676..00000000 --- a/misc/setup/ioquake3.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -readlink() { - local path=$1 ll - - if [ -L "$path" ]; then - ll="$(LC_ALL=C ls -l "$path" 2> /dev/null)" && - echo "${ll##* -> }" - else - return 1 - fi -} - -script=$0 -count=0 -while [ -L "$script" ] -do - script=$(readlink "$script") - count=`expr $count + 1` - if [ $count -gt 100 ] - then - echo "Too many symbolic links" - exit 1 - fi -done -cd "`dirname $script`" - - -lib=lib -test -e lib64 && lib=lib64 - -if test "x$LD_LIBRARY_PATH" = x; then - LD_LIBRARY_PATH="`pwd`/$lib" -else - LD_LIBRARY_PATH="`pwd`/$lib:$LD_LIBRARY_PATH" -fi -export LD_LIBRARY_PATH - -archs=`uname -m` -case "$archs" in - i?86) archs=i386 ;; - x86_64) archs="x86_64 i386" ;; - ppc64) archs="ppc64 ppc" ;; -esac - -for arch in $archs; do - test -x ./ioquake3.$arch || continue - exec ./ioquake3.$arch "$@" -done -echo "could not execute ioquake3" >&2 diff --git a/misc/setup/pkg/ioq3ded.sh b/misc/setup/pkg/ioq3ded.sh deleted file mode 100644 index 5f2d7e50..00000000 --- a/misc/setup/pkg/ioq3ded.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Rev: $Id: ioq3ded.sh,v 1.9 2006/01/18 13:47:42 raistlin Exp raistlin $ -# Needed to make symlinks/shortcuts work. -# the binaries must run with correct working directory - -IOQ3_DIR=/usr/local/share/games/quake3 - -COMPILE_PLATFORM=`uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'` -COMPILE_ARCH=`uname -p | sed -e s/i.86/i386/` - -EXEC_REL=release - -# EXEC_BIN=ioquake3.${COMPILE_ARCH} -# EXEC_BIN=ioquake3-smp.${COMPILE_ARCH} -EXEC_BIN=ioq3ded.${COMPILE_ARCH} - -EXEC_FLAGS="+set fs_basepath ${IOQ3_DIR} +set vm_game 1 +set vm_cgame 1 +set vm_ui 1 +set sv_pure 1 +set com_ansiColor 0" - -EXEC_DIR_LIST="${IOQ3_DIR}" - -for d in ${EXEC_DIR_LIST} -do - if [ -d $d ]; then - EXEC_DIR=${d} - break - fi -done - -if [ "X${EXEC_DIR}" != "X" ]; then - if [ ! -x ${EXEC_DIR}/${EXEC_BIN} ]; then - echo "Executable ${EXEC_DIR}/${EXEC_BIN} not found!" ; exit 1 - fi - cd ${IOQ3_DIR} && \ - ${EXEC_DIR}/${EXEC_BIN} ${EXEC_FLAGS} $* - exit $? -else - echo "No ioq3 binaries found!" - exit 1 -fi - - diff --git a/misc/setup/pkg/ioquake3.sh b/misc/setup/pkg/ioquake3.sh deleted file mode 100644 index b2fe7856..00000000 --- a/misc/setup/pkg/ioquake3.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Rev: $Id: ioquake3.sh,v 1.11 2006/01/18 13:47:42 raistlin Exp raistlin $ -# Needed to make symlinks/shortcuts work. -# the binaries must run with correct working directory - -IOQ3_DIR=/usr/local/share/games/quake3 - -COMPILE_PLATFORM=`uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'` -COMPILE_ARCH=`uname -p | sed -e s/i.86/i386/` - -EXEC_REL=release - -EXEC_BIN=ioquake3.${COMPILE_ARCH} -# EXEC_BIN=ioquake3-smp.${COMPILE_ARCH} -# EXEC_BIN=ioq3ded.${COMPILE_ARCH} - -EXEC_FLAGS="+set fs_basepath ${IOQ3_DIR} +set vm_game 1 +set vm_cgame 1 +set vm_ui 1 +set sv_pure 1 +set com_ansiColor 0" - -EXEC_DIR_LIST="${IOQ3_DIR}" - -for d in ${EXEC_DIR_LIST} -do - if [ -d $d ]; then - EXEC_DIR=${d} - break - fi -done - -if [ "X${EXEC_DIR}" != "X" ]; then - if [ ! -x ${EXEC_DIR}/${EXEC_BIN} ]; then - echo "Executable ${EXEC_DIR}/${EXEC_BIN} not found!" ; exit 1 - fi - cd ${IOQ3_DIR} && \ - ${EXEC_DIR}/${EXEC_BIN} ${EXEC_FLAGS} $* - exit $? -else - echo "No ioq3 binaries found!" - exit 1 -fi - - diff --git a/misc/setup/pkg/ioquake3/depend b/misc/setup/pkg/ioquake3/depend deleted file mode 100644 index 11170caf..00000000 --- a/misc/setup/pkg/ioquake3/depend +++ /dev/null @@ -1,3 +0,0 @@ -P SUNWxilrl XIL Runtime Environment -P SFWsdl SDL - Simple DirectMedia Layer library -P ioquake3d Icculus.Org Quake3 game data files for Solaris 10 (X11,GLX,SDL) diff --git a/misc/setup/pkg/ioquake3/pkginfo.template b/misc/setup/pkg/ioquake3/pkginfo.template deleted file mode 100644 index 34d5b1ff..00000000 --- a/misc/setup/pkg/ioquake3/pkginfo.template +++ /dev/null @@ -1,12 +0,0 @@ -CLASSES=none -BASEDIR=/usr/local/share/games -TZ=PST -PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin -PKG=ioquake3 -NAME=ioquake3 1.34 for Solaris 10 (X11,GLX,SDL) -VERSION= -CATEGORY=application,graphics,opengl -DESC=Icculus.Org Quake3 1.34 for Solaris 10 (http://www.ioquake3.org/) -VENDOR=http://www.ioquake3.org/ -EMAIL=quake@cojot.name -PKGSAV=/var/sadm/pkg/ioquake3/save diff --git a/misc/setup/pkg/ioquake3/postinstall b/misc/setup/pkg/ioquake3/postinstall deleted file mode 100644 index 2775d5ee..00000000 --- a/misc/setup/pkg/ioquake3/postinstall +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: postinstall,v 1.3 2006/01/21 12:54:52 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR/quake3 -dest_dir=${PKG_INSTALL_ROOT}/usr/local/bin - -if [ -d ${dest_dir} ]; then - for inst_script in ioq3ded.sh ioquake3.sh - do - dest_script=${dest_dir}/${inst_script} - if [ ! -h ${dest_script} ]; then - ln -s ${quake3_dir}/${inst_script} ${dest_script} - fi - done -fi - -exit 0 - diff --git a/misc/setup/pkg/ioquake3/postremove b/misc/setup/pkg/ioquake3/postremove deleted file mode 100644 index 37690f61..00000000 --- a/misc/setup/pkg/ioquake3/postremove +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# -# @(#)postremove $Id: postremove,v 1.3 2006/01/21 12:54:52 coyote Exp $ -# -# postremove script for quake3 - -quake3_dir=$BASEDIR -dest_dir=${PKG_INSTALL_ROOT}/usr/local/bin - -if [ -d ${dest_dir} ]; then - for inst_script in ioq3ded.sh ioquake3.sh - do - dest_script=${dest_dir}/${inst_script} - if [ -h ${dest_script} ]; then - rm -f ${dest_script} - fi - done -fi - -exit 0 - diff --git a/misc/setup/pkg/ioquake3/preinstall b/misc/setup/pkg/ioquake3/preinstall deleted file mode 100644 index ad126a11..00000000 --- a/misc/setup/pkg/ioquake3/preinstall +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: preinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR - -exit 0 - diff --git a/misc/setup/pkg/ioquake3/preremove b/misc/setup/pkg/ioquake3/preremove deleted file mode 100644 index 3f316f3c..00000000 --- a/misc/setup/pkg/ioquake3/preremove +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: preremove,v 1.2 2006/01/25 13:22:56 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR - -exit 0 - diff --git a/misc/setup/pkg/ioquake3/prototype.template b/misc/setup/pkg/ioquake3/prototype.template deleted file mode 100644 index f23af773..00000000 --- a/misc/setup/pkg/ioquake3/prototype.template +++ /dev/null @@ -1,8 +0,0 @@ -!default 0755 root bin -i pkginfo -i copyright -i depend -i postinstall -i postremove -i preinstall -i preremove diff --git a/misc/setup/pkg/ioquake3/space b/misc/setup/pkg/ioquake3/space deleted file mode 100644 index 95b72949..00000000 --- a/misc/setup/pkg/ioquake3/space +++ /dev/null @@ -1 +0,0 @@ -/usr/local/share 20000 15 diff --git a/misc/setup/pkg/ioquake3d/depend b/misc/setup/pkg/ioquake3d/depend deleted file mode 100644 index b55ff884..00000000 --- a/misc/setup/pkg/ioquake3d/depend +++ /dev/null @@ -1,2 +0,0 @@ -P SUNWxilrl XIL Runtime Environment -P SFWsdl SDL - Simple DirectMedia Layer library diff --git a/misc/setup/pkg/ioquake3d/pkginfo.template b/misc/setup/pkg/ioquake3d/pkginfo.template deleted file mode 100644 index a351c4de..00000000 --- a/misc/setup/pkg/ioquake3d/pkginfo.template +++ /dev/null @@ -1,12 +0,0 @@ -CLASSES=none -BASEDIR=/usr/local/share/games -TZ=PST -PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin -PKG=ioquake3d -NAME=ioquake3 game data files for Solaris 10 (X11,GLX,SDL) -VERSION= -CATEGORY=application,graphics,opengl -DESC=ioquake3 game data files for Solaris 10 (http://www.ioquake3.org/) -VENDOR=http://www.ioquake3.org/ -EMAIL=quake@cojot.name -PKGSAV=/var/sadm/pkg/ioquake3d/save diff --git a/misc/setup/pkg/ioquake3d/postinstall b/misc/setup/pkg/ioquake3d/postinstall deleted file mode 100644 index f116fc3d..00000000 --- a/misc/setup/pkg/ioquake3d/postinstall +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: postinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR - -exit 0 - diff --git a/misc/setup/pkg/ioquake3d/postremove b/misc/setup/pkg/ioquake3d/postremove deleted file mode 100644 index 7614348d..00000000 --- a/misc/setup/pkg/ioquake3d/postremove +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: postremove,v 1.2 2006/01/25 13:22:56 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR - -exit 0 - diff --git a/misc/setup/pkg/ioquake3d/preinstall b/misc/setup/pkg/ioquake3d/preinstall deleted file mode 100644 index ad126a11..00000000 --- a/misc/setup/pkg/ioquake3d/preinstall +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: preinstall,v 1.2 2006/01/25 13:22:56 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR - -exit 0 - diff --git a/misc/setup/pkg/ioquake3d/preremove b/misc/setup/pkg/ioquake3d/preremove deleted file mode 100644 index 3f316f3c..00000000 --- a/misc/setup/pkg/ioquake3d/preremove +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# @(#)postinstall $Id: preremove,v 1.2 2006/01/25 13:22:56 coyote Exp $ -# -# postinstall script for quake3 - -quake3_dir=$BASEDIR - -exit 0 - diff --git a/misc/setup/pkg/ioquake3d/prototype.template b/misc/setup/pkg/ioquake3d/prototype.template deleted file mode 100644 index 26bd06a1..00000000 --- a/misc/setup/pkg/ioquake3d/prototype.template +++ /dev/null @@ -1,7 +0,0 @@ -!default 0755 root bin -i pkginfo -i depend -i postinstall -i postremove -i preinstall -i preremove diff --git a/misc/setup/pkg/ioquake3d/space b/misc/setup/pkg/ioquake3d/space deleted file mode 100644 index a8d224c3..00000000 --- a/misc/setup/pkg/ioquake3d/space +++ /dev/null @@ -1 +0,0 @@ -/usr/local/share 50000 100 diff --git a/misc/setup/preuninstall.sh b/misc/setup/preuninstall.sh deleted file mode 100644 index 49e80564..00000000 --- a/misc/setup/preuninstall.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -rmdir --ignore-fail-on-non-empty demoq3 missionpack >& /dev/null diff --git a/misc/setup/setup.xml.in b/misc/setup/setup.xml.in deleted file mode 100644 index 65dd1b9d..00000000 --- a/misc/setup/setup.xml.in +++ /dev/null @@ -1,111 +0,0 @@ - - - - README - - - -ifelse(HAVE_X86_64,yes,dnl - -)dnl -ifelse(HAVE_I386,yes,dnl - -)dnl -ifelse(HAVE_PPC,yes,dnl - -)dnl - - -ifelse(HAVE_PATCHPK3,yes,dnl - - - - id_patch_pk3s_Q3A_EULA.txt - - - - - - - - - - id_patch_pk3s_Q3A_EULA.txt - - - - - - - - Quake3/baseq3/pak0.pk3 - - - Setup/missionpack/pak0.pk3 - -)dnl - - diff --git a/misc/setup/slack-desc b/misc/setup/slack-desc deleted file mode 100644 index c88b4bcb..00000000 --- a/misc/setup/slack-desc +++ /dev/null @@ -1,12 +0,0 @@ - |-----handy-ruler------------------------------------------------------| -ioquake3: ioquake 3 - An open source Quake 3 distribution -ioquake3: -ioquake3: ioquake3 aims to build upon id Software's Quake 3 source code release. -ioquake3: The source code was released on August 20, 2005 under the GPL. Since -ioquake3: then code has been cleaned up, bugs have been fixed and features been -ioquake3: added. -ioquake3: The permanent goal is to create THE open source Quake 3 distribution -ioquake3: upon which people base their games and projects. -ioquake3: -ioquake3: http://ioquake3.org/ -ioquake3: diff --git a/misc/setup/splash.xpm b/misc/setup/splash.xpm deleted file mode 100644 index 27677676..00000000 --- a/misc/setup/splash.xpm +++ /dev/null @@ -1,2289 +0,0 @@ -/* XPM */ -static char * splash_xpm[] = { -"296 296 1990 2", -" c #999999", -". c #989797", -"+ c #999898", -"@ c #938B8B", -"# c #979494", -"$ c #8D7D7D", -"% c #958F8F", -"& c #887070", -"* c #928989", -"= c #846666", -"- c #8F7F7F", -"; c #815C5C", -"> c #8B7676", -", c #7D5353", -"' c #876C6C", -") c #7A4949", -"! c #846262", -"~ c #764040", -"{ c #805959", -"] c #733636", -"^ c #7D4F4F", -"/ c #702C2C", -"( c #794646", -"_ c #6C2323", -": c #763C3C", -"< c #691919", -"[ c #733232", -"} c #979595", -"| c #671313", -"1 c #6F2929", -"2 c #969090", -"3 c #660E0E", -"4 c #6C1F1F", -"5 c #948B8B", -"6 c #650A0A", -"7 c #691616", -"8 c #928686", -"9 c #640505", -"0 c #660C0C", -"a c #918181", -"b c #630101", -"c c #640303", -"d c #8D7878", -"e c #630000", -"f c #969292", -"g c #8A6E6E", -"h c #640000", -"i c #938888", -"j c #876565", -"k c #907F7F", -"l c #845B5B", -"m c #650000", -"n c #8D7575", -"o c #815252", -"p c #8A6B6B", -"q c #7E4848", -"r c #660000", -"s c #876262", -"t c #7B3E3E", -"u c #670000", -"v c #845858", -"w c #783535", -"x c #814F4F", -"y c #762B2B", -"z c #680000", -"A c #7E4545", -"B c #732222", -"C c #7B3B3B", -"D c #989696", -"E c #711A1A", -"F c #690000", -"G c #793232", -"H c #701313", -"I c #6A0000", -"J c #762828", -"K c #979191", -"L c #6E0C0C", -"M c #731F1F", -"N c #968F8F", -"O c #6C0505", -"P c #6B0000", -"Q c #711515", -"R c #948A8A", -"S c #6F0D0D", -"T c #928080", -"U c #6C0000", -"V c #6F0909", -"W c #8F7777", -"X c #6E0707", -"Y c #958A8A", -"Z c #8C6D6D", -"` c #6D0000", -" . c #6E0404", -".. c #938383", -"+. c #8A6464", -"@. c #6E0202", -"#. c #917C7C", -"$. c #875A5A", -"%. c #6E0000", -"&. c #8F7474", -"*. c #855050", -"=. c #6F0000", -"-. c #8C6B6B", -";. c #824646", -">. c #8A6161", -",. c #803D3D", -"'. c #700000", -"). c #875757", -"!. c #7E3333", -"~. c #854D4D", -"{. c #7C2929", -"]. c #710000", -"^. c #834444", -"/. c #792020", -"(. c #803A3A", -"_. c #781616", -":. c #720000", -"<. c #7E3131", -"[. c #760D0D", -"}. c #730000", -"|. c #7D2727", -"1. c #740303", -"2. c #7A1D1D", -"3. c #979292", -"4. c #740000", -"5. c #791616", -"6. c #999797", -"7. c #958989", -"8. c #781111", -"9. c #937F7F", -"0. c #750000", -"a. c #780C0C", -"b. c #968E8E", -"c. c #917676", -"d. c #770707", -"e. c #8F6B6B", -"f. c #760000", -"g. c #770202", -"h. c #948484", -"i. c #8D6262", -"j. c #770000", -"k. c #937D7D", -"l. c #8B5858", -"m. c #917373", -"n. c #894F4F", -"o. c #780000", -"p. c #8F6A6A", -"q. c #874545", -"r. c #8D6060", -"s. c #853B3B", -"t. c #790000", -"u. c #8B5656", -"v. c #843232", -"w. c #7A0000", -"x. c #8A4D4D", -"y. c #822828", -"z. c #884343", -"A. c #811F1F", -"B. c #7B0000", -"C. c #863A3A", -"D. c #7F1515", -"E. c #843030", -"F. c #7E0D0D", -"G. c #7C0000", -"H. c #832626", -"I. c #989191", -"J. c #7E0909", -"K. c #821F1F", -"L. c #968A8A", -"M. c #7E0707", -"N. c #7D0000", -"O. c #811717", -"P. c #989595", -"Q. c #958383", -"R. c #7E0404", -"S. c #801010", -"T. c #989292", -"U. c #947C7C", -"V. c #7E0202", -"W. c #7E0000", -"X. c #7F0808", -"Y. c #979090", -"Z. c #937474", -"`. c #7F0000", -" + c #7F0202", -".+ c #978E8E", -"++ c #916A6A", -"@+ c #968585", -"#+ c #906161", -"$+ c #800000", -"%+ c #8E5757", -"&+ c #937373", -"*+ c #8D4D4D", -"=+ c #810000", -"-+ c #916969", -";+ c #8C4444", -">+ c #905F5F", -",+ c #8B3A3A", -"'+ c #820000", -")+ c #8F5555", -"!+ c #8A3131", -"~+ c #830000", -"{+ c #8E4C4C", -"]+ c #892727", -"^+ c #8D4343", -"/+ c #881D1D", -"(+ c #840000", -"_+ c #8C3838", -":+ c #871616", -"<+ c #8A2F2F", -"[+ c #871111", -"}+ c #850000", -"|+ c #8A2525", -"1+ c #988E8E", -"2+ c #870C0C", -"3+ c #891C1C", -"4+ c #978989", -"5+ c #870707", -"6+ c #860000", -"7+ c #881212", -"8+ c #968383", -"9+ c #870202", -"0+ c #870000", -"a+ c #880808", -"b+ c #967C7C", -"c+ c #870101", -"d+ c #957373", -"e+ c #880000", -"f+ c #946969", -"g+ c #978585", -"h+ c #935F5F", -"i+ c #890000", -"j+ c #967B7B", -"k+ c #925656", -"l+ c #8A0000", -"m+ c #957171", -"n+ c #914C4C", -"o+ c #946868", -"p+ c #9F9191", -"q+ c #AB7E7E", -"r+ c #BD6262", -"s+ c #CF4848", -"t+ c #DB3636", -"u+ c #E72525", -"v+ c #EB1F1F", -"w+ c #E12C2C", -"x+ c #CD4B4B", -"y+ c #B76C6C", -"z+ c #9E9191", -"A+ c #914343", -"B+ c #8B0000", -"C+ c #945E5E", -"D+ c #AA7F7F", -"E+ c #C15C5C", -"F+ c #D83A3A", -"G+ c #E82222", -"H+ c #E91F1F", -"I+ c #E02D2D", -"J+ c #D43F3F", -"K+ c #C55555", -"L+ c #B47070", -"M+ c #A38989", -"N+ c #9B9595", -"O+ c #9D9292", -"P+ c #B17474", -"Q+ c #CB4D4D", -"R+ c #E32828", -"S+ c #F70B0B", -"T+ c #FE0000", -"U+ c #FC0202", -"V+ c #EE1919", -"W+ c #D34141", -"X+ c #B76B6B", -"Y+ c #903939", -"Z+ c #935555", -"`+ c #9D9494", -" @ c #AD7B7B", -".@ c #C45757", -"+@ c #E12B2B", -"@@ c #F60A0A", -"#@ c #FD0000", -"$@ c #FB0202", -"%@ c #ED1919", -"&@ c #D63B3B", -"*@ c #BD6161", -"=@ c #A58686", -"-@ c #B46F6F", -";@ c #D63C3C", -">@ c #F11313", -",@ c #FD0101", -"'@ c #EE1717", -")@ c #CE4949", -"!@ c #AC7C7C", -"~@ c #902F2F", -"{@ c #8C0000", -"]@ c #924B4B", -"^@ c #A28B8B", -"/@ c #BC6363", -"(@ c #DE2E2E", -"_@ c #F80707", -":@ c #FC0000", -"<@ c #F70707", -"[@ c #E32525", -"}@ c #C45656", -"|@ c #A58787", -"1@ c #CB4C4C", -"2@ c #EE1515", -"3@ c #FB0101", -"4@ c #DD2F2F", -"5@ c #B37070", -"6@ c #9C9494", -"7@ c #8F2626", -"8@ c #924141", -"9@ c #C94E4E", -"0@ c #F11010", -"a@ c #FB0000", -"b@ c #B86969", -"c@ c #9A9898", -"d@ c #AB7D7D", -"e@ c #D73838", -"f@ c #F90404", -"g@ c #F80505", -"h@ c #D53B3B", -"i@ c #A78383", -"j@ c #8F1E1E", -"k@ c #8D0000", -"l@ c #913838", -"m@ c #9C9595", -"n@ c #BC6161", -"o@ c #EB1717", -"p@ c #FA0000", -"q@ c #EB1818", -"r@ c #BE5E5E", -"s@ c #A88181", -"t@ c #D83636", -"u@ c #F80303", -"v@ c #F90101", -"w@ c #DB3131", -"x@ c #999595", -"y@ c #8F1717", -"z@ c #912E2E", -"A@ c #9D9393", -"B@ c #C35656", -"C@ c #EF1010", -"D@ c #F90000", -"E@ c #ED1414", -"F@ c #BD5F5F", -"G@ c #9F9090", -"H@ c #CD4646", -"I@ c #F40808", -"J@ c #EE1111", -"K@ c #B96666", -"L@ c #999292", -"M@ c #8F1010", -"N@ c #8E0000", -"O@ c #912525", -"P@ c #D73535", -"Q@ c #F70101", -"R@ c #F80000", -"S@ c #E32222", -"T@ c #B17272", -"U@ c #EA1717", -"V@ c #D93232", -"W@ c #989090", -"X@ c #900808", -"Y@ c #8F0000", -"Z@ c #911B1B", -"`@ c #9A9797", -" # c #BA6464", -".# c #F10A0A", -"+# c #F70000", -"@# c #F40404", -"## c #CE4343", -"$# c #CD4444", -"%# c #F70202", -"&# c #C55252", -"*# c #988D8D", -"=# c #8F0101", -"-# c #901111", -";# c #A78282", -"># c #E61A1A", -",# c #F60000", -"'# c #E91616", -")# c #AC7A7A", -"!# c #A18B8B", -"~# c #DD2929", -"{# c #F40505", -"]# c #BD5E5E", -"^# c #988585", -"/# c #900000", -"(# c #910B0B", -"_# c #999696", -":# c #A28A8A", -"<# c #E02222", -"[# c #F50000", -"}# c #F00909", -"|# c #B96363", -"1# c #A88080", -"2# c #E71818", -"3# c #F40303", -"4# c #BD5D5D", -"5# c #977B7B", -"6# c #988F8F", -"7# c #A18C8C", -"8# c #E31D1D", -"9# c #F40000", -"0# c #F20303", -"a# c #C74C4C", -"b# c #E91414", -"c# c #F50101", -"d# c #C84B4B", -"e# c #977171", -"f# c #910000", -"g# c #910606", -"h# c #988888", -"i# c #A48787", -"j# c #EC0D0D", -"k# c #F30101", -"l# c #A68383", -"m# c #E91313", -"n# c #DB2B2B", -"o# c #9B9696", -"p# c #966868", -"q# c #910404", -"r# c #988080", -"s# c #B26F6F", -"t# c #F10303", -"u# c #F30000", -"v# c #C44F4F", -"w# c #E11F1F", -"x# c #EF0707", -"y# c #A58585", -"z# c #965E5E", -"A# c #920000", -"B# c #920101", -"C# c #987979", -"D# c #CE3E3E", -"E# c #F20000", -"F# c #F10202", -"G# c #B76565", -"H# c #CE3D3D", -"I# c #C64C4C", -"J# c #965555", -"K# c #930000", -"L# c #A28989", -"M# c #EA0D0D", -"N# c #F10000", -"O# c #A87F7F", -"P# c #B66767", -"Q# c #F00202", -"R# c #EA0C0C", -"S# c #A08C8C", -"T# c #964B4B", -"U# c #976767", -"V# c #C74949", -"W# c #F00000", -"X# c #DC2323", -"Y# c #E31717", -"Z# c #CB4141", -"`# c #964141", -" $ c #940000", -".$ c #975D5D", -"+$ c #A48585", -"@$ c #EC0606", -"#$ c #EF0000", -"$$ c #BA5E5E", -"%$ c #C25050", -"&$ c #EE0202", -"*$ c #AC7777", -"=$ c #963838", -"-$ c #975353", -";$ c #D72929", -">$ c #EE0000", -",$ c #E51010", -"'$ c #9E8F8F", -")$ c #E41212", -"!$ c #962E2E", -"~$ c #950000", -"{$ c #974A4A", -"]$ c #BE5555", -"^$ c #ED0000", -"/$ c #B86060", -"($ c #D23131", -"_$ c #962424", -":$ c #974040", -"<$ c #A97B7B", -"[$ c #EC0000", -"}$ c #DF1919", -"|$ c #D62929", -"1$ c #C34C4C", -"2$ c #971A1A", -"3$ c #960000", -"4$ c #973737", -"5$ c #EA0202", -"6$ c #EB0000", -"7$ c #AB7777", -"8$ c #E90404", -"9$ c #B76161", -"0$ c #971111", -"a$ c #970000", -"b$ c #982D2D", -"c$ c #E11111", -"d$ c #EA0000", -"e$ c #C14D4D", -"f$ c #AD7373", -"g$ c #B16B6B", -"h$ c #970707", -"i$ c #972323", -"j$ c #DA1C1C", -"k$ c #E90000", -"l$ c #D42929", -"m$ c #BC5656", -"n$ c #AE7272", -"o$ c #980101", -"p$ c #980000", -"q$ c #981A1A", -"r$ c #D72323", -"s$ c #DF1313", -"t$ c #C64343", -"u$ c #B46666", -"v$ c #998D8D", -"w$ c #981414", -"x$ c #DC1717", -"y$ c #E80000", -"z$ c #E40808", -"A$ c #A18A8A", -"B$ c #CC3636", -"C$ c #C93D3D", -"D$ c #998383", -"E$ c #990000", -"F$ c #990F0F", -"G$ c #999191", -"H$ c #A38585", -"I$ c #E70101", -"J$ c #E70000", -"K$ c #E60202", -"L$ c #A48383", -"M$ c #CE3232", -"N$ c #E20A0A", -"O$ c #997A7A", -"P$ c #9A0000", -"Q$ c #9A0A0A", -"R$ c #998C8C", -"S$ c #C73E3E", -"T$ c #E60000", -"U$ c #A58181", -"V$ c #CB3535", -"W$ c #D12929", -"X$ c #997070", -"Y$ c #9A0505", -"Z$ c #998787", -"`$ c #AF6B6B", -" % c #E30404", -".% c #E50000", -"+% c #E40202", -"@% c #C34444", -"#% c #E30000", -"$% c #B23434", -"%% c #6A6A6A", -"&% c #626262", -"*% c #717171", -"=% c #8F8F8F", -"-% c #9A6767", -";% c #9B0000", -">% c #9B0101", -",% c #998282", -"'% c #AC7171", -")% c #DF0A0A", -"!% c #E40000", -"~% c #E00909", -"{% c #A08B8B", -"]% c #B46262", -"^% c #BF0000", -"/% c #450000", -"(% c #050000", -"_% c #000000", -":% c #0A0A0A", -"<% c #494949", -"[% c #929292", -"}% c #9A5D5D", -"|% c #997979", -"1% c #B75A5A", -"2% c #E00707", -"3% c #D61B1B", -"4% c #9F8C8C", -"5% c #E20303", -"6% c #AF0000", -"7% c #120000", -"8% c #272727", -"9% c #9A5353", -"0% c #9C0000", -"a% c #9A7070", -"b% c #C73A3A", -"c% c #E10101", -"d% c #E20000", -"e% c #C14545", -"f% c #CB3131", -"g% c #D90000", -"h% c #1B0000", -"i% c #3D3D3D", -"j% c #989898", -"k% c #9B4A4A", -"l% c #9A6666", -"m% c #919191", -"n% c #868686", -"o% c #8E8E8E", -"p% c #878585", -"q% c #9F5858", -"r% c #D40E0E", -"s% c #E10000", -"t% c #DF0404", -"u% c #A77C7C", -"v% c #A87979", -"w% c #E10303", -"x% c #040404", -"y% c #858585", -"z% c #9B4040", -"A% c #9D0000", -"B% c #9B5C5C", -"C% c #575757", -"D% c #434343", -"E% c #7A7A7A", -"F% c #373737", -"G% c #0B0B0B", -"H% c #010000", -"I% c #250000", -"J% c #CE0000", -"K% c #E00000", -"L% c #C93232", -"M% c #C43D3D", -"N% c #480000", -"O% c #742F2F", -"P% c #A77A7A", -"Q% c #9C3636", -"R% c #9B5353", -"S% c #949494", -"T% c #454545", -"U% c #030303", -"V% c #170000", -"W% c #DF0000", -"X% c #DB0808", -"Y% c #A38383", -"Z% c #D51919", -"`% c #360000", -" & c #DF0303", -".& c #D02323", -"+& c #B45E5E", -"@& c #9D9191", -"#& c #9D2C2C", -"$& c #9E0000", -"%& c #9C4949", -"&& c #979797", -"*& c #3A3A3A", -"=& c #080000", -"-& c #DE0000", -";& c #DD0101", -">& c #B55B5B", -",& c #A57F7F", -"'& c #D90D0D", -")& c #4A0000", -"!& c #DA0C0C", -"~& c #C53838", -"{& c #AD6D6D", -"]& c #9E2323", -"^& c #9F0000", -"/& c #9D4040", -"(& c #5E5E5E", -"_& c #010101", -":& c #0F0000", -"<& c #C90000", -"[& c #BF4444", -"}& c #AA7474", -"|& c #DB0606", -"1& c #090000", -"2& c #C60000", -"3& c #D80D0D", -"4& c #C33C3C", -"5& c #AE6B6B", -"6& c #9D8F8F", -"7& c #9E1919", -"8& c #9D3636", -"9& c #959595", -"0& c #0F0F0F", -"a& c #5E0000", -"b& c #DD0000", -"c& c #C63434", -"d& c #AB7070", -"e& c #D70D0D", -"f& c #D70000", -"g& c #DC0000", -"h& c #D80B0B", -"i& c #C83030", -"j& c #B35D5D", -"k& c #9A9696", -"l& c #9F1010", -"m& c #A00000", -"n& c #9E2C2C", -"o& c #040000", -"p& c #1C0000", -"q& c #130000", -"r& c #180000", -"s& c #D50000", -"t& c #C33838", -"u& c #9C9393", -"v& c #D41313", -"w& c #B70000", -"x& c #1D0000", -"y& c #D30000", -"z& c #DA0404", -"A& c #D01A1A", -"B& c #C04040", -"C& c #AE6969", -"D& c #A08989", -"E& c #A00A0A", -"F& c #9B9494", -"G& c #A67A7A", -"H& c #B65555", -"I& c #681E1E", -"J& c #A80000", -"K& c #D00000", -"L& c #D60000", -"M& c #CC0000", -"N& c #B80000", -"O& c #DA0101", -"P& c #BD4444", -"Q& c #A18686", -"R& c #CB2626", -"S& c #DB0000", -"T& c #580000", -"U& c #1A0000", -"V& c #D80707", -"W& c #C13D3D", -"X& c #B16161", -"Y& c #A28484", -"Z& c #9A8E8E", -"`& c #A10808", -" * c #A10000", -".* c #A01C1C", -"+* c #9C9292", -"@* c #AA7171", -"#* c #B94F4F", -"$* c #C82B2B", -"%* c #D50D0D", -"&* c #D90202", -"** c #DA0000", -"=* c #610000", -"-* c #A40707", -";* c #B35C5C", -">* c #BB4B4B", -",* c #D80404", -"'* c #D40000", -")* c #AD0000", -"!* c #D40F0F", -"~* c #C53232", -"{* c #A77979", -"]* c #9A8686", -"^* c #A10505", -"/* c #A01414", -"(* c #999494", -"_* c #A08787", -":* c #AE6666", -"<* c #BD4343", -"[* c #CC2020", -"}* c #D80202", -"|* c #5C0000", -"1* c #786969", -"2* c #A97272", -"3* c #CD1C1C", -"4* c #D40B0B", -"5* c #CB2222", -"6* c #BF3E3E", -"7* c #9B7F7F", -"8* c #A20303", -"9* c #A20000", -"0* c #A10D0D", -"a* c #9B9393", -"b* c #AD6A6A", -"c* c #B94C4C", -"d* c #C42F2F", -"e* c #CF1616", -"f* c #D70202", -"g* c #D80000", -"h* c #5F0000", -"i* c #060000", -"j* c #260000", -"k* c #737373", -"l* c #747474", -"m* c #5D5D5D", -"n* c #605656", -"o* c #791A1A", -"p* c #B60000", -"q* c #D80101", -"r* c #D40A0A", -"s* c #C13838", -"t* c #B55656", -"u* c #9F8989", -"v* c #9B7878", -"w* c #A30101", -"x* c #A30000", -"y* c #A30606", -"z* c #9A8F8F", -"A* c #A47E7E", -"B* c #AE6464", -"C* c #BB4646", -"D* c #C62929", -"E* c #D01212", -"F* c #D60404", -"G* c #C70000", -"H* c #BC0000", -"I* c #3B3B3B", -"J* c #C00000", -"K* c #3C0000", -"L* c #200000", -"M* c #100000", -"N* c #240000", -"O* c #4C0000", -"P* c #D10000", -"Q* c #D70101", -"R* c #D40707", -"S* c #CF1313", -"T* c #C52C2C", -"U* c #BB4545", -"V* c #B15E5E", -"W* c #A77777", -"X* c #9C6F6F", -"Y* c #9A8B8B", -"Z* c #A28383", -"`* c #AC6A6A", -" = c #B65151", -".= c #C03838", -"+= c #CA1F1F", -"@= c #D20B0B", -"#= c #D50303", -"$= c #CB0000", -"%= c #620000", -"&= c #070000", -"*= c #D01010", -"== c #BB4343", -"-= c #B25B5B", -";= c #A87474", -">= c #9F8A8A", -",= c #7C7C7C", -"'= c #6E6E6E", -")= c #6D6D6D", -"!= c #767676", -"~= c #888888", -"{= c #969696", -"]= c #707070", -"^= c #757575", -"/= c #9D6565", -"(= c #A40000", -"_= c #6D5D5D", -":= c #909090", -"<= c #A37F7F", -"[= c #AD6767", -"}= c #B54E4E", -"|= c #B13535", -"1= c #970505", -"2= c #A70000", -"3= c #C10000", -"4= c #D00D0D", -"5= c #1D1717", -"6= c #BB0000", -"7= c #2F0000", -"8= c #020000", -"9= c #560000", -"0= c #CD0000", -"a= c #D50101", -"b= c #CF0E0E", -"c= c #9F1F1F", -"d= c #3A2525", -"e= c #020202", -"f= c #1F1F1F", -"g= c #5F5F5F", -"h= c #8D8D8D", -"i= c #727272", -"j= c #1C1C1C", -"k= c #9D5B5B", -"l= c #090909", -"m= c #313131", -"n= c #797979", -"o= c #323232", -"p= c #9A9595", -"q= c #9E8B8B", -"r= c #A37E7E", -"s= c #AC6969", -"t= c #B45353", -"u= c #BC3E3E", -"v= c #C42828", -"w= c #CB1616", -"x= c #D10707", -"y= c #3F0000", -"z= c #0B0000", -"A= c #350000", -"B= c #B74C4C", -"C= c #1B1B1B", -"D= c #3C3C3C", -"E= c #673D3D", -"F= c #C32F2F", -"G= c #D40202", -"H= c #2B0000", -"I= c #4E0000", -"J= c #2B2B2B", -"K= c #8B8B8B", -"L= c #9F5252", -"M= c #A50000", -"N= c #515151", -"O= c #444444", -"P= c #020101", -"Q= c #8B4C4C", -"R= c #B64F4F", -"S= c #BD3B3B", -"T= c #C52626", -"U= c #CC1414", -"V= c #D00A0A", -"W= c #D40101", -"X= c #CF0000", -"Y= c #CC1313", -"Z= c #B45252", -"`= c #9E8C8C", -" - c #5B5B5B", -".- c #A47C7C", -"+- c #BC3D3D", -"@- c #500000", -"#- c #222121", -"$- c #948686", -"%- c #9F4848", -"&- c #A18383", -"*- c #5B4F4F", -"=- c #2C0000", -"-- c #C80000", -";- c #D20000", -">- c #420000", -",- c #C71E1E", -"'- c #AF5F5F", -")- c #9C9191", -"!- c #9D8E8E", -"~- c #B35555", -"{- c #CA1717", -"]- c #D30101", -"^- c #B50000", -"/- c #5B0000", -"(- c #D00505", -"_- c #CB1515", -":- c #C42626", -"<- c #BE3737", -"[- c #B74848", -"}- c #B15959", -"|- c #AB6A6A", -"1- c #A57979", -"2- c #9F8888", -"3- c #9C9090", -"4- c #8F8888", -"5- c #A13E3E", -"6- c #A60000", -"7- c #777777", -"8- c #493030", -"9- c #AE6161", -"0- c #B45050", -"a- c #BB3F3F", -"b- c #C12E2E", -"c- c #C71D1D", -"d- c #CE0C0C", -"e- c #D20101", -"f- c #030000", -"g- c #BE0000", -"h- c #CF0808", -"i- c #BE3535", -"j- c #A67676", -"k- c #A87070", -"l- c #BD3737", -"m- c #550505", -"n- c #BA0000", -"o- c #BB1111", -"p- c #0F0202", -"q- c #A67474", -"r- c #A28181", -"s- c #A23535", -"t- c #0D0000", -"u- c #2F2F2F", -"v- c #A08585", -"w- c #A47A7A", -"x- c #A96D6D", -"y- c #AD6161", -"z- c #B25353", -"A- c #B84343", -"B- c #6B1F1F", -"C- c #0E0000", -"D- c #AB0000", -"E- c #D00202", -"F- c #C61D1D", -"G- c #B25555", -"H- c #141414", -"I- c #161414", -"J- c #440000", -"K- c #CA0000", -"L- c #1E0000", -"M- c #340000", -"N- c #470000", -"O- c #380000", -"P- c #D10101", -"Q- c #CF0707", -"R- c #CC0D0D", -"S- c #CA1414", -"T- c #C12B2B", -"U- c #BD3838", -"V- c #B74545", -"W- c #B35252", -"X- c #AE5F5F", -"Y- c #A96C6C", -"Z- c #A57878", -"`- c #795F5F", -" ; c #A32B2B", -".; c #390000", -"+; c #371818", -"@; c #353535", -"#; c #363131", -"$; c #392828", -"%; c #311515", -"&; c #080202", -"*; c #090505", -"=; c #B32222", -"-; c #C81717", -";; c #CA1010", -">; c #CC0A0A", -",; c #CF0303", -"'; c #5A0000", -"); c #0A0000", -"!; c #C40000", -"~; c #2A0000", -"{; c #BA3E3E", -"]; c #A57777", -"^; c #7D7D7D", -"/; c #050505", -"(; c #7B7B7B", -"_; c #3E3E3E", -":; c #570000", -"<; c #D00101", -"[; c #9A0202", -"}; c #A52222", -"|; c #A23E3E", -"1; c #C41F1F", -"2; c #CC0808", -"3; c #CD0505", -"4; c #9C0101", -"5; c #C30000", -"6; c #B90000", -"7; c #160000", -"8; c #BC3737", -"9; c #505050", -"0; c #404040", -"a; c #0E0E0E", -"b; c #070707", -"c; c #4D0000", -"d; c #B10000", -"e; c #5D0000", -"f; c #A61919", -"g; c #A33535", -"h; c #C41C1C", -"i; c #210000", -"j; c #CE0101", -"k; c #CA0D0D", -"l; c #BC3535", -"m; c #AB6565", -"n; c #8A8A8A", -"o; c #0B0707", -"p; c #AC4F4F", -"q; c #C22323", -"r; c #CC0707", -"s; c #1F0000", -"t; c #430000", -"u; c #9A9494", -"v; c #A71313", -"w; c #A90000", -"x; c #A42B2B", -"y; c #C22020", -"z; c #590000", -"A; c #540000", -"B; c #3A0000", -"C; c #600000", -"D; c #CD0101", -"E; c #C71313", -"F; c #B93B3B", -"G; c #A86C6C", -"H; c #9F8787", -"I; c #AD5F5F", -"J; c #BC3333", -"K; c #C90D0D", -"L; c #AE0000", -"M; c #BD0000", -"N; c #A80E0E", -"O; c #AA0000", -"P; c #A62222", -"Q; c #BF2626", -"R; c #C50000", -"S; c #3B0000", -"T; c #CB0303", -"U; c #C21F1F", -"V; c #B34A4A", -"W; c #A57676", -"X; c #9B9292", -"Y; c #282828", -"Z; c #3F3F3F", -"`; c #A67272", -" > c #B54848", -".> c #C12020", -"+> c #9D0202", -"@> c #9B8B8B", -"#> c #A90A0A", -"$> c #A71818", -"%> c #BC2E2E", -"&> c #4F3232", -"*> c #9F8686", -"=> c #777171", -"-> c #9B8686", -";> c #AB0404", -">> c #A90E0E", -",> c #BA3535", -"'> c #CA0101", -")> c #5C0303", -"!> c #484848", -"~> c #AC0000", -"{> c #9C8080", -"]> c #AB0101", -"^> c #510000", -"/> c #510404", -"(> c #571C1C", -"_> c #150000", -":> c #C60A0A", -"<> c #BE2323", -"[> c #B24A4A", -"}> c #A57272", -"|> c #494040", -"1> c #101010", -"2> c #1A0606", -"3> c #C21A1A", -"4> c #C90303", -"5> c #9D7979", -"6> c #4B0000", -"7> c #0C0000", -"8> c #C50D0D", -"9> c #BC2A2A", -"0> c #B14D4D", -"a> c #A67171", -"b> c #464646", -"c> c #151515", -"d> c #9E8989", -"e> c #A86969", -"f> c #B44444", -"g> c #BF2121", -"h> c #C70404", -"i> c #9C7F7F", -"j> c #BF0E0E", -"k> c #590101", -"l> c #2D0101", -"m> c #260D0D", -"n> c #231919", -"o> c #212020", -"p> c #202020", -"q> c #414141", -"r> c #A47474", -"s> c #AF5252", -"t> c #9C2E2E", -"u> c #410000", -"v> c #9C8585", -"w> c #AC0404", -"x> c #302020", -"y> c #9F8585", -"z> c #5C5B5B", -"A> c #828282", -"B> c #1D0202", -"C> c #C60404", -"D> c #9B8A8A", -"E> c #AC0808", -"F> c #190000", -"G> c #C60101", -"H> c #C30B0B", -"I> c #BD1F1F", -"J> c #812828", -"K> c #2C2C2C", -"L> c #171616", -"M> c #9F8383", -"N> c #A76868", -"O> c #B04B4B", -"P> c #B82E2E", -"Q> c #C01616", -"R> c #C50303", -"S> c #AC0D0D", -"T> c #C20C0C", -"U> c #BB2222", -"V> c #B43D3D", -"W> c #AB5959", -"X> c #A27878", -"Y> c #9D8C8C", -"Z> c #363636", -"`> c #424242", -" , c #171717", -"., c #9D8B8B", -"+, c #A47171", -"@, c #AC5555", -"#, c #B53838", -"$, c #BD1C1C", -"%, c #C40404", -"&, c #AC1313", -"*, c #2E0000", -"=, c #631515", -"-, c #595959", -";, c #613C3C", -">, c #140000", -",, c #C00E0E", -"', c #B82B2B", -"), c #B04747", -"!, c #A86464", -"~, c #A08080", -"{, c #9B9191", -"], c #4A4A4A", -"^, c #A07F7F", -"/, c #683030", -"(, c #400000", -"_, c #B40000", -":, c #AC1717", -"<, c #A92C2C", -"[, c #A56D6D", -"}, c #550000", -"|, c #9C0707", -"1, c #B92323", -"2, c #B23D3D", -"3, c #AB5858", -"4, c #A47272", -"5, c #121212", -"6, c #5C5C5C", -"7, c #3A1616", -"8, c #B53333", -"9, c #BB1D1D", -"0, c #C20404", -"a, c #AB2020", -"b, c #B00000", -"c, c #A83636", -"d, c #A37474", -"e, c #C20000", -"f, c #230000", -"g, c #700101", -"h, c #050101", -"i, c #7F7F7F", -"j, c #7E7E7E", -"k, c #9B9090", -"l, c #9F8484", -"m, c #A47070", -"n, c #AA5959", -"o, c #B04343", -"p, c #B62C2C", -"q, c #BC1818", -"r, c #B10707", -"s, c #AA2A2A", -"t, c #A64040", -"u, c #A17B7B", -"v, c #4B2525", -"w, c #A76565", -"x, c #A07C7C", -"y, c #5A5757", -"z, c #8F8585", -"A, c #0C0B0B", -"B, c #A93434", -"C, c #A64949", -"D, c #9F8181", -"E, c #C00101", -"F, c #B81F1F", -"G, c #B23838", -"H, c #AD4D4D", -"I, c #603535", -"J, c #0C0C0C", -"K, c #898989", -"L, c #585858", -"M, c #656565", -"N, c #A73D3D", -"O, c #A45353", -"P, c #9E8585", -"Q, c #BF0404", -"R, c #9F8080", -"S, c #838383", -"T, c #A64747", -"U, c #B20000", -"V, c #A35D5D", -"W, c #9D8989", -"X, c #BD0707", -"Y, c #939393", -"Z, c #161616", -"`, c #A55050", -" ' c #B30000", -".' c #A26666", -"+' c #9C8C8C", -"@' c #BB0B0B", -"#' c #BA0F0F", -"$' c #2D2D2D", -"%' c #212121", -"&' c #555555", -"*' c #A45A5A", -"=' c #A07070", -"-' c #9B8F8F", -";' c #BA0E0E", -">' c #B81717", -",' c #606060", -"'' c #262626", -")' c #343434", -"!' c #292929", -"~' c #A26464", -"{' c #320000", -"]' c #9F7A7A", -"^' c #9A9393", -"/' c #B81111", -"(' c #B42525", -"_' c #616161", -":' c #080808", -"<' c #1D1D1D", -"[' c #686868", -"}' c #333333", -"|' c #A16E6E", -"1' c #715D5D", -"2' c #6E6B6B", -"3' c #820F0F", -"4' c #B03434", -"5' c #6F6F6F", -"6' c #878787", -"7' c #676767", -"8' c #131313", -"9' c #111111", -"0' c #9F7777", -"a' c #B50101", -"b' c #220000", -"c' c #AC4343", -"d' c #222222", -"e' c #808080", -"f' c #9E7E7E", -"g' c #B40303", -"h' c #3D0000", -"i' c #A85252", -"j' c #646464", -"k' c #565656", -"l' c #666666", -"m' c #4C4C4C", -"n' c #9D8585", -"o' c #B50505", -"p' c #300000", -"q' c #A46161", -"r' c #8C8C8C", -"s' c #0D0D0D", -"t' c #787878", -"u' c #9B8C8C", -"v' c #B50808", -"w' c #280000", -"x' c #A17070", -"y' c #1A1A1A", -"z' c #4D4D4D", -"A' c #4F4F4F", -"B' c #B50A0A", -"C' c #330000", -"D' c #520000", -"E' c #B60202", -"F' c #9E7D7D", -"G' c #060606", -"H' c #818181", -"I' c #2E2E2E", -"J' c #181818", -"K' c #232323", -"L' c #636363", -"M' c #2A2A2A", -"N' c #6B6B6B", -"O' c #4D2020", -"P' c #3E0000", -"Q' c #353030", -"R' c #B50E0E", -"S' c #3B0D0D", -"T' c #B40606", -"U' c #9C8888", -"V' c #696969", -"W' c #525252", -"X' c #A74E4E", -"Y' c #B40404", -"Z' c #B31818", -"`' c #AF2E2E", -" ) c #A94444", -".) c #B30A0A", -"+) c #A35E5E", -"@) c #B20A0A", -"#) c #9A9191", -"$) c #B22222", -"%) c #AD3838", -"&) c #A74B4B", -"*) c #B11414", -"=) c #A16C6C", -"-) c #B00F0F", -";) c #9A9292", -">) c #B12B2B", -",) c #AC4141", -"') c #A55252", -")) c #AD2323", -"!) c #9E7C7C", -"~) c #AF1414", -"{) c #AF3535", -"]) c #AA4B4B", -"^) c #A35959", -"/) c #AA3232", -"() c #B20101", -"_) c #AE1919", -":) c #AD3F3F", -"<) c #A85555", -"[) c #A26060", -"}) c #A74141", -"|) c #AF0A0A", -"1) c #AC1F1F", -"2) c #AB4949", -"3) c #A65E5E", -"4) c #A16767", -"5) c #A45050", -"6) c #AD1414", -"7) c #AB2424", -"8) c #A95252", -"9) c #A46868", -"0) c #9F6E6E", -"a) c #A15F5F", -"b) c #AA2020", -"c) c #A92B2B", -"d) c #A75C5C", -"e) c #A27171", -"f) c #9E7474", -"g) c #A82E2E", -"h) c #A73232", -"i) c #A56565", -"j) c #9D7A7A", -"k) c #AD0202", -"l) c #9D7D7D", -"m) c #A53D3D", -"n) c #A63939", -"o) c #A36F6F", -"p) c #BD0202", -"q) c #9E8383", -"r) c #AC0303", -"s) c #A34C4C", -"t) c #A44040", -"u) c #A17979", -"v) c #BC0707", -"w) c #9D8888", -"x) c #9B8585", -"y) c #AA0505", -"z) c #A05B5B", -"A) c #A34747", -"B) c #9F8282", -"C) c #BC0B0B", -"D) c #9C8D8D", -"E) c #A90707", -"F) c #A81212", -"G) c #9E6B6B", -"H) c #A14E4E", -"I) c #BB1010", -"J) c #A90808", -"K) c #A62121", -"L) c #9C7A7A", -"M) c #A05555", -"N) c #BB1515", -"O) c #A80A0A", -"P) c #A43030", -"Q) c #A80404", -"R) c #9F5C5C", -"S) c #BE0606", -"T) c #B91C1C", -"U) c #A70D0D", -"V) c #A23F3F", -"W) c #9A8C8C", -"X) c #A60B0B", -"Y) c #9E6363", -"Z) c #BD1010", -"`) c #B72626", -" ! c #A51414", -".! c #A04E4E", -"+! c #A51313", -"@! c #9D6A6A", -"#! c #BA1A1A", -"$! c #B43030", -"%! c #A41B1B", -"&! c #9E5E5E", -"*! c #A41D1D", -"=! c #9C7171", -"-! c #B33A3A", -";! c #A22222", -">! c #9C6D6D", -",! c #A22C2C", -"'! c #9C7878", -")! c #B72C2C", -"!! c #B14343", -"~! c #A12929", -"{! c #9B7C7C", -"]! c #A03B3B", -"^! c #B43737", -"/! c #AE4D4D", -"(! c #A03030", -"_! c #9A8A8A", -":! c #9E4B4B", -"~ c #BB3232", -",~ c #998B8B", -"'~ c #971E1E", -")~ c #984848", -"!~ c #BF2525", -"~~ c #B83B3B", -"{~ c #972D2D", -"]~ c #984F4F", -"^~ c #BD2E2E", -"/~ c #B54545", -"(~ c #950101", -"_~ c #973C3C", -":~ c #975656", -"<~ c #B93838", -"[~ c #B24F4F", -"}~ c #940707", -"|~ c #940B0B", -"1~ c #B74141", -"2~ c #AF5858", -"3~ c #940E0E", -"4~ c #975A5A", -"5~ c #941A1A", -"6~ c #976464", -"7~ c #B44B4B", -"8~ c #AC6262", -"9~ c #941515", -"0~ c #976969", -"a~ c #942929", -"b~ c #976B6B", -"c~ c #B15555", -"d~ c #A96B6B", -"e~ c #931C1C", -"f~ c #977777", -"g~ c #943838", -"h~ c #977272", -"i~ c #AD5E5E", -"j~ c #A67575", -"k~ c #932323", -"l~ c #988383", -"m~ c #954747", -"n~ c #910101", -"o~ c #977979", -"p~ c #AA6868", -"q~ c #A27F7F", -"r~ c #922A2A", -"s~ c #955656", -"t~ c #900202", -"u~ c #977D7D", -"v~ c #A77171", -"w~ c #923131", -"x~ c #900E0E", -"y~ c #966565", -"z~ c #8F0404", -"A~ c #A47B7B", -"B~ c #923838", -"C~ c #901C1C", -"D~ c #967474", -"E~ c #8E0606", -"F~ c #D00303", -"G~ c #923F3F", -"H~ c #902B2B", -"I~ c #978484", -"J~ c #8E0808", -"K~ c #924646", -"L~ c #913A3A", -"M~ c #8C0404", -"N~ c #8D0A0A", -"O~ c #9D8D8D", -"P~ c #CE0B0B", -"Q~ c #CA1616", -"R~ c #924D4D", -"S~ c #924949", -"T~ c #8C1010", -"U~ c #8C0B0B", -"V~ c #CD1010", -"W~ c #C72020", -"X~ c #925454", -"Y~ c #935858", -"Z~ c #8D1B1B", -"`~ c #8C1111", -" { c #C32929", -".{ c #925B5B", -"+{ c #946767", -"@{ c #8D2828", -"#{ c #8C1919", -"${ c #C91C1C", -"%{ c #C03434", -"&{ c #936262", -"*{ c #957777", -"={ c #8E3737", -"-{ c #8B1F1F", -";{ c #978686", -">{ c #8F4646", -",{ c #8C2626", -"'{ c #C22F2F", -"){ c #B94747", -"!{ c #947070", -"~{ c #989494", -"{{ c #915555", -"]{ c #8C2D2D", -"^{ c #BF3939", -"/{ c #B55050", -"({ c #870B0B", -"_{ c #926464", -":{ c #8C3434", -"<{ c #B25A5A", -"[{ c #957E7E", -"}{ c #881A1A", -"|{ c #947373", -"1{ c #8D3B3B", -"2{ c #B84C4C", -"3{ c #AF6464", -"4{ c #8A2929", -"5{ c #968181", -"6{ c #840101", -"7{ c #8D4242", -"8{ c #B45656", -"9{ c #AB6D6D", -"0{ c #978C8C", -"a{ c #8B3838", -"b{ c #840808", -"c{ c #8E4949", -"d{ c #B15F5F", -"e{ c #978F8F", -"f{ c #830404", -"g{ c #8D4747", -"h{ c #841010", -"i{ c #8E5050", -"j{ c #A38181", -"k{ c #830A0A", -"l{ c #8F5757", -"m{ c #851818", -"n{ c #8F5858", -"o{ c #A97373", -"p{ c #916666", -"q{ c #862626", -"r{ c #8F5E5E", -"s{ c #A67B7B", -"t{ c #D70505", -"u{ c #821414", -"v{ c #937575", -"w{ c #883535", -"x{ c #906565", -"y{ c #A38282", -"z{ c #D50C0C", -"A{ c #821919", -"B{ c #958484", -"C{ c #8A4444", -"D{ c #916C6C", -"E{ c #D21414", -"F{ c #831F1F", -"G{ c #7F0505", -"H{ c #8C5353", -"I{ c #927373", -"J{ c #D70909", -"K{ c #CF1B1B", -"L{ c #842424", -"M{ c #8F6262", -"N{ c #937A7A", -"O{ c #D70C0C", -"P{ c #CD2222", -"Q{ c #842B2B", -"R{ c #811B1B", -"S{ c #917171", -"T{ c #948181", -"U{ c #D31414", -"V{ c #C92B2B", -"W{ c #853232", -"X{ c #832828", -"Y{ c #947E7E", -"Z{ c #7C0303", -"`{ c #968888", -" ] c #D01D1D", -".] c #C53535", -"+] c #863939", -"@] c #853737", -"#] c #968989", -"$] c #7B0707", -"%] c #CC2727", -"&] c #C13F3F", -"*] c #864040", -"=] c #884646", -"-] c #7B0A0A", -";] c #C83131", -">] c #BD4949", -",] c #874747", -"'] c #8A5555", -")] c #7C1414", -"!] c #790404", -"~] c #C43A3A", -"{] c #B95252", -"]] c #884E4E", -"^] c #8D6464", -"/] c #7F2424", -"(] c #7A0B0B", -"_] c #C04444", -":] c #B55C5C", -"<] c #895555", -"[] c #907373", -"}] c #823333", -"|] c #7A1313", -"1] c #BC4E4E", -"2] c #B16565", -"3] c #8B5C5C", -"4] c #750101", -"5] c #938181", -"6] c #854242", -"7] c #7B1919", -"8] c #B85757", -"9] c #AC6F6F", -"0] c #8C6363", -"a] c #760808", -"b] c #885151", -"c] c #7C2020", -"d] c #B46161", -"e] c #8D6A6A", -"f] c #771010", -"g] c #8B6161", -"h] c #7D2828", -"i] c #E00101", -"j] c #A48282", -"k] c #8F7171", -"l] c #791818", -"m] c #8E7070", -"n] c #7E2E2E", -"o] c #DF0505", -"p] c #A28787", -"q] c #917878", -"r] c #7C2626", -"s] c #927F7F", -"t] c #7F3535", -"u] c #A67E7E", -"v] c #DE0A0A", -"w] c #803C3C", -"x] c #A18888", -"y] c #DC0F0F", -"z] c #938484", -"A] c #710202", -"B] c #824444", -"C] c #710505", -"D] c #824343", -"E] c #DA1414", -"F] c #948787", -"G] c #710606", -"H] c #865353", -"I] c #741313", -"J] c #834A4A", -"K] c #E30202", -"L] c #D71A1A", -"M] c #958B8B", -"N] c #710A0A", -"O] c #8A6262", -"P] c #782222", -"Q] c #855252", -"R] c #DF0B0B", -"S] c #D32323", -"T] c #710D0D", -"U] c #8E7171", -"V] c #7B3131", -"W] c #865858", -"X] c #DB1515", -"Y] c #CF2D2D", -"Z] c #711010", -"`] c #6D0303", -" ^ c #917E7E", -".^ c #7F4141", -"+^ c #885F5F", -"@^ c #D71F1F", -"#^ c #CA3737", -"$^ c #711414", -"%^ c #6D0707", -"&^ c #948989", -"*^ c #835050", -"=^ c #8A6767", -"-^ c #D32828", -";^ c #C64141", -">^ c #711717", -",^ c #6D0B0B", -"'^ c #875F5F", -")^ c #C14A4A", -"!^ c #721E1E", -"~^ c #701515", -"{^ c #8B6E6E", -"]^ c #8E7474", -"^^ c #C93B3B", -"/^ c #BD5454", -"(^ c #742525", -"_^ c #742424", -":^ c #907D7D", -"<^ c #907C7C", -"[^ c #C44646", -"}^ c #B85E5E", -"|^ c #762C2C", -"1^ c #793434", -"2^ c #670101", -"3^ c #928282", -"4^ c #C04F4F", -"5^ c #B36767", -"6^ c #783333", -"7^ c #7D4343", -"8^ c #969191", -"9^ c #690A0A", -"0^ c #BB5959", -"a^ c #AE7171", -"b^ c #793A3A", -"c^ c #6C1616", -"d^ c #660202", -"e^ c #958E8E", -"f^ c #B66262", -"g^ c #E90101", -"h^ c #AA7979", -"i^ c #7B4141", -"j^ c #866161", -"k^ c #702222", -"l^ c #680808", -"m^ c #B16C6C", -"n^ c #A68080", -"o^ c #7D4848", -"p^ c #8B7070", -"q^ c #680D0D", -"r^ c #AC7676", -"s^ c #E80606", -"t^ c #A28888", -"u^ c #7F4F4F", -"v^ c #793F3F", -"w^ c #691212", -"x^ c #979393", -"y^ c #A77F7F", -"z^ c #E70808", -"A^ c #9F8F8F", -"B^ c #815656", -"C^ c #7E4E4E", -"D^ c #6A1717", -"E^ c #E60B0B", -"F^ c #835D5D", -"G^ c #630505", -"H^ c #6C1D1D", -"I^ c #EB0404", -"J^ c #E31212", -"K^ c #856464", -"L^ c #886C6C", -"M^ c #6D2222", -"N^ c #E70B0B", -"O^ c #DE1C1C", -"P^ c #886B6B", -"Q^ c #6C2222", -"R^ c #8E7B7B", -"S^ c #6E2828", -"T^ c #E41313", -"U^ c #D92525", -"V^ c #8A7272", -"W^ c #713232", -"X^ c #723434", -"Y^ c #E01A1A", -"Z^ c #D52F2F", -"`^ c #8C7878", -" / c #774141", -"./ c #774343", -"+/ c #DC2121", -"@/ c #CF3939", -"#/ c #8E7D7D", -"$/ c #7C5151", -"%/ c #D82A2A", -"&/ c #CA4242", -"*/ c #908383", -"=/ c #846464", -"-/ c #836363", -";/ c #D33434", -">/ c #C54C4C", -",/ c #928888", -"'/ c #8A7474", -")/ c #8C7979", -"!/ c #C05656", -"~/ c #948D8D", -"{/ c #918585", -"]/ c #C84747", -"^/ c #BA5F5F", -"// c #C35050", -"(/ c #B56969", -"_/ c #BE5A5A", -":/ c #B07373", -" ", -" , ' ", -" ) ! ", -" ~ { ", -" ] ^ ", -" / ( ", -" _ : ", -" + < [ ", -" } | 1 ", -" 2 3 4 ", -" 5 6 7 ", -" 8 9 0 ", -" a b c + ", -" d e e f ", -" g h h i ", -" j h h k ", -" l m m n ", -" o m m p ", -" q r r s ", -" t u u v ", -" w u u x ", -" y z z A ", -" + B z z C ", -" D E F F G ", -" # H I I J ", -" K L I I M ", -" N O P P Q ", -" R P P P S + ", -" T U U U V K ", -" W U U U X Y ", -" Z ` ` ` ... ", -" +.` ` ` @.#. ", -" $.%.%.%.%.&. ", -" *.=.=.=.=.-. ", -" ;.=.=.=.=.>. ", -" ,.'.'.'.'.). ", -" !.'.'.'.'.~. ", -" {.].].].].^. ", -" /.].].].].(. ", -" _.:.:.:.:.<. ", -" [.}.}.}.}.|. ", -" 1.}.}.}.}.2. ", -" 3.4.4.4.4.4.5.6. ", -" 7.4.4.4.4.4.8.3. ", -" 9.0.0.0.0.0.a.b. ", -" c.0.0.0.0.0.d.7. ", -" e.f.f.f.f.f.g.h. ", -" i.j.j.j.j.j.j.k. ", -" l.j.j.j.j.j.j.m. ", -" n.o.o.o.o.o.o.p. ", -" q.o.o.o.o.o.o.r. ", -" s.t.t.t.t.t.t.u. ", -" v.w.w.w.w.w.w.x. ", -" y.w.w.w.w.w.w.z. ", -" A.B.B.B.B.B.B.C. ", -" D.B.B.B.B.B.B.E. ", -" + F.G.G.G.G.G.G.H. ", -" I.J.G.G.G.G.G.G.K.6. ", -" L.M.N.N.N.N.N.N.O.P. ", -" Q.R.N.N.N.N.N.N.S.T. ", -" U.V.W.W.W.W.W.W.X.Y. ", -" Z.`.`.`.`.`.`.`. +.+ ", -" ++`.`.`.`.`.`.`.`.@+ ", -" #+$+$+$+$+$+$+$+$+U. ", -" %+$+$+$+$+$+$+$+$+&+ ", -" *+=+=+=+=+=+=+=+=+-+ ", -" ;+=+=+=+=+=+=+=+=+>+ ", -" ,+'+'+'+'+'+'+'+'+)+ ", -" !+~+~+~+~+~+~+~+~+{+ ", -" ]+~+~+~+~+~+~+~+~+^+ ", -" /+(+(+(+(+(+(+(+(+_+ ", -" 6.:+(+(+(+(+(+(+(+(+<+ ", -" T.[+}+}+}+}+}+}+}+}+|+ ", -" 1+2+}+}+}+}+}+}+}+}+3+ ", -" 4+5+6+6+6+6+6+6+6+6+7+ ", -" 8+9+0+0+0+0+0+0+0+0+a+ ", -" b+0+0+0+0+0+0+0+0+0+c+6. ", -" d+e+e+e+e+e+e+e+e+e+e+1+ ", -" f+e+e+e+e+e+e+e+e+e+e+g+ ", -" h+i+i+i+i+i+i+i+i+i+i+j+ ", -" k+l+l+l+l+l+l+l+l+l+l+m+ ", -" n+l+l+l+l+l+l+l+l+l+l+o+ ", -" + p+q+r+s+t+u+v+w+x+y+z+ A+B+B+B+B+B+B+B+B+B+B+C+ + D+E+F+G+H+I+J+K+L+M+N+ ", -" O+P+Q+R+S+T+U+V+W+X+M+ Y+B+B+B+B+B+B+B+B+B+B+Z+ `+ @.@+@@@#@$@%@&@*@=@+ ", -" N+-@;@>@,@#@,@'@)@!@N+ ~@{@{@{@{@{@{@{@{@{@{@]@ ^@/@(@_@:@:@<@[@}@|@ ", -" |@1@2@3@:@:@3@4@5@6@ 7@{@{@{@{@{@{@{@{@{@{@8@ + M+9@0@a@a@a@<@4@b@+ ", -" c@d@e@f@a@a@a@g@h@i@ 6.j@k@k@k@k@k@k@k@k@k@k@l@ m@n@o@p@p@p@p@q@r@z+ ", -" s@t@u@p@p@p@v@w@d@ x@y@k@k@k@k@k@k@k@k@k@k@z@ A@B@C@D@D@D@D@E@F@m@ ", -" G@H@I@D@D@D@D@J@K@+ L@M@N@N@N@N@N@N@N@N@N@N@O@ M+P@Q@R@R@R@R@S@T@ ", -" T@U@R@R@R@R@R@V@M+ W@X@Y@Y@Y@Y@Y@Y@Y@Y@Y@Y@Z@ `@ #.#+#+#+#+#@###O+ ", -" 6@$#%#R@R@R@R@%#&#c@ *#=#Y@Y@Y@Y@Y@Y@Y@Y@Y@Y@-# ;#>#,#,#,#,#,#'#)# ", -" !#~#+#+#+#+#+#{#]# ^#/#/#/#/#/#/#/#/#/#/#/#(#_# :#<#[#[#[#[#[#}#|#c@ ", -" 1#2#,#,#,#,#,#3#4#+ 5#/#/#/#/#/#/#/#/#/#/#/#X@6# 7#8#9#9#9#9#9#0#a#c@ ", -" ;#b#[#[#[#[#[#c#d#+ e#f#f#f#f#f#f#f#f#f#f#f#g#h# i#j#9#9#9#9#9#k#a# ", -" l#m#9#9#9#9#9#9#n#o# p#f#f#f#f#f#f#f#f#f#f#f#q#r# s#t#u#u#u#u#u#u#v#+ ", -" O+w#u#u#u#u#u#u#x#y# z#A#A#A#A#A#A#A#A#A#A#A#B#C# + D#E#E#E#E#E#E#F#G# ", -" c@H#E#E#E#E#E#E#E#I# J#K#K#K#K#K#K#K#K#K#K#K#K#e# L#M#N#N#N#N#N#N#M#O# ", -" P#Q#N#N#N#N#N#N#R#S# T#K#K#K#K#K#K#K#K#K#K#K#K#U# V#W#W#W#W#W#W#W#X#N+ ", -" z+Y#W#W#W#W#W#W#W#Z# `# $ $ $ $ $ $ $ $ $ $ $ $.$ +$@$#$#$#$#$#$#$#$$$ ", -" %$#$#$#$#$#$#$#$&$*$ =$ $ $ $ $ $ $ $ $ $ $ $ $-$ ;$>$>$>$>$>$>$>$,$z+ ", -" '$,$>$>$>$>$>$>$>$)$O+ !$~$~$~$~$~$~$~$~$~$~$~$~${$ ]$^$^$^$^$^$^$^$^$]$ ", -" /$^$^$^$^$^$^$^$^$($ _$~$~$~$~$~$~$~$~$~$~$~$~$:$ <$[$[$[$[$[$[$[$[$}$`@ ", -" |$^$^$^$^$^$^$^$^$1$ 2$3$3$3$3$3$3$3$3$3$3$3$3$4$ 6@5$6$6$6$6$6$6$6$5$7$ ", -" O+8$[$[$[$[$[$[$[$[$9$ 0$a$a$a$a$a$a$a$a$a$a$a$a$b$ c$d$d$d$d$d$d$d$d$e$ ", -" f$6$6$6$6$6$6$6$6$6$g$ h$a$a$a$a$a$a$a$a$a$a$a$a$i$ j$k$k$k$k$k$k$k$k$l$ ", -" m$d$d$d$d$d$d$d$d$d$n$ 6.o$p$p$p$p$p$p$p$p$p$p$p$p$q$ r$k$k$k$k$k$k$k$k$s$6@ ", -" t$k$k$k$k$k$k$k$k$k$u$ v$p$p$p$p$p$p$p$p$p$p$p$p$p$w$x@ x$y$y$y$y$y$y$y$y$z$A$ ", -" B$y$y$y$y$y$y$y$y$y$C$ D$E$E$E$E$E$E$E$E$E$E$E$E$E$F$G$ H$I$J$J$J$J$J$J$J$J$K$L$ ", -" M$J$J$J$J$J$J$J$J$J$N$L$ O$P$P$P$P$P$P$P$P$P$P$P$P$P$Q$R$ S$T$T$T$T$T$T$T$T$T$T$U$ ", -" V$T$T$T$T$T$T$T$T$T$T$W$N+ X$P$P$P$P$P$P$P$P$P$P$P$P$P$Y$Z$ `$ %.%.%.%.%.%.%.%.%.%+%L$ ", -" @%.%.%.%.%.%.%.%.%.%.%#%$%%%&%*%=% -%;%;%;%;%;%;%;%;%;%;%;%;%;%>%,% '%)%!%!%!%!%!%!%!%!%!%!%~%{% ", -" ]%!%!%!%!%!%!%!%!%!%^%/%(%_%_%_%:%<%[% }%;%;%;%;%;%;%;%;%;%;%;%;%;%;%|% c@1%2%#%#%#%#%#%#%#%#%#%#%#%3%`@ ", -" 4%5%#%#%#%#%#%#%#%6%7%_%_%_%_%_%_%_%8%=% 9%0%0%0%0%0%0%0%0%0%0%0%0%0%0%a% {%b%c%d%d%d%d%d%d%d%d%d%d%d%d%e% ", -" f%d%d%d%d%d%d%g%h%_%_%_%_%_%_%_%_%_%i%j% k%0%0%0%0%0%0%0%0%0%0%0%0%0%0%l% m%n%n%n%n%n%o% =%n%n%n%n%n%n%n%n%n%p%q%r%s%s%s%s%s%s%s%s%s%s%s%s%s%t%u% ", -" v%w%d%d%d%d%d%~+_%_%_%_%_%_%_%_%_%_%x%y% z%A%A%A%A%A%A%A%A%A%A%A%A%A%A%B% C%_%_%_%_%_%D% j%E%F%G%_%_%_%_%_%_%_%_%_%_%_%_%H%I%}.J%K%K%K%K%K%K%K%K%K%K%L% ", -" + M%s%s%s%s%s%N%_%_%_%_%_%_%_%_%_%_%_%O%P%`@ Q%A%A%A%A%A%A%A%A%A%A%A%A%A%A%R% C%_%_%_%_%_%D% S%T%U%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%V%A%W%W%W%W%W%W%W%W%X%Y% ", -" 4%Z%K%K%K%K%`%_%_%_%_%_%_%_%_%_%_%_%f. &.&+&@& #&$&$&$&$&$&$&$&$&$&$&$&$&$&$&%& C%_%_%_%_%_%D% &&*&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%=&P$-&-&-&-&-&-&;&>& ", -" ,&'&W%W%W%)&_%_%_%_%_%_%_%_%_%_%_%B+W%W%W%!&~&{&N+ ]&^&^&^&^&^&^&^&^&^&^&^&^&^&^&/& C%_%_%_%_%_%D% (&_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%:&<&-&-&-&-&-&[&`@ ", -" }&|&-&-&l+_%_%_%_%_%_%_%_%_%_%1&2&-&-&-&-&-&-&3&4&5&6&+ 7&^&^&^&^&^&^&^&^&^&^&^&^&^&^&8& C%_%_%_%_%_%D% 9&0&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%a&b&b&b&b&c&N+ ", -" d&e&b&f&I%_%_%_%_%_%_%_%_%_%r g&b&b&b&b&b&b&b&b&b&h&i&j&Y%k& l&m&m&m&m&m&m&m&m&m&m&m&m&m&m&n& C%_%_%_%_%_%D% *%_%_%_%_%_%_%o&V%p&p&p&p&p&p&p&p&p&q&H%_%_%_%_%_%r&s&g&g&t&u& ", -" P%v&g&w&x&_%_%_%_%_%_%H%)&y&g&g&g&g&g&g&g&g&g&g&g&g&g&z&A&B&C&D& x@E&m&m&m&m&m&m&m&m&m&m&m&m&m&m&]&+ C%_%_%_%_%_%D% F&G&H&I&_%_%_%_%_%r&J&K&L&L&L&L&L&L&L&L&s&M&}.H%_%_%_%_%(%N&O&P&k& ", -" Q&R&S&2&T&1&_%_%_%U&'+f&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&S&V&A&W&X&Y&+ Z&`& * * * * * * * * * * * * * *.*6. C%_%_%_%_%_%D% +*@*#*$*%*&***=*_%_%_%_%_%z ************************s&q&_%_%_%_%H%-*;*`@ ", -" `@>*,***'*)* *N&g%**************************************************!*~*H&{*@&c@ ]*^* * * * * * * * * * * * * * */*(* C%_%_%_%_%_%D% N+_*:*<*[*}*g%g%g%g%g%g%|*_%_%_%_%_%N.g%g%g%g%g%g%g%g%g%g%g%g%g%I%_%_%_%_%_%1* ", -" 2*3*g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%4*5*6*;*{*4%c@ 7*8*9*9*9*9*9*9*9*9*9*9*9*9*9*9*0*L@ C%_%_%_%_%_%D% a*Y&b*c*d*e*f*g*g*g*g*g*g*g*g*g*g*h*i*i*i*i*i*`.g*g*g*g*g*g*g*g*g*g*g*g*g*j*_%_%_%_%_%k* ", -" l*m*n*o*(+(+(+(+(+(+p*g*g*g*g*g*g*g*g*g*g*g*g*g*g*g*g*g*L&y&y&y&y&y&y&y&y&y&y&f&g*q*r*3*s*t*2*u*+ v*w*x*x*x*x*x*x*x*x*x*x*x*x*x*x*y*z* C%_%_%_%_%_%D% a*A*B*C*D*E*F*f&f&f&f&f&f&f&f&f&f&f&f&f&f&f&G*H*H*H*H*H*M&f&f&f&f&f&f&f&f&f&f&f&f&f&j*_%_%_%_%_%k* ", -" I*_%_%_%_%_%_%_%_%_%=+f&f&f&f&f&f&f&f&f&f&f&f&f&J*j.K*L*M*:&:&:&:&:&:&:&:&:&:&q&N*O*B+P*f&f&Q*R*S*T*U*V*W*6& X*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*w*Y* C%_%_%_%_%_%D% `@Z*`* =.=+=@=#=L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&L&I%_%_%_%_%_%k* ", -" I*_%_%_%_%_%_%_%_%_%$+f&f&f&f&f&f&f&f&f&f&f&$=%=&=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%r&i+'*f&f&f&f&f&f&f&Q**=D*==-=;=>=+*`@j%=%,='=)=)=)=)=)=)=)=)=)=)=!=~={= 9&]=)=)=)=)=)= o%)=)=)=)=)=^= /=(=(=(=(=(=(=(=(=(=(=(=;%w.0.0.0._=)=)=)=)=)=)=)='=,=o%j% C%_%_%_%_%_%D% m%'=)=)=)=)=)=:= N+6&<=[=}=|=.*1=p$p$p$p$p$p$p$p$p$p$2=3=y&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&s&4= =5=_%_%_%_%_%k* ", -" I*_%_%_%_%_%_%_%_%_%$+L&L&L&L&L&L&L&L&L&L&6=7=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%8=9=0=L&L&L&L&L&L&L&s&s&s&s&s&a=b=c=d=:%_%_%_%_%_%_%_%_%_%_%_%_%_%e=f=g=9& h=G%_%_%_%_%_& i=_%_%_%_%_%j= k=(=(=(=(=(=(=(=(=(=(=$&I%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l=m=n= C%_%_%_%_%_%D% S%o=_%_%_%_%_%_&E% p=q=r=s=t=u=v=w=x='*x*y=z=_%_%_%_%_%_%_%_%_%_%_%_%_%(%A=A#K&'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*'*b=B=q= C=_%_%_%_%_%k* ", -" D=_%_%_%_%_%_%_%_%_%E=F=G=s&s&s&s&s&s&s&2&H=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%I=K&s&s&s&s&s&s&s&'*'*'*'*'*j.&=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%J=K= h=G%_%_%_%_%_& i=_%_%_%_%_%j= L=M=M=M=M=M=M=M=M=M=M==+H%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%x%N=&& C%_%_%_%_%_%D% j%O=_&_%_%_%_%_%P=Q=R=S=T=U=V=W='*'*'*'*'*X=u (%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%8=O*<&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&y&Y=Z=`= C=_%_%_%_%_%k* ", -" D=_%_%_%_%_%_%_%_%_% -+ .-+-x='*'*'*'*'*@-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%H%4.'*'*'*'*'*'*y&y&y&y&y&`.8=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%#-$-+ h=G%_%_%_%_%_& i=_%_%_%_%_%j= %-M=M=M=M=M=M=M=M=M=M='._%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_&N= C%_%_%_%_%_%D% F&&-*-_&_%_%_%_%_%_%=---y&y&y&y&y&y&y&y&y&y&;-u H%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%>-P*;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-,-'-)- C=_%_%_%_%_%k* ", -" i%_%_%_%_%_%_%_%_%_% - !-~-{-]-y&2=H%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%z=3=y&y&y&y&y&y&y&y&y&^-1&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%/-(-_-:-<-[-}-|-1-2-3-4-G%_%_%_%_%_& i=_%_%_%_%_%j= 5-6-6-6-6-6-6-6-6-6-6-t._%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%x%7- C%_%_%_%_%_%8-9-0-a-b-c-d-e-A#f-_%_%_%_%_%_%p&g-;-;-;-;-;-;-;-;-;-;-;-m&8=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o.;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-h-i-j-+ C=_%_%_%_%_%k* ", -" i%_%_%_%_%_%_%_%_%_% - p=k-l-m-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%G.;-;-;-;-;-;-;-;-;-T&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%=&n-;-;-;-;-;-;-;-;-h-o-p-_%_%_%_%_&q-r-2-6&p= i=_%_%_%_%_%j= s-2=2=2=2=2=2=2=2=2=2=a$t-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%u-j%+ +*q=v-w-x-y-z-A-B-_%_%_%_%_%/-P*P*P*P*P*P*M=C-_%_%_%_%_%_%7%D-P*P*P*P*P*P*P*P*P*P*P*P*K*_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%r&--P*P*P*P*P*P*P*P*P*P*P*P*P*P*P*E-F-G-u* H-_%_%_%_%_%l* ", -" i%_%_%_%_%_%_%_%_%_% - I-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%J-P*P*P*P*P*P*P*P*K-L-_%_%_%_%_%(%M-N-N%N%N%N%N%N%N%N%O-1&_%_%_%_%_%_%N.P*P*P*P*P*P*P*P*P*J*M*_%_%_%_%H%P*P-Q-R-S-F-T-U-V-W-X-Y-Z-`-_%_%_%_%_%j= ;2=2=2=2=2=2=2=2=2=2=2=B.y=.;.;.;+;@;@;@;@;@;#;$;%;&;_%_%_%_%_%*;=;-;;;>;,;K&K&K&K&K&f._%_%_%_%_%';K&K&K&K&K&^-h%_%_%_%_%_%_%);p$K&K&K&K&K&K&K&K&K&K&K&K&!;(%_%_%_%_%_%H%~;N-N-N-N-N-N-N-N-N-y=q&_%_%_%_%_%H%E$K&K&K&K&K&K&K&K&K&K&K&K&K&;;{;];k& ^;/;_%_%_%_%e=(; ", -" _;_%_%_%_%_%_%_%_%_% - [%:%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%=-K&K&K&K&K&K&K&K&n-);_%_%_%_%_%N@X=K&K&K&K&K&K&K&K&K&X=x*t-_%_%_%_%_%:;K&K&K&K&K&K&K&K&K&J*M*_%_%_%_%H%K&K&K&K&K&K&K&K&K&K&K&K&<;[;_%_%_%_%_%j= };J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&|; p=1;2;3;4;o&_%_%_%_%_%(=X=X=X=X=X=X=X=X=X=f._%_%_%_%_%';X=X=X=X=5;H=_%_%_%_%_%_%f-~+X=X=X=X=X=X=X=X=X=X=X=X=X=6-_%_%_%_%_%H%].M&X=X=X=X=X=X=X=X=X=X=6;7;_%_%_%_%_%4.X=X=X=X=X=X=X=X=X=X=2;8;Y-+* n%9;9;9;9;9;9;9;0;a;_%_%_%_%_%l==% ", -" _;_%_%_%_%_%_%_%_%_% - K=b;_%_%_%_%_%_%_%_%i*m %.%.%.%.%.%.%.%.c;_%_%_%_%_%_%_%_%_%x&X=X=X=X=X=X=X=X=d;H%_%_%_%_%M*X=X=X=X=X=X=X=X=X=X=X=X=X=e;_%_%_%_%_%/%X=X=X=X=X=X=X=X=X=^%M*_%_%_%_%H%X=X=X=X=X=X=X=X=X=X=X=X=X=P$_%_%_%_%_%j= + f;J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&J&g; `@h;J%J%$=N*_%_%_%_%_%A#J%J%J%J%J%J%J%J%J%0._%_%_%_%_%';J%J%J%K-K*_%_%_%_%_%_%H%` J%J%J%J%J%J%J%J%J%J%J%J%J%J% $_%_%_%_%_%i;K-J%J%J%J%J%J%J%J%J%J%J%J%@-_%_%_%_%_%%=J%J%J%J%J%J%j;k;l;m;a* *%_%_%_%_%_%_%_%_%_%_%_%_%_%_%m= ", -" _;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%o;p;q;r;J%J%J%J%J%J%^&_%_%_%_%_%_%_%_%_%p&J%J%J%J%J%J%J%J%6%H%_%_%_%_%s;J%J%J%J%J%J%J%J%J%J%J%J%J%B._%_%_%_%_%t;J%J%J%J%J%J%J%J%J%g-:&_%_%_%_%H%J%J%J%J%J%J%J%J%J%J%J%J%J%E$_%_%_%_%_%j= u;v;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;x; + y;0=0=0=7=_%_%_%_%_%/#0=0=0=0=0=0=0=0=0=0._%_%_%_%_%z;0=0=$=T&_%_%_%_%_%_%_%A;M&0=0=0=0=0=0=0=0=0=0=0=0=0=0=A#_%_%_%_%_%B;0=0=0=0=0=0=0=0=0=0=0=0=0=a&_%_%_%_%_%C;0=0=0=D;E;F;G;)- *%_%_%_%_%_%_%_%_%_%_%_%_%_%e=n= ", -" _;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S%+ H;I;J;K;0=0=0=$&_%_%_%_%_%_%_%_%_%p&0=0=0=0=0=0=0=0=L;H%_%_%_%_%s;0=0=0=0=0=0=0=0=0=0=0=0=0=B._%_%_%_%_%t;0=0=0=0=0=0=0=0=0=M;:&_%_%_%_%H%0=0=0=0=0=0=0=0=0=0=0=0=0=E$_%_%_%_%_%j= z*N;O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;P; Q;M&M&M&7=_%_%_%_%_%Y@M&M&M&M&M&M&M&M&M&4._%_%_%_%_%z;M&M&].8=_%_%_%_%_%_%y=R;M&M&M&M&M&M&M&M&M&M&M&M&M&M&M&A#_%_%_%_%_%S;M&M&M&M&M&M&M&M&M&M&M&M&M&a&_%_%_%_%_%C;T;U;V;W;X; *%_%_%_%_%_%_%_%_%_%_%_%_%_%Y; ", -" Z;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% )-`; >.>+>_%_%_%_%_%_%_%_%_%p&M&M&M&M&M&M&M&M&)*H%_%_%_%_%L-M&M&M&M&M&M&M&M&M&M&M&M&M&B._%_%_%_%_%t;M&M&M&M&M&M&M&M&M&H*:&_%_%_%_%H%M&M&M&M&M&M&M&M&M&M&M&M&M&p$_%_%_%_%_%j= @>#>O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;O;$> %>$=$=$=7=_%_%_%_%_%N@$=$=$=$=$=$=$=$=$=4._%_%_%_%_%T&$=l+i*_%_%_%_%_%_%H=M;$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=f#_%_%_%_%_%S;$=$=$=$=$=$=$=$=$=$=$=$=$=e;_%_%_%_%_%&>*>`@ *%_%_%_%_%_%_%_%_%_%_%_%_%_%e=n= ", -" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% =>_%_%_%_%_%_%_%_%_%p&M&M&M&M&M&$=$=$=)*H%_%_%_%_%L-$=$=$=$=$=$=$=$=$=$=$=$=$=w._%_%_%_%_%t;$=$=$=$=$=$=$=$=$=6=:&_%_%_%_%H%$=$=$=$=$=$=$=$=$=$=$=$=$=a$_%_%_%_%_%j= ->;>D-D-D-D-D-D-D-D-D-D-D-D-D-D-D-D->> ,>$=$=$=7=_%_%_%_%_%N@$=$=$=$=$=$=$=$=$=}._%_%_%_%_%T&$&z=_%_%_%_%_%_%p&^-$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=/#_%_%_%_%_%S;K-K-K-K-K-K-K-K-K-K-K-K-'>)>_%_%_%_%_%!> *%_%_%_%_%_%_%_%_%_%_%_%_%_%_%u- ", -" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%p&$=$=$=$=$=K-K-K-~>H%_%_%_%_%L-K-K-K-K-K-K-K-K-K-K-K-K-K-w._%_%_%_%_%>-K-K-K-K-K-K-K-K-K-n-:&_%_%_%_%H%K-K-K-K-K-K-K-K-K-K-K-K-K-a$_%_%_%_%_%j= {>]>D-D-D-D-D-D-D-D-D-D-D-0%4.|*^>^>/>!>!>!>!>!>(>C;=*'.p&_%_%_%_%_%k@K-K-K-K-K-K-K-K-K-:._%_%_%_%_%y=_>_%_%_%_%_%_%:&6-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-K-Y@_%_%_%_%_%S;<&<&<&<&<&<&<&<&<&:><>[>}>|>_%_%_%_%_%!> n%N=N=N=N=N=N=9;0;1>_%_%_%_%_%l=o% ", -" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%2>3>4>K-K-K-K-<&<&D-H%_%_%_%_%L-<&<&<&<&<&<&<&<&<&<&<&<&<&t._%_%_%_%_%>-<&<&<&<&<&<&<&<&<&n-:&_%_%_%_%H%<&<&<&<&<&<&<&<&<&<&<&<&<&3$_%_%_%_%_%j= 5>~>~>~>~>~>~>~>~>~>~>$&6>7>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%{@<&<&<&<&<&<&<&<&<&:._%_%_%_%_%H%_%_%_%_%_%_%=&A#<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&<&Y@_%_%_%_%_%B;----------8>9>0>a>q= b>_%_%_%_%_%!> ,=/;_%_%_%_%e=,= ", -" 0;_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c>p=d>e>f>g>h>----O;H%_%_%_%_%L---------------------------t._%_%_%_%_%>-------------------6;:&_%_%_%_%H%--------------------------~$_%_%_%_%_%j= i>~>~>~>~>~>~>~>~>~> $h%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%{@------------------]._%_%_%_%_%_%_%_%_%_%_%f-N.G*--------------------------------------N@_%_%_%_%_%B;G*j>k>l>m>n>o>p>p>p>p>p>p>0&_%_%_%_%_%!> H-_%_%_%_%_%l* ", -" q>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> a*r>s>t>_%_%_%_%_%L---------------------------o._%_%_%_%_%u>------------------N&:&_%_%_%_%H%--------------------------~$_%_%_%_%_%j= v>w>)*)*)*)*)*)*)*^&h%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%B+G*G*G*G*G*G*G*G*G*]._%_%_%_%_%_%_%_%_%_%_%z;G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*G*k@_%_%_%_%_%x>y>z>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ", -" q>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_%B>C>G*G*G*G*G*G*G*G*G*G*G*G*o._%_%_%_%_%u>G*G*G*G*G*G*G*G*G*w&:&_%_%_%_%H%G*G*G*G*G*G*G*G*G*G*G*G*G* $_%_%_%_%_%j= D>E>)*)*)*)*)*)*)*6>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l+2&2&2&2&2&2&2&2&2&'._%_%_%_%_%_%_%_%_%_%_%F>x*2&2&2&2&2&2&2&2&2&2&2&2&2&2&2&2&2&G>H>I>J>_%_%_%_%_%K> I*_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ", -" q>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_%L>M>N>O>P>Q>R>2&2&2&2&2&2&2&j._%_%_%_%_%u>2&2&2&2&2&2&2&2&2&p*:&_%_%_%_%H%2&2&2&2&2&2&2&2&2&2&2&2&2&K#_%_%_%_%_%j= z*S>L;L;L;L;L;L;$&7>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l+R;R;R;R;R;R;R;R;R;'._%_%_%_%_%_%_%_%_%_%_%_%V%9*R;R;R;R;R;R;R;R;R;R;R;R;T>U>V>W>X>Y>+ )=_%_%_%_%_%K> Z>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ", -" `>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , u;.,+,@,#,$,%,R;R;f._%_%_%_%_%u>R;R;R;R;R;R;R;R;R;^-:&_%_%_%_%H%R;R;R;R;R;R;R;R;R;R;R;R;R;K#_%_%_%_%_%j= u;&,6%6%6%6%6%6%o._%_%_%_%_%_%*,|*r =,-,-,-,-,-,;,:.|*7>_%_%_%_%_%_%i+!;!;!;!;!;!;!;!;!;=._%_%_%_%_%_%_%_%_%_%_%_%_%>,x*!;!;!;!;!;!;,,',),!,~,{,+ )=_%_%_%_%_%K> ],_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%!> C=_%_%_%_%_%k* ", -" `>_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , p=^,!,/,_%_%_%_%_%(,!;!;!;!;!;!;!;!;!;_,:&_%_%_%_%H%!;!;!;!;!;!;!;!;!;!;!;!;!;A#_%_%_%_%_%j= + :,6%6%6%6%6%6%C;_%_%_%_%_%~;6%6%6%<, [,5;5;p$o&_%_%_%_%_%i+5;5;5;5;5;5;5;5;5;=._%_%_%_%_%},'.f-_%_%_%_%_%_%q&|,1,2,3,4,Y> )=_%_%_%_%_%K> n%5,U%U%U%U%U%U%U%U%U%U%U%U%U%U%U%U%<% C=_%_%_%_%_%k* ", -" D%_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%7,8,9,j>0,5;5;5;5;5;_,:&_%_%_%_%H%5;5;5;5;5;5;5;5;5;5;5;5;5;f#_%_%_%_%_%j= a,b,b,b,b,b,b,},_%_%_%_%_%9=b,b,b,c, d,e,e,^%f,_%_%_%_%_%e+e,e,e,e,e,e,e,e,e,%._%_%_%_%_%A;3=g,h,_%_%_%_%_%_%1>n= )=_%_%_%_%_%K> m%i,j,j,j,j,j,j,j,j,j,j,j,j,j,j,j,K= C=_%_%_%_%_%k* ", -" D%_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= + k,l,m,n,o,p,q,r,C-_%_%_%_%H%e,e,e,e,e,e,e,e,e,e,e,e,e,f#_%_%_%_%_%j= s,b,b,b,b,b,b,},_%_%_%_%_%|*b,b,b,t, u,3=3=3==-_%_%_%_%_%0+3=3=3=3=3=3=3=3=3=%._%_%_%_%_%v,w,x,y,U%_%_%_%_%_%_%a;n= )=_%_%_%_%_%K> C=_%_%_%_%_%k* ", -" D%_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= p=z,A,_%_%_%_%H%3=3=3=3=3=3=3=3=3=3=3=3=3=/#_%_%_%_%_%j= B,d;d;d;d;d;d;},_%_%_%_%_%|*d;d;d;C, D,E,J*J*=-_%_%_%_%_%0+J*J*J*J*J*J*F,G,H,I,_%_%_%_%_%D% j% -_&_%_%_%_%_%_%J,E% )=_%_%_%_%_%K> K,&%L,M,=% C=_%_%_%_%_%k* ", -" O=_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= h=G%_%_%_%_%H%J*J*J*J*J*J*J*J*J*J*J*J*J*Y@_%_%_%_%_%j= N,d;d;d;d;d;d;},_%_%_%_%_%e;d;d;d;O, P,Q,J*J*=-_%_%_%_%_%6+J*J*J*J*J*E,R, C%_%_%_%_%_%D% 6,x%_%_%_%_%_%_%G%!= )=_%_%_%_%_%K> l*x%_%_%_%G%S, C=_%_%_%_%_%k* ", -" O=_%_%_%_%_%_%_%_%_% - n;b;_%_%_%_%_%_%_%_%:%S% !=_%_%_%_%_%_%_%_%_%c> A>_&_%_%_%_% , 6,_%_%_%_%_%o= h=G%_%_%_%_%H%^%^%^%^%^%^%^%^%^%^%^%^%^%N@_%_%_%_%_%j= T,U,U,U,U,U,U,9=_%_%_%_%_%e;U,U,U,V, W,X,^%g-=-_%_%_%_%_%}+^%^%^%^%^%X,W, C%_%_%_%_%_%D% j%6,x%_%_%_%_%_%_%J,l* )=_%_%_%_%_%K> T%_%_%_%_%_%6, C=_%_%_%_%_%k* ", -" O=_%_%_%_%_%_%_%_%_%m=Y, K=b;_%_%_%_%_%_%_%_%e=D=b>b>b>b>b>b>b>b>m=_%_%_%_%_%_%_%_%_%Z, A>_&_%_%_%_% , 6,_%_%_%_%_%o= h=G%_%_%_%_%H%g-g-g-g-g-g-g-g-g-g-g-g-g-N@_%_%_%_%_%j= `, ' ' ' ' ' '9=_%_%_%_%_%e; ' ' '.' +'@'g-g-=-_%_%_%_%_%}+g-g-g-g-g-#'k, C%_%_%_%_%_%D% j%(&x%_%_%_%_%_%_%G%k* )=_%_%_%_%_%K> q>_%_%_%_%_%L, C=_%_%_%_%_%k* ", -" T%_%_%_%_%_%_%_%_%_%_%$'Y, S%:%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%%' A>_&_%_%_%_%H- &'_%_%_%_%_%o= h=G%_%_%_%_%H%n-M;M;M;M;M;M;M;M;M;M;M;M;k@_%_%_%_%_%j= *' ' ' ' ' ' '9=_%_%_%_%_%T& ' ' '=' -';'M;6;L*_%_%_%_%_%(+M;M;M;M;M;>'6. C%_%_%_%_%_%D% j%,'e=_%_%_%_%_%_%l=l* )=_%_%_%_%_%Y; q>_%_%_%_%_%&' H-_%_%_%_%_%k* ", -" T%_%_%_%_%_%_%_%_%_%_%_%''=% ,_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%)' n%/;_%_%_%_%e=n; 9&!'_%_%_%_%_%o= m%1>_%_%_%_%_%A#M;M;M;M;M;M;M;M;M;M;M;M;k@_%_%_%_%_%j= ~'_,_,_,_,_,_,C;_%_%_%_%_%{' '_,_,]' ^'/'H*l+8=_%_%_%_%_%N@H*H*H*H*H*(' C%_%_%_%_%_%D% _'x%_%_%_%_%_%_%:']= ^=_%_%_%_%_%1>=% <%_%_%_%_%_%@;j% n=x%_%_%_%_%e=E% ", -" b>_%_%_%_%_%_%_%_%_%_%_%_%_; `>_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%g= =%a;_%_%_%_%_%<'6,)='='='='='='='='=['}'_&_%_%_%_%_%o= j%j=_%_%_%_%_%F>P }+6+6+6+6+6+6+6+6+6+6+h _%_%_%_%_%j= |'_,_,_,_,_,_,f._%_%_%_%_%_%N%t.=+1''='='='='=2'3'm t-_%_%_%_%_%8=x*6=6=6=6=6=4' C%_%_%_%_%_%D% j%_'/;_%_%_%_%_%_%:%5' 6'_%_%_%_%_%_%!'&%'='='='='='='='='='='='='='='='=5'S% 6,_%_%_%_%_%U%_;7''='='='='='='='=)=-,8'_%_%_%_%_%b;K, ", -" k*:'_%_%_%_%_%_%_%_%_%_%_%9'[% n=_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%G%o% u-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= T%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= 0'a'^-^-^-^-^-^&=&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%b'p*n-n-n-n-n-c' C%_%_%_%_%_%D% j%&%/;_%_%_%_%_%_%J= ,_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%/;n% n%_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%d'j% ", -" %%/;_%_%_%_%_%_%_%_%_%_%9'Y, @;_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%L, '=e=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= e'/;_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= f'g'^-^-^-^-^-_,h'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%%.6;6;6;6;6;6;i' C%_%_%_%_%_%D% j'e=_%_%_%_%_%!' k'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%/;n% u-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j' ", -" l'/;_%_%_%_%_%_%_%_%_%m= o%C=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_&I*&& j%F%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= m'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= n'o'p*p*p*p*p*p*0%M*_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%p'U,N&N&N&N&N&N&q' C%_%_%_%_%_%D% M,/;_%_%_%_%!' Y,%'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%:'r' A>s'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%$'j% ", -" ,'U%_%_%_%_%_%_%_%b;t' y%d'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%e=0;S% [%J=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= &&I*_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= u'v'w&w&w&w&w&w&w&6+t-_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%w'M=w&w&w&w&w&w&w&x' C%_%_%_%_%_%D% M,b;_%_%_%!' y%y'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%<'j% 5's'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%''o% ", -" M,:%_%_%_%_%_%x%,' m%z'G%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%y'7'j% S%A'G%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%o= && -9'_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%j= u;B'w&w&w&w&w&w&w&w&3$C'8=_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%1&D')*p*p*p*p*p*p*p*E'F' C%_%_%_%_%_%D% M,G'_%_%!' r'i%x%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%:%k* i,K>_&_%_%_%_%_%_%_%_%_%_%_%_%_%_%_%l=<%m% ", -" H'I'_&_%_%J'*% K=,'F%K'Z,8'8'8'8'8'8'8'8'8'8'J'''`>'=S% r'L'O=@;)')')')')')')')')')'I*M'_%_%_%_%_%o= :=N'O'>-P'P'P'P'P'P'P'P'P'P'P'P'h'Q')')')'b> R'N&N&N&N&N&N&N&N&N&^-3$e )&P'S')')')')')')')'7,y=I=].x*^-^-^-^-^-^-^-^-^-T'U' )=)')')')')',' V')')'A' j%n%-,q>@;)')')')')')')')')')'F%I*0;m'_'K, &&^;W'i%)')')')')')')')')')'Z>D%g=K= ", -" ~='=,=j% 6,_%_%_%_%_%o= X'^-^-^-^-^-^-^-^-^-^-^-^-^-Y'-' Z'N&N&N&N&N&N&N&N&N&N&N&N&N&N&`' )^-^-^-^-^-^-^-^-^-^-^-^-^-.)u; ", -" 6,_%_%_%_%_%o= +)_,_,_,_,_,_,_,_,_,_,_,_,_,@)#) $)6;6;6;6;6;6;6;6;6;6;6;6;6;6;%) &)_,_,_,_,_,_,_,_,_,_,_,_,_,*) ", -" 6,_%_%_%_%_%o= =) ' ' ' ' ' ' ' ' ' ' ' ' '-);) >)n-n-n-n-n-n-n-n-n-n-n-n-n-n-,) ') ' ' ' ' ' ' ' ' ' ' ' ' ')) ", -" 6,_%_%_%_%_%o= !)U,U,U,U,U,U,U,U,U,U,U,U,U,~)u; {)n-n-n-n-n-n-n-n-n-n-n-n-n-n-]) ^)U,U,U,U,U,U,U,U,U,U,U,U,U,/) ", -" 6,_%_%_%_%_%o= D>()U,U,U,U,U,U,U,U,U,U,U,U,_)_# :)6=6=6=6=6=6=6=6=6=6=6=6=6=6=<) [)d;d;d;d;d;d;d;d;d;d;d;d;d;}) ", -" 6,_%_%_%_%_%o= #)|)d;d;d;d;d;d;d;d;d;d;d;d;1)6. 2)6=6=6=6=6=6=6=6=6=6=6=6=6=6=3) 4)b,b,b,b,b,b,b,b,b,b,b,b,b,5) ", -" 6,_%_%_%_%_%o= u;6)b,b,b,b,b,b,b,b,b,b,b,b,7) 8)H*H*H*H*H*H*H*H*H*H*H*H*H*H*9) 0)6%6%6%6%6%6%6%6%6%6%6%6%6%a) ", -" 6,_%_%_%_%_%o= + b)6%6%6%6%6%6%6%6%6%6%6%6%c) d)H*H*H*H*H*H*H*H*H*H*H*H*H*H*e) f)L;L;L;L;L;L;L;L;L;L;L;L;L;0) ", -" 6,_%_%_%_%_%o= g)L;L;L;L;L;L;L;L;L;L;L;L;h) i)M;M;M;M;M;M;M;M;M;M;M;M;M;M;x, j)k))*)*)*)*)*)*)*)*)*)*)*)*l) ", -" 6,_%_%_%_%_%o= m))*)*)*)*)*)*)*)*)*)*)*)*n) o)M;M;M;M;M;M;M;M;M;M;M;M;M;p)q) {>r)~>~>~>~>~>~>~>~>~>~>~>~>u' ", -" 6,_%_%_%_%_%o= s)~>~>~>~>~>~>~>~>~>~>~>~>t) u)g-g-g-g-g-g-g-g-g-g-g-g-g-v)w) x)y)D-D-D-D-D-D-D-D-D-D-D-;>+ ", -" 6,_%_%_%_%_%o= z)D-D-D-D-D-D-D-D-D-D-D-D-A) B)^%^%^%^%^%^%^%^%^%^%^%^%^%C)D) D>E)O;O;O;O;O;O;O;O;O;O;O;F) ", -" i,L,L,L,L,L,)= G)O;O;O;O;O;O;O;O;O;O;O;O;H) +'^%^%^%^%^%^%^%^%^%^%^%^%^%I)X; z*J)O;O;O;O;O;O;O;O;O;O;O;K) ", -" L)w;w;w;w;w;w;w;w;w;w;w;w;M) p=J*J*J*J*J*J*J*J*J*J*J*J*J*N)`@ x@O)w;w;w;w;w;w;w;w;w;w;w;P) ", -" x)Q)J&J&J&J&J&J&J&J&J&J&J&R) S)J*J*J*J*J*J*J*J*J*J*J*J*T) + U)J&J&J&J&J&J&J&J&J&J&J&V) ", -" W)X)2=2=2=2=2=2=2=2=2=2=2=Y) Z)3=3=3=3=3=3=3=3=3=3=3=3=`) !2=2=2=2=2=2=2=2=2=2=2=.! ", -" (*+!2=2=2=2=2=2=2=2=2=2=2=@! #!3=3=3=3=3=3=3=3=3=3=3=3=$! %!6-6-6-6-6-6-6-6-6-6-6-&! ", -" *!6-6-6-6-6-6-6-6-6-6-6-=! 1,e,e,e,e,e,e,e,e,e,e,e,e,-! ;!M=M=M=M=M=M=M=M=M=M=M=>! ", -" ,!M=M=M=M=M=M=M=M=M=M=M='! )!5;5;5;5;5;5;5;5;5;5;5;5;!! ~!(=(=(=(=(=(=(=(=(=(=(={! ", -" ]!(=(=(=(=(=(=(=(=(=(=(=7* ^!5;5;5;5;5;5;5;5;5;5;5;5;/! (!x*x*x*x*x*x*x*x*x*x*w*_! ", -" :!x*x*x*x*x*x*x*x*x*x*x! y!$&$&$&$&$&$&$&$&$&$&z! ", -" + A!A%A%A%A%A%A%A%A%A%B!+ C!G*G*G*G*G*G*G*G*G*G*G*D!E! F!A%A%A%A%A%A%A%A%A%A%B% ", -" G!0%0%0%0%0%0%0%0%0%H! x!----------------------I!{, J!0%0%0%0%0%0%0%0%0%0%K! ", -" L!0%0%0%0%0%0%0%0%0%M! Y>N!--------------------O!+ P!;%;%;%;%;%;%;%;%;%;%O$ ", -" Q!;%;%;%;%;%;%;%;%;%R! S!T!<&<&<&<&<&<&<&<&<&<&U! V!P$P$P$P$P$P$P$P$P$W!X! ", -" Y!P$P$P$P$P$P$P$P$P$Z! X;`!K-K-K-K-K-K-K-K-K-K- ~ .~E$E$E$E$E$E$E$E$E$+~v$ ", -" @~E$E$E$E$E$E$E$E$E$#~ F&$~K-K-K-K-K-K-K-K-K-K-%~ &~p$p$p$p$p$p$p$p$p$*~(* ", -" =~p$p$p$p$p$p$p$p$p$-~ `@;~$=$=$=$=$=$=$=$=$=$=>~ ,~a$a$a$a$a$a$a$a$a$'~ ", -" V!a$a$a$a$a$a$a$a$a$)~ !~$=$=$=$=$=$=$=$=$=$=~~ L@3$3$3$3$3$3$3$3$3${~ ", -" X!3$3$3$3$3$3$3$3$3$]~ ^~M&M&M&M&M&M&M&M&M&M&/~ + (~~$~$~$~$~$~$~$~$_~ ", -" (*(~~$~$~$~$~$~$~$~$:~ <~M&M&M&M&M&M&M&M&M&M&[~ }~ $ $ $ $ $ $ $ $T# ", -" |~ $ $ $ $ $ $ $ $.$ 1~0=0=0=0=0=0=0=0=0=0=2~ 3~ $ $ $ $ $ $ $ $4~ ", -" 5~K#K#K#K#K#K#K#K#6~ 7~0=0=0=0=0=0=0=0=0=0=8~ 9~K#K#K#K#K#K#K#K#0~ ", -" a~A#A#A#A#A#A#A#A#b~ c~J%J%J%J%J%J%J%J%J%J%d~ e~A#A#A#A#A#A#A#B#f~ ", -" g~f#f#f#f#f#f#f#f#h~ i~X=X=X=X=X=X=X=X=X=X=j~ k~f#f#f#f#f#f#f#q#l~ ", -" m~f#f#f#f#f#f#f#n~o~ p~X=X=X=X=X=X=X=X=X=X=q~ r~/#/#/#/#/#/#/#X@1+ ", -" s~/#/#/#/#/#/#/#t~u~ v~K&K&K&K&K&K&K&K&K&K&u* w~Y@Y@Y@Y@Y@Y@Y@x~+ ", -" y~Y@Y@Y@Y@Y@Y@Y@z~l~ A~K&K&K&K&K&K&K&K&K&K&X; B~N@N@N@N@N@N@N@C~ ", -" D~N@N@N@N@N@N@N@E~h# &-E-P*P*P*P*P*P*P*P*F~ G~k@k@k@k@k@k@k@H~ ", -" I~k@k@k@k@k@k@k@J~1+ 2-Q-P*P*P*P*P*P*P*P*R- K~{@{@{@{@{@{@{@L~ ", -" 6#M~{@{@{@{@{@{@N~T. O~P~;-;-;-;-;-;-;-;-Q~ R~B+B+B+B+B+B+B+S~ ", -" T.T~B+B+B+B+B+B+U~+ +*V~y&y&y&y&y&y&y&y&W~ X~l+l+l+l+l+l+l+Y~ ", -" _#Z~l+l+l+l+l+l+`~ `@_-y&y&y&y&y&y&y&y& { .{i+i+i+i+i+i+i++{ ", -" @{i+i+i+i+i+i+#{ ${'*'*'*'*'*'*'*'*%{ &{i+i+i+i+i+i+i+*{ ", -" ={e+e+e+e+e+e+-{ T='*'*'*'*'*'*'*'*+- f+e+e+e+e+e+e+e+;{ ", -" >{0+0+0+0+0+0+,{ '{s&s&s&s&s&s&s&s&){ !{0+0+0+0+0+0+c+~{ ", -" {{6+6+6+6+6+6+]{ ^{s&s&s&s&s&s&s&s&/{ *{6+6+6+6+6+6+({ ", -" _{6+6+6+6+6+6+:{ ==L&L&L&L&L&L&L&L&<{ [{}+}+}+}+}+}+}{ ", -" |{}+}+}+}+}+}+1{ 2{f&f&f&f&f&f&f&f&3{ @+(+(+(+(+(+(+4{ ", -" 5{6{(+(+(+(+(+7{ 8{f&f&f&f&f&f&f&f&9{ 0{~+~+~+~+~+~+a{ ", -" 4+b{~+~+~+~+~+c{ d{g*g*g*g*g*g*g*g*W* e{f{'+'+'+'+'+g{ ", -" I.h{'+'+'+'+'+i{ b*g*g*g*g*g*g*g*g*j{ I.k{=+=+=+=+=+l{ ", -" + m{=+=+=+=+=+n{ o{g%g%g%g%g%g%g%g%>= T.3'$+$+$+$+$+p{ ", -" q{$+$+$+$+$+r{ s{&*************t{6& ~{u{`.`.`.`.`.v{ ", -" w{`.`.`.`.`.x{ y{,*************z{)- P.A{W.W.W.W.W.B{ ", -" C{W.W.W.W.W.D{ D&V&S&S&S&S&S&S&E{F& 6.F{W.W.W.W.G{e{ ", -" H{N.N.N.N.N.I{ @&J{S&S&S&S&S&S&K{k& L{N.N.N.N.S.T. ", -" M{G.G.G.G.G.N{ `@O{g&g&g&g&g&g&P{+ Q{G.G.G.G.R{D ", -" S{B.B.B.B.B.T{ U{g&g&g&g&g&g&V{ W{B.B.B.B.X{ ", -" Y{Z{B.B.B.B.`{ ]b&b&b&b&b&b&.] +]w.w.w.w.@] ", -" #]$]w.w.w.w.e{ %]b&b&b&b&b&b&&] *]t.t.t.t.=] ", -" ~{-]t.t.t.t.D ;]-&-&-&-&-&-&>] ,]o.o.o.o.'] ", -" )]o.o.o.!] ~]W%W%W%W%W%W%{] ]]j.j.j.j.^] ", -" /]j.j.j.(] _]W%W%W%W%W%W%:] <]f.f.f.f.[] ", -" }]f.f.f.|] 1]K%K%K%K%K%K%2] 3]0.0.0.4]5] ", -" 6]0.0.0.7] 8]K%K%K%K%K%K%9] 0]4.4.4.a]7. ", -" b]4.4.4.c] d]s%s%s%s%s%s%v% e]}.}.}.f]K ", -" g]}.}.}.h] `$s%s%s%s%s%i]j] k]}.}.}.l]+ ", -" m]:.:.:.n] }&d%d%d%d%d%o]p] q]:.:.:.r] ", -" s]].].].t] u]#%#%#%#%#%v]4% s]].].].t] ", -" b.'.'.'.w] x]#%#%#%#%#%y]@& z]A]'.'.B] ", -" + C]'.'.D] @&!%!%!%!%!%E]N+ F]G]=.=.H] ", -" I]=.=.J] + K]!%!%!%!%L] M]N]%.%.O] ", -" P]%.%.Q] R].%.%.%.%S] b.T]` ` U] ", -" V]` ` W] X]T$T$T$T$Y] 3.Z]U `] ^ ", -" .^U U +^ @^T$T$T$T$#^ P.$^P %^&^ ", -" *^P P =^ -^J$J$J$J$;^ + >^I ,^~{ ", -" '^I I Z M$J$J$J$J$)^ !^F ~^ ", -" {^F F ]^ ^^y$y$y$y$/^ (^z _^ ", -" :^z z <^ [^y$y$y$y$}^ |^z 1^ ", -" 5 2^u 3^ 4^k$k$k$k$5^ 6^u 7^ ", -" 8^9^r &^ 0^d$d$d$d$a^ b^r o ", -" # c^d^e^ f^d$d$d$g^h^ i^m j^ ", -" + k^l^2 m^6$6$6$8$n^ o^h p^ ", -" O%q^3. r^6$6$6$s^t^ u^e k ", -" v^w^x^ y^[$[$[$z^A^ B^%=e^ ", -" C^D^} L#[$[$[$E^o# F^G^+ ", -" F^H^. A^I^^$^$J^ K^| ", -" L^M^+ @&N^^$^$O^ P^Q^ ", -" R^S^ 6@T^>$>$U^ V^W^ ", -" 8 X^ o#Y^#$#$Z^ `^ / ", -" e^./ + +/#$#$@/ #/, ", -" } $/ %/W#W#&/ */=/ ", -" -/ ;/W#W#>/ ,/'/ ", -" )/ H#N#N#!/ ~/{/ ", -" % ]/N#N#^/ # } ", -" //E#E#(/ ", -" _/u#u#:/ ", -" Date: Tue, 9 Apr 2024 23:22:45 +0200 Subject: [PATCH 0313/2040] Fixed scripts using syntax like $self --- code/parser/bison_source.txt | 2 +- code/parser/parsetree.cpp | 9 +++++++++ code/parser/parsetree.h | 13 +++++++++++++ code/script/scriptcompiler.h | 12 ------------ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/code/parser/bison_source.txt b/code/parser/bison_source.txt index e5d393ef..a4e1d4ce 100644 --- a/code/parser/bison_source.txt +++ b/code/parser/bison_source.txt @@ -294,7 +294,7 @@ identifier ; listener_identifier - : identifier_prim { $$ = node2(ENUM_string, $1, TOKPOS(@1)); } + : identifier_prim { $$ = node_listener($1, TOKPOS(@1)); } | TOKEN_LEFT_BRACKET expr TOKEN_RIGHT_BRACKET { $$ = $2; } ; diff --git a/code/parser/parsetree.cpp b/code/parser/parsetree.cpp index a139f2fc..30b9d7d0 100644 --- a/code/parser/parsetree.cpp +++ b/code/parser/parsetree.cpp @@ -342,3 +342,12 @@ sval_u node6(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4, sval_ return val; } + +sval_u node_listener(sval_u val1, sval_u val2) +{ + if (!str::icmp(val1.stringValue, "self")) { + return node2(ENUM_listener, node1_(method_self), val2); + } else { + return node2(ENUM_string, val1, val2); + } +} diff --git a/code/parser/parsetree.h b/code/parser/parsetree.h index f2769266..53133513 100644 --- a/code/parser/parsetree.h +++ b/code/parser/parsetree.h @@ -101,6 +101,18 @@ enum parseStage_e { PS_BODY_END }; +enum { + method_game, + method_level, + method_local, + method_parm, + method_self, + method_group, + method_owner, + method_field, + method_array, +}; + void parsetree_freeall(); void parsetree_init(); size_t parsetree_length(); @@ -124,6 +136,7 @@ sval_u node3(int type, sval_u val1, sval_u val2, sval_u val3); sval_u node4(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4); sval_u node5(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4, sval_u val5); sval_u node6(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4, sval_u val5, sval_u val6); +sval_u node_listener(sval_u val1, sval_u val2); typedef struct parse_pos_s { int sourcePos; diff --git a/code/script/scriptcompiler.h b/code/script/scriptcompiler.h index 48592872..34c53dcc 100644 --- a/code/script/scriptcompiler.h +++ b/code/script/scriptcompiler.h @@ -32,18 +32,6 @@ class ScriptVariable; typedef void (*ScriptDisplayTokenFunc)(const char *type, const char *name); -enum { - method_game, - method_level, - method_local, - method_parm, - method_self, - method_group, - method_owner, - method_field, - method_array, -}; - typedef struct scriptmacro { str name; str parameters; From a23de7b3611fa74a3b8e39c73405b5efc7ba50ee Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 9 Apr 2024 23:39:32 +0200 Subject: [PATCH 0314/2040] Made Killed() a virtual method --- code/fgame/entity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/entity.h b/code/fgame/entity.h index cd9b1f12..4e8fd2f1 100644 --- a/code/fgame/entity.h +++ b/code/fgame/entity.h @@ -502,7 +502,7 @@ public: void BroadcastAIEvent(int iType = AI_EVENT_MISC, float rad = SOUND_RADIUS); void BroadcastAIEvent(Event *ev); void Kill(Event *ev); - void Killed(Event *ev); + virtual void Killed(Event *ev); void SurfaceModelEvent(Event *ev); void SurfaceCommand(const char *surf_name, const char *token); virtual void Postthink(void); From fa80e0bd75a4a72073b512933d81ead6fc877081 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 00:05:00 +0200 Subject: [PATCH 0315/2040] Implemented FencePost --- code/fgame/Entities.cpp | 123 ++++++++++++++++++++++++++++++++++++---- code/fgame/Entities.h | 4 ++ code/fgame/bg_public.h | 2 +- 3 files changed, 118 insertions(+), 11 deletions(-) diff --git a/code/fgame/Entities.cpp b/code/fgame/Entities.cpp index 67d59f00..4f4a279e 100644 --- a/code/fgame/Entities.cpp +++ b/code/fgame/Entities.cpp @@ -80,7 +80,8 @@ Event EV_PG_MaxDuration "Sets the maximum duration of bursts(in seconds)\nDefault=3", EV_NORMAL ); -Event EV_PG_MinNumShots( +Event EV_PG_MinNumShots +( "MinNumShots", EV_DEFAULT, "i", @@ -88,7 +89,8 @@ Event EV_PG_MinNumShots( "Sets the minimum # of shots to fire in a cycle\nDefault=1", EV_NORMAL ); -Event EV_PG_MaxNumShots( +Event EV_PG_MaxNumShots +( "MaxNumShots", EV_DEFAULT, "i", @@ -275,7 +277,8 @@ Event EV_PG_SetPreImpactSoundTime "Set the time before impact to play the preimpact sound.", EV_NORMAL ); -Event EV_PG_SetPreImpactSoundProbability( +Event EV_PG_SetPreImpactSoundProbability +( "preimpactsoundprob", EV_DEFAULT, "f", @@ -520,7 +523,7 @@ void ProjectileGenerator::SetupNextCycle() // get a random delay m_fShotsPerSec = numShots / m_fCycleTime; - delay = 0.01f; + delay = 0.01f; if (m_bIsTurnedOn || !m_bFireOnStartUp) { delay = G_Random(m_fMaxDelay - m_fMinDelay) + m_fMinDelay; } @@ -1995,12 +1998,12 @@ ThrobbingBox_Stickybomb::ThrobbingBox_Stickybomb() } setModel("items/pulse_stickybomb.tik"); - m_sUsedModel = "items/stickybomb.tik"; - m_sSound = "explode_flak88"; + m_sUsedModel = "items/stickybomb.tik"; + m_sSound = "explode_flak88"; m_sActivateSound = "stickybomb_plant"; - m_sTickSound = "stickybomb_fuse"; + m_sTickSound = "stickybomb_fuse"; - health = 10; + health = 10; m_fStopwatchStartTime = 0; setSolidType(SOLID_BBOX); @@ -2215,10 +2218,110 @@ int Objective::GetObjectiveIndex() const */ CLASS_DECLARATION(Entity, FencePost, "func_fencepost") { - {&EV_Killed, NULL}, - {NULL, NULL} + {&EV_Killed, &FencePost::Killed}, + {NULL, NULL } }; +FencePost::FencePost() +{ + max_health = 20; + health = 20; + damage_type = MOD_AAGUN; + + if (!LoadingSavegame) { + PostEvent(EV_BecomeSolid, EV_POSTSPAWN); + } + + takedamage = DAMAGE_YES; +} + +void FencePost::Killed(Event *ev) +{ + Vector vMins, vMaxs; + Vector vStart, vEnd; + Vector vCenter; + float fHalf; + + vCenter = mins - maxs; + vCenter *= 0.5; + + if (size.x > size.y) { + if (size.x > size.z) { + if (size.y > size.z) { + fHalf = size.y / 2.f; + } else { + fHalf = size.z / 2.f; + } + + vMins[0] = mins[0]; + vMaxs[0] = maxs[0]; + vMins[1] = vCenter[1]; + vMaxs[1] = vCenter[1]; + vMins[2] = vCenter[2]; + vMaxs[2] = vCenter[2]; + } else { + fHalf = size.x / 2.f; + + vMins[2] = mins[2]; + vMaxs[2] = maxs[2]; + vMins[1] = vCenter[1]; + vMaxs[1] = vCenter[1]; + vMins[0] = vCenter[0]; + vMaxs[0] = vCenter[0]; + } + } else { + if (size.y > size.z) { + if (size.x > size.z) { + fHalf = size.x / 2.f; + } else { + fHalf = size.z / 2.f; + } + + vMins[1] = mins[1]; + vMaxs[1] = maxs[1]; + vMins[0] = vCenter[0]; + vMaxs[0] = vCenter[0]; + vMins[2] = vCenter[2]; + vMaxs[2] = vCenter[2]; + } else { + fHalf = size.y / 2.f; + + vMins[2] = mins[2]; + vMaxs[2] = maxs[2]; + vMins[1] = vCenter[1]; + vMaxs[1] = vCenter[1]; + vMins[0] = vCenter[0]; + vMaxs[0] = vCenter[0]; + } + } + + MatrixTransformVector(vMins, orientation, vStart); + MatrixTransformVector(vMaxs, orientation, vEnd); + + vStart += origin; + vEnd += origin; + + if (fHalf > 255) { + fHalf = 255; + } + + gi.SetBroadcastVisible(vStart, vEnd); + gi.MSG_StartCGM(CGM_FENCEPOST); + gi.MSG_WriteCoord(vStart[0]); + gi.MSG_WriteCoord(vStart[1]); + gi.MSG_WriteCoord(vStart[2]); + gi.MSG_WriteCoord(vEnd[0]); + gi.MSG_WriteCoord(vEnd[1]); + gi.MSG_WriteCoord(vEnd[2]); + gi.MSG_WriteByte((int)fHalf); + gi.MSG_WriteByte(0); + gi.MSG_EndCGM(); + + deadflag = DEAD_DEAD; + + PostEvent(EV_Remove, 0); +} + Event EV_SetEnemyName ( "enemyname", diff --git a/code/fgame/Entities.h b/code/fgame/Entities.h index 75fce27c..806ef6b4 100644 --- a/code/fgame/Entities.h +++ b/code/fgame/Entities.h @@ -342,6 +342,10 @@ class FencePost : public Entity { public: CLASS_PROTOTYPE(FencePost); + + FencePost(); + + void Killed(Event* ev) override; }; class AISpawnPoint : public SimpleArchivedEntity diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 0824473c..9cfed026 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -753,7 +753,7 @@ movement on the server game. CGM_NOTIFY_KILL, CGM_NOTIFY_HIT, CGM_VOICE_CHAT, - CGM_UNKNOWN_1, + CGM_FENCEPOST, }; enum cg_message_ver_6_e { From 048a97329028b10967700eff7748b75a20ed0325 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 00:20:32 +0200 Subject: [PATCH 0316/2040] Added GetProjectileHitsRemaining --- code/fgame/vehicle.cpp | 4 ++++ code/fgame/vehicle.h | 8 +++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 0ce9fad1..76cc8825 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -6459,6 +6459,10 @@ void Vehicle::EventCanUse(Event *ev) } } +int Vehicle::GetProjectileHitsRemaining() const { + return m_iProjectileHitsRemaining; +} + /* ==================== Vehicle::Archive diff --git a/code/fgame/vehicle.h b/code/fgame/vehicle.h index 143a7270..cac1a6e1 100644 --- a/code/fgame/vehicle.h +++ b/code/fgame/vehicle.h @@ -326,11 +326,6 @@ protected: virtual void VehicleStart(Event *ev); virtual void VehicleTouched(Event *ev); virtual void VehicleBlocked(Event *ev); - // Added in 2.30 - //==== - void SetProjectileVulnerable(Event *ev); - void DoProjectileVulnerability(Entity *pProjectile, Entity *pOwner, meansOfDeath_t meansOfDeath); - //==== void Think(void) override; void Postthink(void) override; virtual void Drivable(Event *ev); @@ -525,6 +520,9 @@ public: //==== void EventSetMaxUseAngle(Event *ev); void EventCanUse(Event *ev); + int GetProjectileHitsRemaining() const; + void SetProjectileVulnerable(Event* ev); + void DoProjectileVulnerability(Entity* pProjectile, Entity* pOwner, meansOfDeath_t meansOfDeath); //==== }; From a5d637dbb3f96f9b7321efd6d56ee44c28f30836 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 00:21:23 +0200 Subject: [PATCH 0317/2040] Added GetOwner() --- code/fgame/VehicleCollisionEntity.cpp | 77 +++++++++++---------------- code/fgame/VehicleCollisionEntity.h | 32 +++++------ 2 files changed, 45 insertions(+), 64 deletions(-) diff --git a/code/fgame/VehicleCollisionEntity.cpp b/code/fgame/VehicleCollisionEntity.cpp index a63a51e6..c6520698 100644 --- a/code/fgame/VehicleCollisionEntity.cpp +++ b/code/fgame/VehicleCollisionEntity.cpp @@ -24,69 +24,56 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "VehicleCollisionEntity.h" #include "g_phys.h" -CLASS_DECLARATION( Entity, VehicleCollisionEntity, NULL ) -{ - { &EV_Damage, &VehicleCollisionEntity::EventDamage }, - { NULL, NULL } +CLASS_DECLARATION(Entity, VehicleCollisionEntity, NULL) { + {&EV_Damage, &VehicleCollisionEntity::EventDamage}, + {NULL, NULL } }; -VehicleCollisionEntity::VehicleCollisionEntity - ( - Entity *ent - ) +VehicleCollisionEntity::VehicleCollisionEntity(Entity *ent) { - if( LoadingSavegame ) - { - return; - } + if (LoadingSavegame) { + return; + } - edict->s.eType = ET_GENERAL; + edict->s.eType = ET_GENERAL; - m_pOwner = ent; - takedamage = DAMAGE_YES; + m_pOwner = ent; + takedamage = DAMAGE_YES; - showModel(); - setMoveType( MOVETYPE_PUSH ); - setSolidType(SOLID_NOT); + showModel(); + setMoveType(MOVETYPE_PUSH); + setSolidType(SOLID_NOT); - edict->clipmask |= MASK_VEHICLE; - edict->s.eFlags |= EF_LINKANGLES; + edict->clipmask |= MASK_VEHICLE; + edict->s.eFlags |= EF_LINKANGLES; } -VehicleCollisionEntity::VehicleCollisionEntity - ( - void - ) +VehicleCollisionEntity::VehicleCollisionEntity(void) { - if( LoadingSavegame ) - { - return; - } + if (LoadingSavegame) { + return; + } - gi.Error( ERR_DROP, "VehicleCollisionEntity Created with no parameters!\n" ); + gi.Error(ERR_DROP, "VehicleCollisionEntity Created with no parameters!\n"); } -void VehicleCollisionEntity::EventDamage - ( - Event *ev - ) +void VehicleCollisionEntity::EventDamage(Event *ev) { - m_pOwner->ProcessEvent(*ev); + m_pOwner->ProcessEvent(*ev); } -void VehicleCollisionEntity::Solid - ( - void - ) +void VehicleCollisionEntity::Solid(void) { - setContents( CONTENTS_SOLID ); - setSolidType( SOLID_BSP ); + setContents(CONTENTS_SOLID); + setSolidType(SOLID_BSP); } -void VehicleCollisionEntity::NotSolid - ( - void - ) +void VehicleCollisionEntity::NotSolid(void) { - setSolidType( SOLID_NOT ); + setSolidType(SOLID_NOT); +} + +Entity *VehicleCollisionEntity::GetOwner() const +{ + return m_pOwner; } diff --git a/code/fgame/VehicleCollisionEntity.h b/code/fgame/VehicleCollisionEntity.h index f2b508a1..4d08b04c 100644 --- a/code/fgame/VehicleCollisionEntity.h +++ b/code/fgame/VehicleCollisionEntity.h @@ -21,40 +21,34 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // VehicleCollisionEntity.h : MOHAA vehicle collision -#ifndef __VEHICLECOLLISIONENTITY_H__ -#define __VEHICLECOLLISIONENTITY_H__ +#pragma once #include "entity.h" class VehicleCollisionEntity : public Entity { private: - EntityPtr m_pOwner; + EntityPtr m_pOwner; private: - void EventDamage( Event *ev ); + void EventDamage(Event *ev); public: - CLASS_PROTOTYPE( VehicleCollisionEntity ); + CLASS_PROTOTYPE(VehicleCollisionEntity); - VehicleCollisionEntity( Entity *ent ); - VehicleCollisionEntity(); + VehicleCollisionEntity(Entity *ent); + VehicleCollisionEntity(); - void Archive( Archiver& arc ) override; + void Archive(Archiver& arc) override; - void Solid( void ); - void NotSolid( void ); + void Solid(void); + void NotSolid(void); + Entity *GetOwner() const; }; -inline -void VehicleCollisionEntity::Archive - ( - Archiver& arc - ) +inline void VehicleCollisionEntity::Archive(Archiver& arc) { - Entity::Archive( arc ); + Entity::Archive(arc); - arc.ArchiveSafePointer( &m_pOwner ); + arc.ArchiveSafePointer(&m_pOwner); } - -#endif // __VEHICLECOLLISIONENTITY_H__ \ No newline at end of file From 99647e677a71852797973124cc45a01cbbf805e2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 00:22:35 +0200 Subject: [PATCH 0318/2040] Do projectile vulnerability for vehicles --- code/fgame/weaputils.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index 7e1f5db5..52918e5a 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -1231,8 +1231,8 @@ void Projectile::Touch(Event *ev) weap->m_iNumTorsoShots++; if (weap->IsSubclassOfVehicleTurretGun()) { - VehicleTurretGun *t = (VehicleTurretGun *)weap.Pointer(); - Player *p = (Player *)t->GetRemoteOwner().Pointer(); + VehicleTurretGun* t = (VehicleTurretGun*)weap.Pointer(); + Player* p = (Player*)t->GetRemoteOwner().Pointer(); if (p && p->IsSubclassOfPlayer()) { p->m_iNumHits++; @@ -1260,10 +1260,33 @@ void Projectile::Touch(Event *ev) PostEvent(EV_Remove, 0); // Call the explosion event - Event *explEv; + Event* explEv; explEv = new Event(EV_Projectile_Explode); explEv->AddEntity(other); ProcessEvent(explEv); + + Vehicle* pVehicle = NULL; + + // Added in 2.30 + if (other->IsSubclassOfVehicle()) { + pVehicle = static_cast(other); + } else if (other->IsSubclassOfVehicleTurretGun()) { + VehicleTurretGun* pTurret = static_cast(other); + Entity* pEnt = pTurret->GetVehicle(); + if (pEnt->IsSubclassOfVehicle()) { + pVehicle = static_cast(pEnt); + } + } else if (other->isSubclassOf(VehicleCollisionEntity)) { + VehicleCollisionEntity* pCollision = static_cast(other); + + if (pCollision && pCollision->GetOwner()->IsSubclassOfVehicle()) { + pVehicle = static_cast(pCollision->GetOwner()); + } + } + + if (pVehicle && pVehicle->GetProjectileHitsRemaining() > 0) { + pVehicle->DoProjectileVulnerability(this, owner, meansofdeath); + } } void Projectile::SetCanHitOwner(Event *ev) From eea8c4226856de4a30483db49bcb554bde80dce5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:37:49 +0200 Subject: [PATCH 0319/2040] Added GetOwner event --- code/fgame/VehicleCollisionEntity.cpp | 25 +++++++++++++++++++++++-- code/fgame/VehicleCollisionEntity.h | 2 ++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/code/fgame/VehicleCollisionEntity.cpp b/code/fgame/VehicleCollisionEntity.cpp index c6520698..8c53faa6 100644 --- a/code/fgame/VehicleCollisionEntity.cpp +++ b/code/fgame/VehicleCollisionEntity.cpp @@ -24,8 +24,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "VehicleCollisionEntity.h" #include "g_phys.h" +Event EV_Owner +( + "owner", + EV_DEFAULT, + NULL, + NULL, + "owner", + EV_GETTER +); + CLASS_DECLARATION(Entity, VehicleCollisionEntity, NULL) { {&EV_Damage, &VehicleCollisionEntity::EventDamage}, + {&EV_Owner, &VehicleCollisionEntity::GetOwner }, {NULL, NULL } }; @@ -57,9 +68,9 @@ VehicleCollisionEntity::VehicleCollisionEntity(void) gi.Error(ERR_DROP, "VehicleCollisionEntity Created with no parameters!\n"); } -void VehicleCollisionEntity::EventDamage(Event *ev) +void VehicleCollisionEntity::GetOwner(Event *ev) { - m_pOwner->ProcessEvent(*ev); + ev->AddListener(m_pOwner); } void VehicleCollisionEntity::Solid(void) @@ -73,6 +84,16 @@ void VehicleCollisionEntity::NotSolid(void) setSolidType(SOLID_NOT); } +void VehicleCollisionEntity::EventDamage(Event *ev) +{ + m_pOwner->ProcessEvent(*ev); +} + +void VehicleCollisionEntity::Used(Event *ev) +{ + m_pOwner->ProcessEvent(*ev); +} + Entity *VehicleCollisionEntity::GetOwner() const { return m_pOwner; diff --git a/code/fgame/VehicleCollisionEntity.h b/code/fgame/VehicleCollisionEntity.h index 4d08b04c..5185fc3c 100644 --- a/code/fgame/VehicleCollisionEntity.h +++ b/code/fgame/VehicleCollisionEntity.h @@ -32,6 +32,8 @@ private: private: void EventDamage(Event *ev); + void GetOwner(Event *ev); + void Used(Event *ev); public: CLASS_PROTOTYPE(VehicleCollisionEntity); From d6870ecbeec0410352713927ac31cb84aaf00d10 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:44:03 +0200 Subject: [PATCH 0320/2040] Added trigger_sideduse from 2.30 --- code/fgame/trigger.cpp | 23 ++++++++++++++++++++++- code/fgame/trigger.h | 11 +++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/code/fgame/trigger.cpp b/code/fgame/trigger.cpp index 11cc3392..f2aebed3 100644 --- a/code/fgame/trigger.cpp +++ b/code/fgame/trigger.cpp @@ -457,7 +457,7 @@ void Trigger::TriggerStuff(Event *ev) // if we setup an angle for this trigger, only trigger if other is within ~60 degrees of the triggers origin // only test for this case if we were touched, activating or killed should never go through this code // - if (useTriggerDir && (*ev == EV_Touch)) { + if (useTriggerDir && (*ev == EV_Touch || (*ev == EV_Use && isSubclassOf(TriggerSidedUse)))) { Vector norm; float dot; @@ -1951,6 +1951,27 @@ CLASS_DECLARATION(Trigger, TriggerUse, "trigger_use") { TriggerUse::TriggerUse() {} +/*****************************************************************************/ +/*QUAKED trigger_sideduse (1 0 0) ? x x NOT_PLAYERS MONSTERS + +Activates targets when 'used' by an entity. It is usable only within specific degrees. +"setthread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters + +******************************************************************************/ + +CLASS_DECLARATION(TriggerUse, TriggerSidedUse, "trigger_sideduse") { + {NULL, NULL} +}; + +TriggerSidedUse::TriggerSidedUse() {} + /*****************************************************************************/ /*QUAKED trigger_useonce (1 0 0) ? x x NOT_PLAYERS MONSTERS diff --git a/code/fgame/trigger.h b/code/fgame/trigger.h index d8adabe4..aabcc2c1 100644 --- a/code/fgame/trigger.h +++ b/code/fgame/trigger.h @@ -401,6 +401,17 @@ public: TriggerUse(); }; +// +// Added in 2.30 +// Can only be triggered if within specific degrees +class TriggerSidedUse : public TriggerUse +{ +public: + CLASS_PROTOTYPE(TriggerSidedUse); + + TriggerSidedUse(); +}; + class TriggerUseOnce : public TriggerUse { public: From 6731f56aead3a52cc8ae33f237dc8c1be78781ae Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 10 Apr 2024 23:42:09 +0200 Subject: [PATCH 0321/2040] Fixed m_PrevCodePos usage --- code/script/scriptvm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/script/scriptvm.cpp b/code/script/scriptvm.cpp index a2bcb5fd..168ce2a3 100644 --- a/code/script/scriptvm.cpp +++ b/code/script/scriptvm.cpp @@ -1800,8 +1800,8 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) // the target name was not found m_VMStack.GetTop().setListenerValue(NULL); - if ((*m_CodePos >= OP_BIN_EQUALITY && *m_CodePos <= OP_BIN_GREATER_THAN_OR_EQUAL) - || (*m_CodePos >= OP_BOOL_UN_NOT && *m_CodePos <= OP_UN_CAST_BOOLEAN)) { + if ((*m_PrevCodePos >= OP_BIN_EQUALITY && *m_PrevCodePos <= OP_BIN_GREATER_THAN_OR_EQUAL) + || (*m_PrevCodePos >= OP_BOOL_UN_NOT && *m_PrevCodePos <= OP_UN_CAST_BOOLEAN)) { ScriptError("Targetname '%s' does not exist.", targetname.c_str()); } } else if (targetList->NumObjects() == 1) { From f9901787b596047b85678d8a5309d645c4947996 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:26:45 +0200 Subject: [PATCH 0322/2040] Removed "touch" unregistration --- code/fgame/g_phys.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index 33133913..7e4314fb 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -190,16 +190,11 @@ void G_Impact trace_t *trace ) { - gentity_t *e2; - Event *ev; - SafePtr< Entity > safe1; - SafePtr< Entity > safe2; + gentity_t *e2; + Event *ev; e2 = trace->ent; - safe1 = e1; - safe2 = e2->entity; - level.impact_trace = *trace; // touch anything, including the world @@ -208,10 +203,6 @@ void G_Impact ev = new Event( EV_Touch ); ev->AddEntity( e2->entity ); e1->ProcessEvent( ev ); - - if( safe1 ) { - safe1->Unregister( "touch" ); - } } // entity could have been removed, so check if he's in use before sending the event @@ -225,10 +216,6 @@ void G_Impact ev = new Event( EV_Touch ); ev->AddEntity( e1 ); e2->entity->ProcessEvent( ev ); - - if( safe2 ) { - safe2->Unregister( "touch" ); - } } memset( &level.impact_trace, 0, sizeof( level.impact_trace ) ); From 927f4bb4bd74267108a418d9c157ccbb252c67af Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:30:00 +0200 Subject: [PATCH 0323/2040] Marked overridden virtual methods --- code/fgame/camera.h | 2 +- code/fgame/misc.h | 2 +- code/fgame/object.h | 2 +- code/fgame/player.h | 2 +- code/fgame/playerbot.h | 2 +- code/fgame/vehicle.h | 2 +- code/fgame/weapturret.h | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/fgame/camera.h b/code/fgame/camera.h index c0f077ff..fafde254 100644 --- a/code/fgame/camera.h +++ b/code/fgame/camera.h @@ -241,7 +241,7 @@ protected: Vector CalculatePosition(void); Vector CalculateOrientation(void); float CalculateFov(void); - virtual void bind(Entity *master, qboolean use_my_angles = false); + virtual void bind(Entity *master, qboolean use_my_angles = false) override; void unbind(void) override; public: diff --git a/code/fgame/misc.h b/code/fgame/misc.h index 3edc142a..51909c7f 100644 --- a/code/fgame/misc.h +++ b/code/fgame/misc.h @@ -565,7 +565,7 @@ public: void EnsureOverLadder(Entity *pUser); void EnsureForwardOffLadder(Entity *pUser); - void Archive(Archiver& arc); + void Archive(Archiver& arc) override; }; inline void FuncLadder::Archive(Archiver& arc) diff --git a/code/fgame/object.h b/code/fgame/object.h index 24cefb0a..fe3fedfe 100644 --- a/code/fgame/object.h +++ b/code/fgame/object.h @@ -46,7 +46,7 @@ public: InteractObject(); void Damaged(Event *ev); - void Killed(Event *ev); + void Killed(Event *ev) override; void Setup(Event *ev); void EventHitEffect(Event *ev); void EventKilledEffect(Event *ev); diff --git a/code/fgame/player.h b/code/fgame/player.h index 03501e3c..5eebc593 100644 --- a/code/fgame/player.h +++ b/code/fgame/player.h @@ -539,7 +539,7 @@ public: void DoUse(Event *ev); void Obituary(Entity *attacker, Entity *inflictor, int meansofdeath, int iLocation); - void Killed(Event *ev); + void Killed(Event *ev) override; void Dead(Event *ev); void Pain(Event *ev); diff --git a/code/fgame/playerbot.h b/code/fgame/playerbot.h index c39954fe..e7f24707 100644 --- a/code/fgame/playerbot.h +++ b/code/fgame/playerbot.h @@ -174,7 +174,7 @@ public: void Spawned(void) override; - void Killed(Event *ev); + void Killed(Event *ev) override; void GotKill(Event *ev); void EventStuffText(Event *ev); }; diff --git a/code/fgame/vehicle.h b/code/fgame/vehicle.h index cac1a6e1..b8709df2 100644 --- a/code/fgame/vehicle.h +++ b/code/fgame/vehicle.h @@ -533,7 +533,7 @@ public: DrivableVehicle(void); - virtual void Killed(Event *ev); + virtual void Killed(Event *ev) override; }; class VehicleWheelsX4 : public DrivableVehicle diff --git a/code/fgame/weapturret.h b/code/fgame/weapturret.h index 1b200081..6646dbf9 100644 --- a/code/fgame/weapturret.h +++ b/code/fgame/weapturret.h @@ -200,8 +200,8 @@ public: void StopWeaponAnim() override; bool AI_CanTarget(const vec3_t org); - virtual float FireDelay(firemode_t mode); - virtual void SetFireDelay(Event *ev); // added in 2.0 + virtual float FireDelay(firemode_t mode) override; + virtual void SetFireDelay(Event *ev) override; // added in 2.0 void ShowInfo(float fDot, float fDist) override; // added in 2.0 From 0e20d7e880358174354af53a9f3c61968193e2d6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 14 Apr 2024 23:03:46 +0200 Subject: [PATCH 0324/2040] Fixed arm/arm64 binary loading on Windows (fixes #295) --- code/qcommon/q_platform.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index fdf0c25f..86d28c81 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -107,9 +107,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PATH_SEP '\\' #if defined(_WIN64) || defined( __WIN64__ ) -#define ARCH_STRING "x86_64" +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) +# define ARCH_STRING "x86_64" +#elif defined(__aarch64__) || defined(__ARM64__) || defined (_M_ARM64) +# define ARCH_STRING "arm64" +#endif #elif defined _M_ALPHA -#define ARCH_STRING "AXP" +# define ARCH_STRING "AXP" #endif #define Q3_LITTLE_ENDIAN From f39a4c0bc7c35159f49a941a1eb805751cb9a356 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:47:39 +0200 Subject: [PATCH 0325/2040] Fixed projectile explosion origin. This fixes exploder triggers sometimes never being triggered (fixes #294) --- code/fgame/weaputils.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index 52918e5a..f675709b 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -892,11 +892,13 @@ void Projectile::Explode(Event *ev) // Move the projectile back off the surface a bit so we can see // explosion effects. Vector dir, v; - v = velocity; - v.normalize(); - dir = v; - v = origin - v * 36; - setOrigin(v); + dir = velocity; + if (dir.normalize() == 0) { + vec3_t forward; + AngleVectors(angles, forward, NULL, NULL); + dir = forward; + } + v = origin; ExplosionAttack(v, owner, explosionmodel, dir, ignoreEnt, 1.0f, weap, m_bHurtOwnerOnly); } From 054201bea997bb948b7cfab3c102224da37c3af6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Apr 2024 19:07:08 +0200 Subject: [PATCH 0326/2040] Fixed character assertion fail when the character was a value below 0 --- code/sys/win_localization.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/sys/win_localization.cpp b/code/sys/win_localization.cpp index 02eb35ee..fbda671c 100644 --- a/code/sys/win_localization.cpp +++ b/code/sys/win_localization.cpp @@ -228,20 +228,20 @@ static int bjb_strnscmp( const char *a, const char *b, size_t n ) { while( 1 ) { - while( isspace( *a ) ) + while( isspace( (unsigned char)*a ) ) a++; - while( isspace( *b ) ) + while( isspace( (unsigned char)*b ) ) b++; while( *a && *a == *b ) a++, b++; - if( isspace( *a ) ) + if( isspace( (unsigned char)*a ) ) { - if( isalnum( a[ -1 ] ) && isalnum( *b ) ) + if( isalnum( (unsigned char)a[ -1 ] ) && isalnum( (unsigned char)*b ) ) break; } - else if( isspace( *b ) ) + else if( isspace( (unsigned char)*b ) ) { - if( isalnum( b[ -1 ] ) && isalnum( *a ) ) + if( isalnum( (unsigned char)b[ -1 ] ) && isalnum( (unsigned char)*a ) ) break; } else From 06dab5d8b0a688187eb848e4076e6ff0a42262a9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Apr 2024 19:39:32 +0200 Subject: [PATCH 0327/2040] Refactored ScriptThread::EventPointsWithinDist for more clarity --- code/fgame/scriptthread.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index a5f74957..9cbd5bd9 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -4183,12 +4183,16 @@ void ScriptThread::EventAIsCloserThanBToC(Event *ev) void ScriptThread::EventPointsWithinDist(Event *ev) { Vector delta; - float dist = ev->GetFloat(3); - - delta = ev->GetVector(1) - ev->GetVector(2); + Vector v1, v2; + float fDistance; + + v1 = ev->GetVector(1); + v2 = ev->GetVector(2); + fDistance = ev->GetFloat(3); + delta = v1 - v2; // check squared distance - ev->AddInteger(((delta * delta) < (dist * dist))); + ev->AddInteger(delta.lengthSquared() < Square(fDistance)); } bool ScriptThread::CanScriptTracePrint(void) From 4630a1f386e0e51898a4447c9f8a865e6786716e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Apr 2024 19:40:33 +0200 Subject: [PATCH 0328/2040] Fixed wrong return values for Vehicle::EventCanUse It fixes Modello being hardly usable on maps like e3l2 --- code/fgame/vehicle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 76cc8825..93684170 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -6453,9 +6453,9 @@ void Vehicle::EventCanUse(Event *ev) VectorNormalize(vDir); if (fabs(GetAngleBetweenVectors2D(vForward, vDir)) > m_fMaxUseAngle) { - ev->AddInteger(1); + ev->AddInteger(false); } else { - ev->AddInteger(0); + ev->AddInteger(true); } } From 5ee7cb16bb76b209b030f8fd960023b8b2aa51da Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Apr 2024 20:28:54 +0200 Subject: [PATCH 0329/2040] for ANIM_MODE_SCRIPTED and ANIM_MODE_NOCLIP, set the yaw based on the angular delta --- code/fgame/actor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 805dfd90..c21d4820 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -3674,6 +3674,7 @@ void Actor::DoMove(void) MoveDest(frame_delta.length() / level.frametime); break; case ANIM_MODE_SCRIPTED: + setAngles(angles + Vector(0, angular_delta, 0)); trace = G_Trace( origin, mins, maxs, origin + frame_delta, this, edict->clipmask & ~MASK_SCRIPT_SLAVE, qtrue, "Actor" ); @@ -3681,6 +3682,7 @@ void Actor::DoMove(void) velocity = frame_delta / level.frametime; break; case ANIM_MODE_NOCLIP: + setAngles(angles + Vector(0, angular_delta, 0)); SafeSetOrigin(origin + frame_delta); velocity = frame_delta / level.frametime; break; From 19c68aa25d2887bcfdff1b5d3f159109a6d8476d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 21 Apr 2024 20:33:31 +0200 Subject: [PATCH 0330/2040] Ignore player collision if the actor is already nonsolid This fixes #277 where the vehicle could get stuck due to the actor being solid afterwards --- code/fgame/actor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index c21d4820..3c417781 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -3625,7 +3625,9 @@ void Actor::SafeSetOrigin(vec3_t newOrigin) if (!m_bNoPlayerCollision) { Player *p = (Player *)G_GetEntity(0); - if (p && IsTouching(p)) { + // Solidity check added in 2.30 + // If the Actor is already nonsolid the player won't get stuck + if (p && IsTouching(p) && getSolidType() != SOLID_NOT) { Com_Printf("(entnum %d, radnum %d) is going not solid to not get stuck in the player\n", entnum, radnum); m_bNoPlayerCollision = true; setSolidType(SOLID_NOT); From 6d10ed27c54af1d11c3709abe4a13c464b13076e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:48:24 +0200 Subject: [PATCH 0331/2040] Fixed preferred weapon not showing on stats screen Fixes #271 --- code/fgame/player.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 6dcac54d..40fd9b37 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -10087,7 +10087,9 @@ void Player::Stats(Event *ev) } } - szPreferredWeapon = m_sPerferredWeaponOverride; + if (m_sPerferredWeaponOverride.length()) { + szPreferredWeapon = m_sPerferredWeaponOverride; + } if (iNumHits) { Com_sprintf( From ee48193f15f5e4042907b8f1b5c699ef6e229460 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:21:13 +0200 Subject: [PATCH 0332/2040] Added notagaxis Fixes #222 --- code/cgame/cg_commands.cpp | 24 ++++++++++++++++++++++-- code/cgame/cg_commands.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/code/cgame/cg_commands.cpp b/code/cgame/cg_commands.cpp index 30e45fda..9ea70dd0 100644 --- a/code/cgame/cg_commands.cpp +++ b/code/cgame/cg_commands.cpp @@ -196,7 +196,8 @@ Event EV_Client_SetColorVelocity "rVel gVel bVel", "Set the color velocity of the spawned dlight tempmodel" ); -Event EV_Client_SetRandomVelocity( +Event EV_Client_SetRandomVelocity +( "randvel", EV_DEFAULT, "SfFSfFSfF", @@ -210,7 +211,8 @@ Event EV_Client_SetRandomVelocity( "without randomness.\n" "This velocity is applied using the world axis" ); -Event EV_Client_SetRandomVelocityAlongAxis( +Event EV_Client_SetRandomVelocityAlongAxis +( "randvelaxis", EV_DEFAULT, "SfFSfFSfF", @@ -225,6 +227,14 @@ Event EV_Client_SetRandomVelocityAlongAxis( "without randomness.\n" "This velocity is applied using the parent axis" ); +Event EV_Client_NoTagAxis +( + "notagaxis", + EV_DEFAULT, + NULL, + NULL, + "Forces the effect to use the model's orientation for randvelaxis and offsetalongaxis" +); Event EV_Client_SetAccel ( "accel", @@ -1221,6 +1231,7 @@ CLASS_DECLARATION(Listener, ClientGameCommandManager, NULL) { {&EV_Client_SetColorVelocity, &ClientGameCommandManager::SetAngularVelocity }, {&EV_Client_SetRandomVelocity, &ClientGameCommandManager::SetRandomVelocity }, {&EV_Client_SetRandomVelocityAlongAxis, &ClientGameCommandManager::SetRandomVelocityAlongAxis}, + {&EV_Client_NoTagAxis, &ClientGameCommandManager::SetNoTagAxis }, {&EV_Client_SetAccel, &ClientGameCommandManager::SetAccel }, {&EV_Client_SetFriction, &ClientGameCommandManager::SetFriction }, {&EV_Client_SetSpin, &ClientGameCommandManager::SetSpin }, @@ -2668,6 +2679,15 @@ void ClientGameCommandManager::SetRandomVelocityAlongAxis(Event *ev) SetRandomVelocity(ev); } +void ClientGameCommandManager::SetNoTagAxis(Event* ev) +{ + if (!m_spawnthing) { + return; + } + + m_spawnthing->cgd.flags2 |= T2_NOTAGAXIS; +} + void ClientGameCommandManager::SetRadialVelocity(Event *ev) { if (!m_spawnthing) { diff --git a/code/cgame/cg_commands.h b/code/cgame/cg_commands.h index 7bd22fd2..27565d81 100644 --- a/code/cgame/cg_commands.h +++ b/code/cgame/cg_commands.h @@ -113,6 +113,7 @@ TIKI file, similar to ScriptMaster in the server game dll. #define T2_VARYCOLOR (1 << 20) #define T2_SPIN (1 << 21) #define T2_RELATIVEANGLES (1 << 22) +#define T2_NOTAGAXIS (1 << 23) class spawnthing_t; class specialeffect_t; @@ -788,6 +789,7 @@ private: void SetScaleRate(Event *ev); void SetRandomVelocity(Event *ev); void SetRandomVelocityAlongAxis(Event *ev); + void SetNoTagAxis(Event *ev); // Added in 2.0 void SetAccel(Event *ev); void SetFriction(Event *ev); void SetSpin(Event *ev); From e89543710c74fe1cc66e460d624865e880fce3c3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:04:14 +0200 Subject: [PATCH 0333/2040] Check for max use angle when using the vehicle --- code/fgame/vehicle.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 93684170..97404b67 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -3678,6 +3678,23 @@ void Vehicle::DriverUse(Event *ev) return; } + // Added in 2.30 + // Check use angle + if (!driver.ent && m_fMaxUseAngle && ent && Turrets[0].ent) { + Vector vForward; + Vector vDir; + + AngleVectors(Turrets[0].ent->angles, vForward, NULL, NULL); + + vDir = Turrets[0].ent->origin - ent->origin; + VectorNormalize(vDir); + + if (fabs(GetAngleBetweenVectors2D(vForward, vDir)) > m_fMaxUseAngle) { + // Not usable + return; + } + } + if (ev->NumArgs() == 2) { if (ev->IsVectorAt(2)) { vExitPosition = ev->GetVector(2); From 26c33751127e341866be26f544c3d49f528a5bc2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:28:56 +0200 Subject: [PATCH 0334/2040] When there is no enter_boneindex for turret slot, use the boneindex instead This fixes #208 --- code/fgame/vehicle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 97404b67..b521598c 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -1503,6 +1503,9 @@ void Vehicle::QueryTurretSlotPosition(int slot, float *pos) if (Turrets[slot].enter_boneindex >= 0) { GetTagPositionAndOrientation(Turrets[slot].enter_boneindex, &orient); VectorCopy(orient.origin, pos); + } else if (Turrets[slot].boneindex >= 0) { + GetTagPositionAndOrientation(Turrets[slot].boneindex, &orient); + VectorCopy(orient.origin, pos); } else { VectorCopy(origin, pos); } From 48fc5a72b836ccbc0ffb44aa8561f844068a4d45 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 19:59:20 +0200 Subject: [PATCH 0335/2040] Fixed some setters and getters being inverted --- code/fgame/Entities.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/fgame/Entities.cpp b/code/fgame/Entities.cpp index 4f4a279e..18e7e1c1 100644 --- a/code/fgame/Entities.cpp +++ b/code/fgame/Entities.cpp @@ -2338,7 +2338,7 @@ Event EV_SetEnemyName2 "s", "enemyname", "", - EV_GETTER + EV_SETTER ); Event EV_GetEnemyName ( @@ -2347,7 +2347,7 @@ Event EV_GetEnemyName "s", "enemyname", "", - EV_SETTER + EV_GETTER ); Event EV_Sentient_GetDontDropWeapons ( @@ -2663,12 +2663,12 @@ void AISpawnPoint::SetFov(Event *ev) void AISpawnPoint::SetSight(Event *ev) { - ev->AddFloat(m_fSight); + m_fSight = ev->GetFloat(1); } void AISpawnPoint::GetSight(Event *ev) { - m_fSight = ev->GetFloat(1); + ev->AddFloat(m_fSight); } void AISpawnPoint::GetHearing(Event *ev) From 3cd5acf3aaed83c7e1f6d2472412def1732c07ff Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 20:10:01 +0200 Subject: [PATCH 0336/2040] Fixed issue with case-sensitive variables. normal/return commands are case-insensitive getter/setter commands are case-sensitive --- code/fgame/scriptmaster.cpp | 5 ++++- code/qcommon/listener.cpp | 37 ++++++++++++++++++++++++++----- code/qcommon/listener.h | 17 --------------- code/script/scriptcompiler.cpp | 40 +++++++++++++++++++--------------- 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/code/fgame/scriptmaster.cpp b/code/fgame/scriptmaster.cpp index c7730709..40232cd9 100644 --- a/code/fgame/scriptmaster.cpp +++ b/code/fgame/scriptmaster.cpp @@ -541,7 +541,10 @@ void ScriptMaster::InitConstStrings(void) eventDef = en.CurrentValue(); eventnum = (*en.CurrentKey())->eventnum; str command = eventDef->command.c_str(); - command.tolower(); + + if (eventDef->type == EV_NORMAL || eventDef->type == EV_RETURN) { + command.tolower(); + } name = AddString(command); diff --git a/code/qcommon/listener.cpp b/code/qcommon/listener.cpp index d2c1b38e..fb30bc4b 100644 --- a/code/qcommon/listener.cpp +++ b/code/qcommon/listener.cpp @@ -399,8 +399,14 @@ int HashCode(const command_t& key) const char *p; int hash = 0; - for (p = key.command; *p; p++) { - hash = tolower(*p) + 31 * hash; + if (key.type == EV_NORMAL || key.type == EV_RETURN) { + for (p = key.command; *p; p++) { + hash = tolower(*p) + 31 * hash; + } + } else { + for (p = key.command; *p; p++) { + hash = *p + 31 * hash; + } } return hash; @@ -1424,7 +1430,6 @@ FindSetterEventNum */ unsigned int Event::FindSetterEventNum(str s) { - s.tolower(); return FindSetterEventNum(Director.AddString(s)); } @@ -1435,7 +1440,6 @@ FindGetterEventNum */ unsigned int Event::FindGetterEventNum(str s) { - s.tolower(); return FindGetterEventNum(Director.AddString(s)); } @@ -1452,8 +1456,10 @@ int Event::GetEventWithFlags(str name, int flags, uchar type) con_map *cmdList; if (type == EV_NORMAL) { + name.tolower(); cmdList = &normalCommandList; } else if (type == EV_RETURN) { + name.tolower(); cmdList = &returnCommandList; } else if (type == EV_GETTER) { cmdList = &getterCommandList; @@ -1463,8 +1469,6 @@ int Event::GetEventWithFlags(str name, int flags, uchar type) return 0; } - name.tolower(); - index = cmdList->find(Director.GetString(name)); if (!index || !(GetEventFlags(*index) & flags)) { @@ -4352,3 +4356,24 @@ command_t::command_t(const char *name, byte t) : command(name) , type(t) {} + +bool operator==(const char* name, const command_t& command) +{ + if (command.type == EV_NORMAL || command.type == EV_RETURN) { + return !str::icmp(name, command.command); + } else { + return !str::cmp(name, command.command); + } +} + +#ifdef WITH_SCRIPT_ENGINE +bool operator==(const command_t& cmd1, const command_t& cmd2) +{ + return (!str::icmp(cmd1.command, cmd2.command) && (cmd2.type == (uchar)-1 || cmd2.type == cmd1.type)); +} +#else +bool operator==(const command_t& cmd1, const command_t& cmd2) +{ + return (!str::icmp(cmd1.command, cmd2.command)); +} +#endif \ No newline at end of file diff --git a/code/qcommon/listener.h b/code/qcommon/listener.h index ef3b8c12..70acb320 100644 --- a/code/qcommon/listener.h +++ b/code/qcommon/listener.h @@ -242,23 +242,6 @@ public: friend bool operator==(const command_t& cmd1, const command_t& cmd2); }; -inline bool operator==(const char *name, const command_t& command) -{ - return !str::icmp(name, command.command); -} - -#ifdef WITH_SCRIPT_ENGINE -inline bool operator==(const command_t& cmd1, const command_t& cmd2) -{ - return (!str::icmp(cmd1.command, cmd2.command) && (cmd2.type == (uchar)-1 || cmd2.type == cmd1.type)); -} -#else -inline bool operator==(const command_t& cmd1, const command_t& cmd2) -{ - return (!str::icmp(cmd1.command, cmd2.command)); -} -#endif - class Event : public Class { public: diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index 9e6eeaeb..17dfcf18 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -252,7 +252,7 @@ void ScriptCompiler::EmitAssignmentStatement(sval_t lhs, unsigned int sourcePos) unsigned int index; sval_t listener_val; const char *name = lhs.node[2].stringValue; - str name_lowered; + //str name_lowered; if (lhs.node[0].type != ENUM_field) { if (lhs.node[0].type == ENUM_array_expr) { @@ -265,10 +265,10 @@ void ScriptCompiler::EmitAssignmentStatement(sval_t lhs, unsigned int sourcePos) return; } - name_lowered = name; - name_lowered.tolower(); - index = Director.AddString(name_lowered); - eventnum = Event::FindSetterEventNum(name_lowered); + //name_lowered = name; + //name_lowered.tolower(); + index = Director.AddString(name); + eventnum = Event::FindSetterEventNum(name); listener_val = lhs.node[1]; @@ -477,7 +477,8 @@ void ScriptCompiler::EmitField(sval_t listener_val, sval_t field_val, unsigned i unsigned int eventnum = 0; unsigned int index = -1; unsigned int prev_index; - str name_lowered; + const char* name; + //str name_lowered; /* if (field_val.node[0].stringValue) { @@ -494,10 +495,11 @@ void ScriptCompiler::EmitField(sval_t listener_val, sval_t field_val, unsigned i } */ - name_lowered = field_val.stringValue; - name_lowered.tolower(); - index = Director.AddString(name_lowered); - eventnum = Event::FindGetterEventNum(name_lowered); + name = field_val.stringValue; + //name_lowered = name; + //name_lowered.tolower(); + index = Director.AddString(name); + eventnum = Event::FindGetterEventNum(name); prev_index = GetOpcodeValue(sizeof(unsigned int), sizeof(unsigned int)); @@ -918,10 +920,10 @@ void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) sval_u listener_val = lhs.node[1]; const char *name = lhs.node[2].stringValue; - name_lowered = name; - name_lowered.tolower(); + //name_lowered = name; + //name_lowered.tolower(); - int eventnum = Event::FindSetterEventNum(name_lowered); + int eventnum = Event::FindSetterEventNum(name); if (listener_val.node[0].type != ENUM_listener || (eventnum && BuiltinWriteVariable(sourcePos, listener_val.node[1].byteValue, eventnum))) { @@ -930,7 +932,7 @@ void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) EmitOpcode(OP_STORE_PARAM, sourcePos); EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].byteValue, sourcePos); - unsigned int index = Director.AddString(name_lowered); + unsigned int index = Director.AddString(name); EmitOpcodeValue(index, sizeof(unsigned int)); } } @@ -956,7 +958,8 @@ int ScriptCompiler::EmitParameterList(sval_t event_parameter_list) void ScriptCompiler::EmitRef(sval_t val, unsigned int sourcePos) { unsigned int index; - str name_lowered; + const char* name; + //str name_lowered; if (val.node[0].type != ENUM_field) { if (val.node[0].type == ENUM_array_expr) { @@ -969,9 +972,10 @@ void ScriptCompiler::EmitRef(sval_t val, unsigned int sourcePos) return; } - name_lowered = val.node[2].stringValue; - name_lowered.tolower(); - index = Director.AddString(name_lowered); + name = val.node[2].stringValue; + //name_lowered = name; + //name_lowered.tolower(); + index = Director.AddString(name); EmitValue(val.node[1]); EmitOpcode(OP_STORE_FIELD_REF, sourcePos); From 56dce21538d0b5f6518d8282d70cc8127b7fbf92 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 23:38:45 +0200 Subject: [PATCH 0337/2040] Fixed an invalid access to lighting sphere leaves It was causing crashes on some occasions --- code/renderer/tr_sphere_shade.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_sphere_shade.cpp b/code/renderer/tr_sphere_shade.cpp index b0e0fdb3..fb411ada 100644 --- a/code/renderer/tr_sphere_shade.cpp +++ b/code/renderer/tr_sphere_shade.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -1047,7 +1047,8 @@ static void RB_Sphere_BuildStaticLights() if (tr.world->vis) { int cntarea; - for (curleaf = 0, leaf = backEnd.currentSphere->leaves[curleaf]; curleaf < 8 && leaf; curleaf++, leaf++) { + for (curleaf = 0, leaf = backEnd.currentSphere->leaves[curleaf]; curleaf < 8 && leaf; + curleaf++, leaf = backEnd.currentSphere->leaves[curleaf]) { cntarea = leaf->numlights; if (cntarea) { From cc85d0c1002ce4aa1ede8e7bd0de3cd7d27cffd6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Apr 2024 23:40:00 +0200 Subject: [PATCH 0338/2040] Bumped version number --- code/qcommon/q_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/q_version.h b/code/qcommon/q_version.h index 333a1d0a..743ea48c 100644 --- a/code/qcommon/q_version.h +++ b/code/qcommon/q_version.h @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // // These values are the only one that must be set for the version #define PRODUCT_VERSION_MAJOR 0 -#define PRODUCT_VERSION_MINOR 61 +#define PRODUCT_VERSION_MINOR 62 #define PRODUCT_VERSION_PATCH 0 #define PRODUCT_VERSION_SUFFIX "alpha" From 4b05c400b2de5e2b5ae8a27bc3aa2d498ca53af6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Apr 2024 19:29:54 +0200 Subject: [PATCH 0339/2040] Round to integer for vectoyaw() This fixes Actor never finishing TurnTo as the DesiredYaw was set to a very precise value --- code/qcommon/q_shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 703d130e..293e1afc 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -86,7 +86,7 @@ float vectoyaw(const vec3_t vec) } else { //if (vec[PITCH]) { - yaw = (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI); + yaw = (int)(atan2(vec[YAW], vec[PITCH]) * 180 / M_PI); //} else if (vec[YAW] > 0) { // yaw = 90; //} else { From ac8c18250d89ae46b07d0687e4c69087cd97ee63 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Apr 2024 20:39:54 +0200 Subject: [PATCH 0340/2040] If the actor is an american, always call ThinkHoldGun_TurretGun() without checking for enemy --- code/fgame/actor_machinegunner.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor_machinegunner.cpp b/code/fgame/actor_machinegunner.cpp index 07ddaf0e..30e075a1 100644 --- a/code/fgame/actor_machinegunner.cpp +++ b/code/fgame/actor_machinegunner.cpp @@ -89,8 +89,11 @@ void Actor::End_MachineGunner(void) } Unholster(); - if (m_pTurret && m_pTurret->GetOwner() == this) { - m_pTurret->TurretEndUsed(); + if (m_pTurret) { + m_pTurret->m_bHadOwner = true; + if (m_pTurret->GetOwner() == this) { + m_pTurret->TurretEndUsed(); + } } } @@ -207,6 +210,12 @@ void Actor::Think_MachineGunner_TurretGun(void) UpdateEnemyInternal(); + if (m_Team == TEAM_AMERICAN) { + // Added in 2.30 + ThinkHoldGun_TurretGun(); + return; + } + if (m_pTurret->AI_CanTarget(G_GetEntity(0)->centroid)) { ThinkHoldGun_TurretGun(); return; From 41c322ec81b82dbd76f56107fbf53a0994b572eb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Apr 2024 19:59:16 +0200 Subject: [PATCH 0341/2040] Refactored ScriptSlave::FollowingPath and ScriptSlave::SetupPath with bugfixes --- code/fgame/scriptslave.cpp | 164 ++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 83 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index b99d1e06..03e816d1 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1478,27 +1478,7 @@ void ScriptSlave::FollowingPath(Event *ev) } } - if (m_iCurNode <= 0) { - vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL); - vWishPosition = (vTmp + 1); - vDelta = vWishPosition - origin; - - if (vDelta.length() <= 32.0f) { - m_iCurNode++; - - if (m_iCurNode >= m_pCurPath->m_iPoints) { - velocity = vec_zero; - avelocity = vec_zero; - - delete m_pCurPath; - m_pCurPath = NULL; - m_iCurNode = 0; - moving = false; - ProcessEvent(EV_ScriptSlave_MoveDone); - return; - } - } - } else { + if (m_iCurNode > 0) { vTmp = m_pCurPath->GetByNode(m_iCurNode - 1, NULL); vPrev = (vTmp + 1); vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL); @@ -1509,7 +1489,7 @@ void ScriptSlave::FollowingPath(Event *ev) angles.AngleVectorsLeft(&vWishAngles); fCoef = ProjectLineOnPlane(vWishAngles, DotProduct(origin, vWishAngles), vPrev, vCur, NULL); - + vTmp = m_pCurPath->GetByNode((m_iCurNode - (1.0f - fCoef)), NULL); vTmp = m_pCurPath->Get(vTmp[0] + m_fLookAhead, NULL); vWishPosition = (vTmp + 1); @@ -1517,6 +1497,26 @@ void ScriptSlave::FollowingPath(Event *ev) if (fCoef > 1.0f) { m_iCurNode++; + if (m_iCurNode >= m_pCurPath->m_iPoints) { + velocity = vec_zero; + avelocity = vec_zero; + + delete m_pCurPath; + m_pCurPath = NULL; + m_iCurNode = 0; + moving = false; + ProcessEvent(EV_ScriptSlave_MoveDone); + return; + } + } + } else { + vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL); + vWishPosition = (vTmp + 1); + vDelta = vWishPosition - origin; + + if (vDelta.length() <= 32.0f) { + m_iCurNode++; + if (m_iCurNode >= m_pCurPath->m_iPoints) { velocity = vec_zero; avelocity = vec_zero; @@ -1531,11 +1531,11 @@ void ScriptSlave::FollowingPath(Event *ev) } } - vWishAngles = vWishPosition - origin; + vDelta = vWishPosition - origin; - if (vWishAngles.length() > 0.0f) { - VectorNormalize(vWishAngles); - VectorToAngles(vWishAngles, vNextWishAngles); + if (vDelta.length() > 0.0f) { + vDelta.normalize(); + VectorToAngles(vDelta, vNextWishAngles); // // Added in 2.0 @@ -1545,33 +1545,33 @@ void ScriptSlave::FollowingPath(Event *ev) vNextWishAngles[0] *= -1; } } else { - AngleVectorsLeft(angles, vWishAngles, NULL, NULL); vNextWishAngles = angles; + AngleVectorsLeft(angles, vDelta, NULL, NULL); } vAngles = angles; for (int i = 0; i < 3; i++) { + float change, error; + n_angles[i] = vNextWishAngles[i] - angles[i]; - if (n_angles[i] <= 180.0f) { - if (n_angles[i] < -180.0f) { - n_angles[i] += 360.0f; - } - } else { - n_angles[i] -= 360.0f; + if (n_angles[i] > 180) { + n_angles[i] -= 360; + } else if (n_angles[i] < -180) { + n_angles[i] += 360; } - float change = level.frametime * 360.0f; - float error = 0.33f * n_angles[i]; + change = level.frametime * 360.0f; + error = 0.33f * n_angles[i]; - if (-change > error) { + if (error < -change) { error = -change; - } else if (error <= change) { - change = error; + } else if (error > change) { + error = change; } - primal_angles[i] = change + angles[i]; + primal_angles[i] = angles[i] + error; } setAngles(primal_angles); @@ -1603,15 +1603,15 @@ void ScriptSlave::FollowingPath(Event *ev) } avelocity = vDeltaAngles; - velocity = vWishAngles * m_fCurSpeed; + velocity = vDelta * m_fCurSpeed; - if (m_fCurSpeed < m_fIdealSpeed) { + if (m_fIdealSpeed > m_fCurSpeed) { m_fCurSpeed += m_fIdealAccel * level.frametime; if (m_fCurSpeed > m_fIdealSpeed) { m_fCurSpeed = m_fIdealSpeed; } - } else if (m_fCurSpeed > m_fIdealSpeed) { + } else if (m_fIdealSpeed < m_fCurSpeed) { m_fCurSpeed -= m_fIdealAccel * level.frametime; if (m_fCurSpeed < m_fIdealSpeed) { @@ -1797,15 +1797,11 @@ void ScriptSlave::EventNormalAngles(Event *ev) void ScriptSlave::SetupPath(cSpline<4, 512> *pPath, SimpleEntity *se) { str name; - //int iObjNum; + int iObjNum = 0; Vector vLastOrigin; SimpleEntity *ent; int i; - static cSpline<4, 512> *pTmpPath = NULL; - - if (!pTmpPath) { - pTmpPath = new cSpline<4, 512>; - } + static cSpline<4, 512> *pTmpPath = new cSpline<4, 512>; if (!pPath) { return; @@ -1818,25 +1814,24 @@ void ScriptSlave::SetupPath(cSpline<4, 512> *pPath, SimpleEntity *se) name = se->Target(); - if (name.c_str()) { - Vector vDelta; - vec4_t origin; - float fCurLength; + if (name.length()) { + i = 0; - i = 0; - fCurLength = 0; - ent = se; - while (ent) { - if (vLastOrigin.length() == 0.0f && i > 1) { + for(ent = se; ent; ent = ent->Next()) { + Vector vDelta; + vec4_t vTmp; + + vDelta = vLastOrigin - ent->origin; + + if (vDelta.length() == 0 && i > 1) { Com_Printf("^~^~^Warning: ScriptSlave Flying with a Path that contains 2 equal points\n"); } else { - origin[0] = fCurLength; - origin[1] = ent->origin[0]; - origin[2] = ent->origin[1]; - origin[3] = ent->origin[2]; - pTmpPath->Add(origin, 0); + vTmp[0] = iObjNum++; + vTmp[1] = ent->origin[0]; + vTmp[2] = ent->origin[1]; + vTmp[3] = ent->origin[2]; + pTmpPath->Add(vTmp, 0); vLastOrigin = ent->origin; - fCurLength++; } if (ent == se && i > 1) { @@ -1844,35 +1839,38 @@ void ScriptSlave::SetupPath(cSpline<4, 512> *pPath, SimpleEntity *se) } i++; - ent = ent->Next(); } + } - if (pTmpPath->m_iPoints > 2) { - float *vTmp; + if (pTmpPath->m_iPoints > 2) { + float* vTmp; + float fCurLength = 0; + vec3_t vLastOrigin; + vec3_t origin; + vec3_t vDelta; - pPath->Reset(); - vTmp = pTmpPath->GetByNode(0.0f, 0); + pPath->Reset(); - vLastOrigin[0] = vTmp[1]; - vLastOrigin[1] = vTmp[2]; - vLastOrigin[2] = vTmp[3]; + vTmp = pTmpPath->GetByNode(0, NULL); + VectorCopy((vTmp + 1), vLastOrigin); + VectorCopy((vTmp + 1), origin); - fCurLength = 0; + for (i = 0; i < pTmpPath->m_iPoints; i++) { + vec4_t vTmp2; - for (i = 0; i < pTmpPath->m_iPoints; i++) { - vTmp = pTmpPath->GetByNode(i, 0); + vTmp = pTmpPath->GetByNode(i, NULL); - vDelta = (vTmp + 1) - vLastOrigin; + VectorCopy((vTmp + 1), vLastOrigin); + VectorSubtract(vLastOrigin, origin, vDelta); - fCurLength += vDelta.length(); - origin[0] = fCurLength; - origin[1] = vTmp[1]; - origin[2] = vTmp[2]; - origin[3] = vTmp[3]; + fCurLength += VectorLength(vDelta); + vTmp2[0] = fCurLength; + vTmp2[1] = vLastOrigin[0]; + vTmp2[2] = vLastOrigin[1]; + vTmp2[3] = vLastOrigin[2]; - pPath->Add(origin, 0); - vLastOrigin = (vTmp + 1); - } + pPath->Add(vTmp2, 0); + VectorCopy(vLastOrigin, origin); } } } From af919dadca924122c31ba8310baa7cc198d10e5c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Apr 2024 20:04:21 +0200 Subject: [PATCH 0342/2040] Simplified code for g_showflypath --- code/fgame/scriptslave.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 03e816d1..12602121 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1463,17 +1463,17 @@ void ScriptSlave::FollowingPath(Event *ev) if (g_showflypath && g_showflypath->integer) { for (int i = 0; i < m_pCurPath->m_iPoints; i++) { vTmp = m_pCurPath->GetByNode(i, NULL); - G_DebugBBox((vTmp + 1), Vector(-32, -32, -32), Vector(32, 32, 32), 0.0f, 1.0f, 1.0f, 1.0f); + VectorCopy((vTmp + 1), vCur); + + G_DebugBBox(vCur, Vector(-32, -32, -32), Vector(32, 32, 32), 0, 1, 1, 1); for (int ii = 0; ii <= 8; ii++) { - G_DebugLine( - (m_pCurPath->GetByNode((ii / 10.0f + (i + 1)), NULL) + 1), - (m_pCurPath->GetByNode(m_fLookAhead + (ii / 10.0f + (i + 1)), NULL) + 1), - 0.0f, - 1.0f, - 1.0f, - 1.0f - ); + vTmp = m_pCurPath->GetByNode(i + ii / 10.0, NULL); + VectorCopy((vTmp + 1), vPrev); + vTmp = m_pCurPath->GetByNode(i + ii / 10.0 + m_fLookAhead, NULL); + VectorCopy((vTmp + 1), vCur); + + G_DebugLine(vPrev, vCur, 0, 1, 0, 1); } } } From 16f775c78c6f9f7546bab7482b721e460e877ada Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Apr 2024 23:04:09 +0200 Subject: [PATCH 0343/2040] Fixed ScriptSlave path with 2 equal points This fixes the script slave moving infinitely and not sending movedone notifications as it would never advance to the next path. e3l4's outro is now fixed because of that (was stuck). --- code/fgame/scriptslave.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 12602121..91e67eaf 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1479,19 +1479,22 @@ void ScriptSlave::FollowingPath(Event *ev) } if (m_iCurNode > 0) { + // Get previous node vTmp = m_pCurPath->GetByNode(m_iCurNode - 1, NULL); vPrev = (vTmp + 1); - vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL); - vCur = (vTmp + 1); + // Get current node + vTmp = m_pCurPath->GetByNode(m_iCurNode, NULL); + vCur = (vTmp + 1); - m_vIdealDir = vCur - vPrev; + vDelta = vCur - vPrev; + m_vIdealDir = vDelta; VectorNormalize(m_vIdealDir); angles.AngleVectorsLeft(&vWishAngles); fCoef = ProjectLineOnPlane(vWishAngles, DotProduct(origin, vWishAngles), vPrev, vCur, NULL); - vTmp = m_pCurPath->GetByNode((m_iCurNode - (1.0f - fCoef)), NULL); - vTmp = m_pCurPath->Get(vTmp[0] + m_fLookAhead, NULL); + vTmp = m_pCurPath->GetByNode(m_iCurNode - (1.0 - fCoef), NULL); + vTmp = m_pCurPath->Get(vTmp[0] + m_fLookAhead, NULL); vWishPosition = (vTmp + 1); if (fCoef > 1.0f) { @@ -1505,6 +1508,7 @@ void ScriptSlave::FollowingPath(Event *ev) m_pCurPath = NULL; m_iCurNode = 0; moving = false; + ProcessEvent(EV_ScriptSlave_MoveDone); return; } @@ -1800,7 +1804,7 @@ void ScriptSlave::SetupPath(cSpline<4, 512> *pPath, SimpleEntity *se) int iObjNum = 0; Vector vLastOrigin; SimpleEntity *ent; - int i; + int i = 1; static cSpline<4, 512> *pTmpPath = new cSpline<4, 512>; if (!pPath) { @@ -1815,8 +1819,6 @@ void ScriptSlave::SetupPath(cSpline<4, 512> *pPath, SimpleEntity *se) name = se->Target(); if (name.length()) { - i = 0; - for(ent = se; ent; ent = ent->Next()) { Vector vDelta; vec4_t vTmp; From 05a6b43e0893295b1279983cb5cf52818e68f1ae Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 30 Apr 2024 19:25:02 +0200 Subject: [PATCH 0344/2040] Check for __APPLE__ to detect MacOS --- code/gamespy/common/gsPlatform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/gamespy/common/gsPlatform.h b/code/gamespy/common/gsPlatform.h index a4daf16e..6264efc4 100644 --- a/code/gamespy/common/gsPlatform.h +++ b/code/gamespy/common/gsPlatform.h @@ -8,7 +8,7 @@ // Windows: _WIN32 // Xbox: _WIN32 + _XBOX // Xbox360: _WIN32 + _XBOX + _X360 -// MacOSX: _MACOSX + _UNIX +// MacOSX: _MACOSX + _UNIX + __APPLE__ // Linux: _LINUX + _UNIX // Nintendo DS: _NITRO // PSP: _PSP @@ -34,7 +34,7 @@ #endif #endif -#if defined(_LINUX) || defined(_MACOSX) +#if defined(_LINUX) || defined(_MACOSX) || defined(__APPLE__) #define _UNIX #endif From d4dfde334088be3558e447a1bce388e506e8d72c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 30 Apr 2024 20:26:08 +0200 Subject: [PATCH 0345/2040] Trigger must not be effective when being damaged if it does not take damage This fixes issue with vehicles damaging triggers by touching them (like the ClickItemTrigger on m5l3 with tanks) --- code/fgame/trigger.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/trigger.cpp b/code/fgame/trigger.cpp index f2aebed3..5cbe0cba 100644 --- a/code/fgame/trigger.cpp +++ b/code/fgame/trigger.cpp @@ -766,6 +766,10 @@ void Trigger::DamageEvent(Event *ev) Vector dir; Vector momentum; + if (!takedamage) { + return; + } + if (Immune(ev->GetInteger(9))) { // trigger is immune return; From 35681e7a1f25ad578750aff2627dfe49e9ffe58c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 17:42:02 +0200 Subject: [PATCH 0346/2040] Added MASK_IGNORE_ENTS --- code/fgame/bg_public.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index 9cfed026..dcdbc48a 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -705,6 +705,7 @@ movement on the server game. | CONTENTS_WEAPONCLIP) #define MASK_CORNER_NODE \ (CONTENTS_SOLID | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_UNKNOWN2 | CONTENTS_WEAPONCLIP | CONTENTS_BODY) +#define MASK_IGNORE_ENTS (CONTENTS_CORPSE | CONTENTS_BODY | CONTENTS_UNKNOWN3 | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX | CONTENTS_CLAYPIDGEON | CONTENTS_LADDER) void BG_EvaluateTrajectoryDelta(const trajectory_t *tr, int atTime, vec3_t result); From daa7aceecf33d8a130384eec52d9b7939ea8270e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 17:43:04 +0200 Subject: [PATCH 0347/2040] Fixed sighttrace not properly passing entities This fixes the issue where some scripts (like e2l3's BattleHouse) expect sighttrace to ignore entities (fixes #202) --- code/fgame/scriptthread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index 9cbd5bd9..fb0710ab 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -3778,7 +3778,7 @@ void ScriptThread::EventTrace(Event *ev) void ScriptThread::EventSightTrace(Event *ev) { - int content_mask = MASK_LINE; + int content_mask = MASK_SOLID; Vector start; Vector mins; Vector maxs; @@ -3794,7 +3794,7 @@ void ScriptThread::EventSightTrace(Event *ev) mins = ev->GetVector(4); case 3: if (ev->GetInteger(3)) { - content_mask = MASK_SOLID; + content_mask &= ~MASK_IGNORE_ENTS; } case 2: end = ev->GetVector(2); From e5dbfba55e6f4bdccae68a6d90afdab5a1a33851 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 17:54:41 +0200 Subject: [PATCH 0348/2040] Fixed an issue where scripts would get compiled every time they are executed, causing a performance issue --- code/fgame/scriptmaster.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/fgame/scriptmaster.cpp b/code/fgame/scriptmaster.cpp index 40232cd9..b036e08e 100644 --- a/code/fgame/scriptmaster.cpp +++ b/code/fgame/scriptmaster.cpp @@ -800,16 +800,16 @@ GameScript *ScriptMaster::GetGameScriptInternal(str& filename) gi.Error(ERR_DROP, "Script filename '%s' exceeds maximum length of %d\n", filename.c_str(), MAX_QPATH); } + strcpy(filepath, filename.c_str()); + gi.FS_CanonicalFilename(filepath); + filename = filepath; + scr = m_GameScripts[StringDict.findKeyIndex(filename)]; if (scr != NULL) { return scr; } - strcpy(filepath, filename.c_str()); - gi.FS_CanonicalFilename(filepath); - filename = filepath; - scr = new GameScript(filename); m_GameScripts[StringDict.addKeyIndex(filename)] = scr; From c5b46529b0876cc07ed140b9c46b1ed91e12dc5b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 18:24:44 +0200 Subject: [PATCH 0349/2040] Check the client if it has a valid entity for MSG_SetBroadcastVisible() --- code/server/sv_game.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 05d4dc1e..6ff8229f 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -446,10 +446,16 @@ void MSG_SetBroadcastVisible( const vec_t *vPos, const vec_t *vPosB) pCGM = g_CGMessages; pClient = svs.clients; for(i = 0; i < svs.iNumClients; i++,pCGM++,pClient++) { - if(pClient->state != CS_ACTIVE) { + if (!pClient->gentity || !pClient->gentity->inuse) { + // The entity can be null on map load + continue; + } + + if(pClient->state == CS_FREE) { g_CGMRecieve[i] = qfalse; continue; } + leafnum = CM_PointLeafnum(pClient->gentity->s.origin); clientcluster = CM_LeafCluster(leafnum); clientarea = CM_LeafArea(leafnum); From 88bc0e1e85b2cd62ce351662cde8232fbdab452a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 18:36:27 +0200 Subject: [PATCH 0350/2040] Reimplemented MSG_SetBroadcastVisible() and MSG_SetBroadcastAll() --- code/server/sv_game.c | 96 ++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 6ff8229f..0be5e071 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -113,7 +113,8 @@ void SV_ClearCGMessage (int iClient) g_CGMessages[iClient].datatypes = 0; } g_CGMRecieve[iClient] = 0; -} +} + void SV_ClearAllCGMessages () { cgm_t *pCGM; @@ -133,8 +134,10 @@ void SV_ClearAllCGMessages () g_CGMRecieve[i] = 0; } } + #define CGM_DATA_SIZE 4096 #define CGM_DATATYPES_SIZE 8192 + void SV_InitCGMessage (int iClient) { cgm_t *pCGM; @@ -211,6 +214,7 @@ static void MSG_WriteCGMBits (cgm_t *pCGM, int value, int bits) pCGM->datatypes[pCGM->dtindex] = bits; pCGM->dtindex++; } + void PF_MSG_WriteBits (int value, int bits) { cgm_t *pCGM; @@ -234,7 +238,8 @@ void PF_MSG_WriteChar (int c) // write 8 bit character MSG_WriteCGMBits(pCGM,c,8); } -} +} + void PF_MSG_WriteByte (int c) { cgm_t *pCGM; @@ -247,6 +252,7 @@ void PF_MSG_WriteByte (int c) MSG_WriteCGMBits(pCGM,c,8); } } + void PF_MSG_WriteSVC (int c) { cgm_t *pCGM; @@ -258,6 +264,7 @@ void PF_MSG_WriteSVC (int c) MSG_WriteCGMBits(pCGM,c,8); } } + void PF_MSG_WriteShort (int c) { cgm_t *pCGM; @@ -269,6 +276,7 @@ void PF_MSG_WriteShort (int c) MSG_WriteCGMBits(pCGM,c,16); } } + void PF_MSG_WriteLong (int c) { cgm_t *pCGM; @@ -280,6 +288,7 @@ void PF_MSG_WriteLong (int c) MSG_WriteCGMBits(pCGM,c,32); } } + void PF_MSG_WriteFloat (float f) { union { @@ -296,6 +305,7 @@ void PF_MSG_WriteFloat (float f) MSG_WriteCGMBits(pCGM,dat.l,32); } } + void PF_MSG_WriteString (const char *s) { cgm_t *pCGM; @@ -312,6 +322,7 @@ void PF_MSG_WriteString (const char *s) } } } + void PF_MSG_WriteAngle8 (float f) { cgm_t *pCGM; @@ -323,6 +334,7 @@ void PF_MSG_WriteAngle8 (float f) MSG_WriteCGMBits(pCGM,f * 256.0 / 360.0,8); } } + void PF_MSG_WriteAngle16 (float f) { cgm_t *pCGM; @@ -334,6 +346,7 @@ void PF_MSG_WriteAngle16 (float f) MSG_WriteCGMBits(pCGM,ANGLE2SHORT(f),16); } } + void PF_MSG_WriteCoord (float f) { cgm_t *pCGM; @@ -354,6 +367,7 @@ void PF_MSG_WriteCoord (float f) MSG_WriteCGMBits(pCGM, write, 19); } } + void PF_MSG_WriteDir (vec_t *dir) { cgm_t *pCGM; @@ -367,6 +381,7 @@ void PF_MSG_WriteDir (vec_t *dir) MSG_WriteCGMBits(pCGM,b,8); } } + void PF_MSG_StartCGM (int type) { cgm_t *pCGM; @@ -387,10 +402,12 @@ void PF_MSG_StartCGM (int type) MSG_WriteCGMBits(pCGM, type, 6); } } + void PF_MSG_EndCGM () { memset(g_CGMRecieve,0,sizeof(g_CGMRecieve)); } + void PF_MSG_SetClient (int iClient) { memset(g_CGMRecieve,0,sizeof(g_CGMRecieve)); @@ -400,7 +417,7 @@ void PF_MSG_SetClient (int iClient) } } -void MSG_SetBroadcastAll () +void MSG_SetBroadcastAll() { cgm_t *pCGM; client_t* client; @@ -410,16 +427,24 @@ void MSG_SetBroadcastAll () for(i = 0; i < svs.iNumClients; i++,pCGM++) { client = &svs.clients[i]; - if (client->gentity && client->gentity->inuse && client->state != CS_FREE) { - if (pCGM->data && pCGM->cursize < 3968) { - g_CGMRecieve[i] = qtrue; - } else { - MSG_HandleCGMBufferOverflow(pCGM, 0); - } + if (!client->gentity || !client->gentity->inuse) { + continue; } + + if (client->state == CS_FREE) { + continue; + } + + if (!pCGM->data || pCGM->cursize >= 3968) { + MSG_HandleCGMBufferOverflow(pCGM, qfalse); + continue; + } + + g_CGMRecieve[i] = qtrue; } } -void MSG_SetBroadcastVisible( const vec_t *vPos, const vec_t *vPosB) + +void MSG_SetBroadcastVisible(const vec_t* vPos, const vec_t* vPosB) { byte *clientpvs; int posBcluster; @@ -435,16 +460,22 @@ void MSG_SetBroadcastVisible( const vec_t *vPos, const vec_t *vPosB) int i; cgm_t *pCGM; -#if 0 - MSG_SetBroadcastAll(); -#else - // dont check the same pos twice - if(vPosB && VectorCompare(vPos,vPosB)) { - vPosB = 0; + posleaf = CM_PointLeafnum(vPos); + posarea = CM_LeafArea(posleaf); + poscluster = CM_LeafCluster(posleaf); + + if (vPosB) { + posBleaf = CM_PointLeafnum(vPosB); + posBarea = CM_LeafArea(posBleaf); + posBcluster = CM_LeafCluster(posBleaf); + } else { + posBarea = 0; + posBcluster = 0; } pCGM = g_CGMessages; pClient = svs.clients; + for(i = 0; i < svs.iNumClients; i++,pCGM++,pClient++) { if (!pClient->gentity || !pClient->gentity->inuse) { // The entity can be null on map load @@ -452,40 +483,29 @@ void MSG_SetBroadcastVisible( const vec_t *vPos, const vec_t *vPosB) } if(pClient->state == CS_FREE) { - g_CGMRecieve[i] = qfalse; continue; } leafnum = CM_PointLeafnum(pClient->gentity->s.origin); - clientcluster = CM_LeafCluster(leafnum); clientarea = CM_LeafArea(leafnum); + clientcluster = CM_LeafCluster(leafnum); clientpvs = CM_ClusterPVS(clientcluster); - posleaf = CM_PointLeafnum(vPos); - poscluster = CM_LeafCluster(posleaf); - posarea = CM_LeafArea(posleaf); - - if ( clientpvs[poscluster >> 3] & (1 << (poscluster&7) ) ) { - // visible. - g_CGMRecieve[i] = qtrue; + if (CM_AreasConnected(clientarea, posarea) && (!vPosB || !CM_AreasConnected(clientarea, posBarea))) { continue; } - - if(vPosB) { - posBleaf = CM_PointLeafnum(vPosB); - posBcluster = CM_LeafCluster(posBleaf); - posBarea = CM_LeafArea(posBleaf); - if ( clientpvs[posBcluster >> 3] & (1 << (posBcluster&7) ) ) { - // visible. - g_CGMRecieve[i] = qtrue; - continue; - } + if (!(clientpvs[poscluster >> 3] & (1 << (poscluster & 7))) && (!vPosB || !(clientpvs[posBcluster >> 3] & (1 << (posBcluster & 7))))) { + continue; } - // not visible - g_CGMRecieve[i] = qfalse; + + if (!pCGM->data || pCGM->cursize >= 3968) { + MSG_HandleCGMBufferOverflow(pCGM, qfalse); + continue; + } + + g_CGMRecieve[i] = qtrue; } -#endif } void MSG_SetBroadcastHearable ( const vec_t *vPos, const vec_t *vPosB) { From ff6e81d44f453c38932d0b269b2ed709155f7486 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 18:55:25 +0200 Subject: [PATCH 0351/2040] Fixed CL_GetSnapshot sometimes wrongfully assigning parents multiple times and displaying errors This should fix #170 --- code/client/cl_cgame.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index 4733b336..da55bb05 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -211,20 +211,20 @@ qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) { } snapshot->numEntities = 0; - for ( i = 0 ; i < count ; i++ ) { + for(i = 0; i < MAX_ENTITIES_IN_SNAPSHOT; i++) { + parents[i] = -1; + } + + for (i = 0; i < count; i++) { s1 = &cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)]; pnum = s1->parent; if (pnum == ENTITYNUM_NONE) { parents[s1->number] = -2; - } - else - { + } else { if (parents[pnum] == -2) { parents[s1->number] = -2; - } - else - { + } else { // add it later parents[s1->number] = pnum; continue; @@ -234,20 +234,20 @@ qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) { snapshot->entities[snapshot->numEntities++] = *s1; } - for(pcount = 0; pcount < 8 && snapshot->numEntities != count; pcount++) - { - for (i = 0; i < count; i++) - { + for(pcount = 0; pcount < 8 && snapshot->numEntities != count; pcount++) { + for (i = 0; i < count; i++) { s1 = &cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)]; pnum = parents[s1->number]; if (pnum >= 0 && parents[pnum] == -2) { + parents[s1->number] = -2; snapshot->entities[snapshot->numEntities++] = *s1; } } } - if (pcount >= 8) - { + if (snapshot->numEntities != count) { + Com_DPrintf("CL_GetSnapshot: Not all children could find their parents.\n"); + for (i = count; i < snapshot->numEntities; i++) { s1 = &cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)]; @@ -261,6 +261,8 @@ qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) { s1->origin[1], s1->origin[2] ); + + parents[s1->number] = -2; } } } From 170b4b0972f9aa6b957f7ded6905382f105ce860 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 20:11:22 +0200 Subject: [PATCH 0352/2040] Fixed ScriptAimedStrafingGunfire aimTarget never set nor used This fixes the gunfire incorrectly damaging things it shouldn't damage. For example, the sniper3 balcony AI on e3l1: The bomber caused this AI to fall before initialization (by damaging them when it shouldn't), the AI became nonsolid. After initialization, the AI had enemy enabled, however it remained nonsolid because of the balcony fall. It was constantly shooting at the player and it was unkillable because it was nonsolid. The mission wasn't able to be completed because of this issue. --- code/fgame/scriptslave.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 91e67eaf..0d6d8601 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -2251,8 +2251,9 @@ Event EV_ScriptAimedStrafingGunfire_AimTarget ); CLASS_DECLARATION(ScriptSimpleStrafingGunfire, ScriptAimedStrafingGunfire, "script_aimedstrafinggunfire") { - {&EV_ScriptSimpleStrafingGunfire_Fire, &ScriptAimedStrafingGunfire::GunFire}, - {NULL, NULL } + {&EV_ScriptAimedStrafingGunfire_AimTarget, &ScriptAimedStrafingGunfire::SetAimTarget}, + {&EV_ScriptSimpleStrafingGunfire_Fire, &ScriptAimedStrafingGunfire::GunFire }, + {NULL, NULL } }; ScriptAimedStrafingGunfire::ScriptAimedStrafingGunfire() @@ -2270,8 +2271,8 @@ void ScriptAimedStrafingGunfire::GunFire(Event *ev) Vector dir, right, up; Vector horzAngles; - AngleVectors(angles, NULL, NULL, up); - dir = -1 * up; + dir = aimTarget->origin - origin; + dir.normalize(); VectorToAngles(dir, horzAngles); AngleVectors(horzAngles, NULL, right, up); From db01f72adc4c060ce697290954d806600931cc1d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 1 May 2024 20:41:39 +0200 Subject: [PATCH 0353/2040] Reimplemented ScriptVariable::entityValue Some script events don't check if it's an actual entity, it would cause crashes. E3L3 would crash after the player got out of the AB41: the AB41 was targetting a VehiclePoint and vehicles_thinkers.scr script set the `self.collisionent` to `self.target` which caused a crash as `VehiclePoint` doesn't inherit from `Entity` --- code/script/scriptvariable.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/code/script/scriptvariable.cpp b/code/script/scriptvariable.cpp index 5f32a1b9..b7d2c77a 100644 --- a/code/script/scriptvariable.cpp +++ b/code/script/scriptvariable.cpp @@ -900,10 +900,30 @@ void ScriptVariable::SetKey(const short3& key) #endif -Entity *ScriptVariable::entityValue(void) +Entity* ScriptVariable::entityValue(void) { #if defined(GAME_DLL) - return (Entity *)listenerValue(); + Entity* ent; + + switch (type) { + case VARIABLE_CONSTSTRING: + ent = static_cast(world->GetScriptTarget(Director.GetString(m_data.intValue))); + break; + case VARIABLE_STRING: + ent = static_cast(world->GetScriptTarget(stringValue())); + break; + case VARIABLE_LISTENER: + ent = static_cast(m_data.listenerValue->Pointer()); + break; + default: + throw ScriptException("Cannot cast '%s' to entity", typenames[type]); + } + + if (ent && !ent->isSubclassOf(Entity)) { + ScriptError("Cannot cast '%s' to entity", ent->getClassname()); + } + + return ent; #else return NULL; #endif From dc7caf04a8c40e91bc556eb849482bb2738411b0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 12 May 2024 23:40:11 +0200 Subject: [PATCH 0354/2040] Fixed MoveTo not working on waypoints. This fixes an issue where objects using waypoint (like elevators) would move at `(0 0 0)`. Closes #298 --- code/fgame/scriptslave.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 0d6d8601..90c2b365 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -969,9 +969,18 @@ void ScriptSlave::MoveToEvent(Event *ev) if (ev->IsVectorAt(1)) { NewPos = ev->GetVector(1); } else { - waypoint = (Waypoint *)ev->GetEntity(1); - if (waypoint) { - NewPos = waypoint->origin; + SimpleEntity* ent; + + ent = ev->GetSimpleEntity(1); + if (ent) { + // + // see if it is a waypoint + // + if (ent->IsSubclassOfWaypoint()) { + waypoint = static_cast(ent); + } + // use the entity's origin + NewPos = ent->origin; } } } From 98239050d892cf9d92997c448bcdb52024d3d46b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 12 May 2024 23:49:19 +0200 Subject: [PATCH 0355/2040] Correctly archive the active weapon (safe pointer) This fixes the player sometimes being holstered after loading from a save (closes #270) --- code/fgame/sentient_combat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/sentient_combat.cpp b/code/fgame/sentient_combat.cpp index adc0241d..0e957210 100644 --- a/code/fgame/sentient_combat.cpp +++ b/code/fgame/sentient_combat.cpp @@ -33,7 +33,7 @@ ActiveWeapon::ActiveWeapon() void ActiveWeapon::Archive(Archiver& arc) { - arc.ArchiveObjectPointer((Class **)&weapon); + arc.ArchiveSafePointer(&weapon); ArchiveEnum(hand, weaponhand_t); } From c3abbd901404bbe1e025ddc4fb9677a4b3e855ff Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 20 May 2024 13:10:12 +0200 Subject: [PATCH 0356/2040] Added assertion checks --- code/renderer/tr_model.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index 19a4514e..137ae4a4 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -1058,7 +1058,7 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { skelHeaderGame_t* skelmodel; skelSurfaceGame_t* psurface; qboolean bFound; - short collapse[1000]; + short collapse[TIKI_MAX_VERTEXES]; if (!r_drawentitypoly->integer) { return; @@ -1185,15 +1185,22 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { } else { + assert(sf->numVerts < TIKI_MAX_VERTEXES); + for (i = 0; i < render_count; i++) { collapse[i] = i; } + for (i = render_count; i < sf->numVerts; i++) { collapse[i] = collapse[collapse_map[i]]; } for (i = 0; i < indexes; i += 3) { + assert(collapse[triangles[i]] < sf->numVerts); + assert(collapse[triangles[i + 1]] < sf->numVerts); + assert(collapse[triangles[i + 2]] < sf->numVerts); + if (collapse[triangles[i]] == collapse[triangles[i + 1]] || collapse[triangles[i + 1]] == collapse[triangles[i + 2]] || collapse[triangles[i + 2]] == collapse[triangles[i]]) From 85c8769512aff9290a9c2ca7cff6b8d8ea0409d9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 20 May 2024 13:11:48 +0200 Subject: [PATCH 0357/2040] Fixed incorrect usage of the grid lighting This fixes some entities being invisible when `r_fastentlight` is set to 1, due to the alpha color being 0 (cast from int to char for each color value). Fixes #299 --- code/renderer/tr_shade_calc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index 041729b5..792e38db 100644 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -1661,18 +1661,18 @@ void RB_CalcLightGridColor(unsigned char* colors) if (!backEnd.currentEntity) { for (i = 0; i < tess.numVertexes; i++) { - colors[i * 4] = backEnd.currentStaticModel->iGridLighting; - colors[i * 4 + 1] = backEnd.currentStaticModel->iGridLighting; - colors[i * 4 + 2] = backEnd.currentStaticModel->iGridLighting; - colors[i * 4 + 3] = backEnd.currentStaticModel->iGridLighting; + colors[i * 4] = ((byte*)&backEnd.currentStaticModel->iGridLighting)[0]; + colors[i * 4 + 1] = ((byte*)&backEnd.currentStaticModel->iGridLighting)[1]; + colors[i * 4 + 2] = ((byte*)&backEnd.currentStaticModel->iGridLighting)[2]; + colors[i * 4 + 3] = ((byte*)&backEnd.currentStaticModel->iGridLighting)[3]; } } else if (backEnd.currentEntity != &tr.worldEntity) { for (i = 0; i < tess.numVertexes; i++) { - colors[i * 4] = backEnd.currentEntity->iGridLighting; - colors[i * 4 + 1] = backEnd.currentEntity->iGridLighting; - colors[i * 4 + 2] = backEnd.currentEntity->iGridLighting; - colors[i * 4 + 3] = backEnd.currentEntity->iGridLighting; + colors[i * 4] = ((byte*)&backEnd.currentEntity->iGridLighting)[0]; + colors[i * 4 + 1] = ((byte*)&backEnd.currentEntity->iGridLighting)[1]; + colors[i * 4 + 2] = ((byte*)&backEnd.currentEntity->iGridLighting)[2]; + colors[i * 4 + 3] = ((byte*)&backEnd.currentEntity->iGridLighting)[3]; } } else { From 16464c5a6813f84788d6b808a2848f9124953afa Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 27 May 2024 23:28:12 +0200 Subject: [PATCH 0358/2040] Removed zone events from entity This fixes a conflict where some scripts would store stuff in a variable named `zone` in an entity --- code/fgame/entity.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 471b4bff..07f264a1 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -1471,6 +1471,7 @@ Event EV_Entity_SetDHack "Enable or disable depth hack.", EV_NORMAL ); +/* Event EV_Entity_GetZone ( "getzone", @@ -1498,6 +1499,7 @@ Event EV_Entity_IsInZone "Returns 1 if the entity is in the specified zone. 0 otherwise", EV_RETURN ); +*/ Event EV_Entity_SetHintRequireLookAt ( "setuselookat", @@ -1667,9 +1669,11 @@ CLASS_DECLARATION(SimpleEntity, Entity, NULL) { {&EV_ShootableOnly, &Entity::EventShootableOnly }, {&EV_SetShaderTime, &Entity::SetShaderTime }, {&EV_NoTarget, &Entity::NoTarget }, + /* {&EV_Entity_GetZone, &Entity::GetZone }, {&EV_Entity_Zone, &Entity::GetZone }, {&EV_Entity_IsInZone, &Entity::IsInZone }, + */ {&EV_Entity_SetDHack, &Entity::SetDepthHack }, {&EV_Entity_SetHintRequireLookAt, &Entity::SetHintRequireLookAt }, {&EV_Entity_SetHintString, &Entity::SetHintString }, From a85694b5489c01e8874e0f07f0f3a8292afdeeae Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 28 May 2024 20:49:03 +0200 Subject: [PATCH 0359/2040] Fixed incorrect method for `EV_ScriptThread_Showmenu`. This fixes #302 where screen text with the mission date would never be shown. --- code/fgame/scriptthread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index fb0710ab..1f28c78f 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -2113,7 +2113,7 @@ CLASS_DECLARATION(Listener, ScriptThread, NULL) { {&EV_ScriptThread_MissionFailed, &ScriptThread::MissionFailed }, {&EV_ScriptThread_IsAlive, &ScriptThread::EventIsAlive }, {&EV_ScriptThread_Popmenu, &ScriptThread::EventPopmenu }, - {&EV_ScriptThread_Showmenu, &ScriptThread::EventPopmenu }, + {&EV_ScriptThread_Showmenu, &ScriptThread::EventShowmenu }, {&EV_ScriptThread_Hidemenu, &ScriptThread::EventHidemenu }, {&EV_ScriptThread_PlayMovie, &ScriptThread::EventPlayMovie }, {&EV_ScriptThread_Pushmenu, &ScriptThread::EventPushmenu }, From 21fda4cabd82065e852bc9b447ff52f91727a482 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 28 May 2024 21:31:28 +0200 Subject: [PATCH 0360/2040] Removed redundant code --- code/tiki/tiki_files.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index dbfd5e76..18bfae60 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -182,7 +182,7 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) loaddef.numclientinitcmds = 0; if (loaddef.tikiFile.LoadFile(path, qfalse)) { - loaddef.path = path; + loaddef.bInIncludesSection = false; token = loaddef.tikiFile.GetToken(true); if (strcmp(token, "TIKI")) { @@ -195,11 +195,6 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) return NULL; } - loaddef.numanims = 0; - loaddef.numserverinitcmds = 0; - loaddef.numclientinitcmds = 0; - loaddef.bInIncludesSection = false; - while (loaddef.tikiFile.TokenAvailable(true)) { token = loaddef.tikiFile.GetToken(true); From e89262ed3ba5d6640a82fca986bbf2aecea02fd6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 28 May 2024 21:38:17 +0200 Subject: [PATCH 0361/2040] Fixed TIKI_ParseAnimations improperly returning, even when a map was specified, causing parsing issues --- code/tiki/tiki_parse.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index 1fe94eed..6765a268 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -322,9 +322,9 @@ qboolean TIKI_ParseIncludes(dloaddef_t *ld) } while (1) { - if (!strncmp(token, mapname, strlen(token)) || !strncmp(token, servertype, strlen(token))) { + if (!Q_stricmpn(token, mapname, strlen(token)) || !Q_stricmpn(token, servertype, strlen(token))) { b_incl = true; - } else if ((!stricmp(token, "{") || !ld->tikiFile.TokenAvailable(true))) { + } else if (!stricmp(token, "{") || !ld->tikiFile.TokenAvailable(true)) { break; } @@ -387,7 +387,11 @@ void TIKI_ParseAnimations(dloaddef_t *ld) while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); if (!stricmp(token, "}")) { - return; + if (!b_mapspec) { + // Return when there is no mapspec + return; + } + b_mapspec = false; } else if (!stricmp(token, "$mapspec")) { token = ld->tikiFile.GetToken(true); if (sv_mapname) { @@ -415,7 +419,7 @@ void TIKI_ParseAnimations(dloaddef_t *ld) if (strstr(token, "}")) { if (!depth) { - break; + continue; } depth--; @@ -423,7 +427,7 @@ void TIKI_ParseAnimations(dloaddef_t *ld) } } } else { - if (ld->numanims > 4094) { + if (ld->numanims >= MAX_TIKI_LOAD_ANIMS) { TIKI_Error("TIKI_ParseAnimations: Too many animations in '%s'.\n", ld->path); continue; } @@ -440,8 +444,7 @@ void TIKI_ParseAnimations(dloaddef_t *ld) continue; } - depth = strlen(token); - if (depth < 48) { + if (strlen(token) < 48) { anim->alias = (char *)TIKI_CopyString(token); token = ld->tikiFile.GetToken(false); From 0a3a23af41677dbdf0224026e4b631e5bfd8907e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 29 May 2024 23:54:48 +0200 Subject: [PATCH 0362/2040] Using AI_EVENT_MAX to check for max ai events --- code/fgame/entity.h | 3 ++- code/fgame/g_utils.cpp | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/code/fgame/entity.h b/code/fgame/entity.h index 4e8fd2f1..901dc457 100644 --- a/code/fgame/entity.h +++ b/code/fgame/entity.h @@ -81,7 +81,8 @@ enum eAIEvent { AI_EVENT_MISC_LOUD, AI_EVENT_FOOTSTEP, AI_EVENT_GRENADE, - AI_EVENT_BADPLACE // Added in 2.0 + AI_EVENT_BADPLACE, // Added in 2.0 + AI_EVENT_MAX }; //deadflag diff --git a/code/fgame/g_utils.cpp b/code/fgame/g_utils.cpp index 828271c7..8fca9c03 100644 --- a/code/fgame/g_utils.cpp +++ b/code/fgame/g_utils.cpp @@ -1641,14 +1641,30 @@ int G_AIEventTypeFromString(const char *pszType) float G_AIEventRadius(int iType) { static float fRadius[] = { - 2048.0f, 384.0f, 4096.0f, 1024.0f, 1024.0f, 1536.0f, 1536.0f, 1500.0f, 2250.0f, 512.0f, 384.0f, 0, 0, 0, 0}; + 0, + 2048, + 384, + 4096, + 1024, + 1024, + 1536, + 1536, + 1500, + 2250, + 512, + 384, + 32768, + 0, + 0, + 0 + }; - if (iType <= AI_EVENT_GRENADE) { - return fRadius[iType]; - } else { + if (iType >= AI_EVENT_MAX) { Com_Printf("G_AIEventRadius: invalid event type\n"); return 1500.0f; } + + return fRadius[iType]; } void G_BroadcastAIEvent(Entity *originator, Vector origin, char *pszType) From 7fe7e74fe2020153130d6d5e857005ed3778bb1b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:44:06 +0200 Subject: [PATCH 0363/2040] Replaced all stricmp calls with Q_stricmp --- code/tiki/tiki_files.cpp | 18 +++--- code/tiki/tiki_parse.cpp | 128 +++++++++++++++++++-------------------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 18bfae60..f50421ba 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -198,16 +198,16 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) while (loaddef.tikiFile.TokenAvailable(true)) { token = loaddef.tikiFile.GetToken(true); - if (!stricmp(token, "setup")) { + if (!Q_stricmp(token, "setup")) { if (!TIKI_ParseSetup(&loaddef)) { TIKI_FreeStorage(&loaddef); return NULL; } - } else if (!stricmp(token, "init")) { + } else if (!Q_stricmp(token, "init")) { TIKI_ParseInit(&loaddef); - } else if (!stricmp(token, "animations")) { + } else if (!Q_stricmp(token, "animations")) { TIKI_ParseAnimations(&loaddef); - } else if (!stricmp(token, "includes")) { + } else if (!Q_stricmp(token, "includes")) { if (!loaddef.bInIncludesSection) { loaddef.bInIncludesSection = TIKI_ParseIncludes(&loaddef); } else { @@ -218,7 +218,7 @@ dtikianim_t *TIKI_LoadTikiAnim(const char *path) loaddef.tikiFile.Filename() ); } - } else if (!stricmp(token, "}") && loaddef.bInIncludesSection) { + } else if (!Q_stricmp(token, "}") && loaddef.bInIncludesSection) { loaddef.bInIncludesSection = false; } else { TIKI_Error( @@ -385,7 +385,7 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapname, "all")) { + if (strptr || !Q_stricmp(loadsurf->name, "all")) { for (j = 0; j < temp.tiki.numMeshes; j++) { mesh = temp.tiki.mesh[j]; skelmodel = TIKI_GetSkel(mesh); @@ -396,7 +396,7 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapname && !strnicmp(loadsurf->name, surf->name, strptr - loadsurf->name)) - || !stricmp(loadsurf->name, "all")) { + || !Q_stricmp(loadsurf->name, "all")) { TIKI_SetupIndividualSurface(tikianim->name, tikiSurf, surf->name, loadsurf); found = true; } @@ -415,7 +415,7 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapsurfaces[surfOffset]; for (k = 0; k < skelmodel->numSurfaces; k++) { - if (!stricmp(loadsurf->name, surf->name)) { + if (!Q_stricmp(loadsurf->name, surf->name)) { TIKI_SetupIndividualSurface(tikianim->name, tikiSurf, surf->name, loadsurf); if (!tikiSurf->name[0]) { TIKI_Warning( @@ -629,7 +629,7 @@ bool SkeletorCacheFindFilename(const char *path, int *indexPtr) upperBound = m_numInCache - 1; while (lowerBound <= upperBound) { index = (lowerBound + upperBound) / 2; - sortValue = stricmp(path, m_cachedData[m_cachedDataLookup[index]].path); + sortValue = Q_stricmp(path, m_cachedData[m_cachedDataLookup[index]].path); if (!sortValue) { if (indexPtr) { *indexPtr = index; diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index 6765a268..5ea4ad38 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -71,7 +71,7 @@ void TIKI_ParseFrameCommands(dloaddef_t *ld, dloadframecmd_t **cmdlist, int maxc while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "}")) { + if (!Q_stricmp(token, "}")) { break; } @@ -90,22 +90,22 @@ void TIKI_ParseFrameCommands(dloaddef_t *ld, dloadframecmd_t **cmdlist, int maxc cmds->num_args = 0; (*numcmds)++; - if (!stricmp(token, "start") || !stricmp(token, "first")) { + if (!Q_stricmp(token, "start") || !Q_stricmp(token, "first")) { framenum = TIKI_FRAME_FIRST; - } else if (!stricmp(token, "end")) { + } else if (!Q_stricmp(token, "end")) { framenum = TIKI_FRAME_END; - } else if (!stricmp(token, "last")) { + } else if (!Q_stricmp(token, "last")) { framenum = TIKI_FRAME_LAST; - } else if (!stricmp(token, "every")) { + } else if (!Q_stricmp(token, "every")) { framenum = TIKI_FRAME_EVERY; - } else if (!stricmp(token, "exit")) { + } else if (!Q_stricmp(token, "exit")) { framenum = TIKI_FRAME_EXIT; - } else if (!stricmp(token, "entry") || !stricmp(token, "enter")) { + } else if (!Q_stricmp(token, "entry") || !Q_stricmp(token, "enter")) { framenum = TIKI_FRAME_ENTRY; - } else if (!stricmp(token, "(")) { + } else if (!Q_stricmp(token, "(")) { usecurrentframe = true; ld->tikiFile.UnGetToken(); - } else if (!stricmp(token, ")")) { + } else if (!Q_stricmp(token, ")")) { usecurrentframe = false; ld->tikiFile.UnGetToken(); } else if (!usecurrentframe) { @@ -175,21 +175,21 @@ void TIKI_ParseAnimationCommands(dloaddef_t *ld, dloadanim_t *anim) while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "client")) { + if (!Q_stricmp(token, "client")) { TIKI_ParseFrameCommands( ld, anim->loadclientcmds, sizeof(anim->loadclientcmds) / sizeof(anim->loadclientcmds[0]), &anim->num_client_cmds ); - } else if (!stricmp(token, "server")) { + } else if (!Q_stricmp(token, "server")) { TIKI_ParseFrameCommands( ld, anim->loadservercmds, sizeof(anim->loadservercmds) / sizeof(anim->loadservercmds[0]), &anim->num_server_cmds ); - } else if (!stricmp(token, "}")) { + } else if (!Q_stricmp(token, "}")) { break; } else { TIKI_Error( @@ -221,26 +221,26 @@ void TIKI_ParseAnimationFlags(dloaddef_t *ld, dloadanim_t *anim) while (ld->tikiFile.TokenAvailable(false)) { token = ld->tikiFile.GetToken(false); - if (!stricmp(token, "weight")) { + if (!Q_stricmp(token, "weight")) { anim->weight = ld->tikiFile.GetFloat(false); anim->flags |= TAF_RANDOM; - } else if (!stricmp(token, "deltadriven")) { + } else if (!Q_stricmp(token, "deltadriven")) { anim->flags |= TAF_DELTADRIVEN; - } else if (!stricmp(token, "default_angles")) { + } else if (!Q_stricmp(token, "default_angles")) { anim->flags |= TAF_DEFAULT_ANGLES; - } else if (!stricmp(token, "notimecheck")) { + } else if (!Q_stricmp(token, "notimecheck")) { anim->flags |= TAF_NOTIMECHECK; - } else if (!stricmp(token, "crossblend")) { + } else if (!Q_stricmp(token, "crossblend")) { anim->blendtime = ld->tikiFile.GetFloat(false); - } else if (!stricmp(token, "dontrepeate")) { + } else if (!Q_stricmp(token, "dontrepeate")) { anim->flags |= TAF_NOREPEAT; - } else if (!stricmp(token, "random")) { + } else if (!Q_stricmp(token, "random")) { anim->flags |= TAF_RANDOM; - } else if (!stricmp(token, "autosteps_run")) { + } else if (!Q_stricmp(token, "autosteps_run")) { anim->flags |= TAF_AUTOSTEPS | TAF_AUTOSTEPS_RUNNING | TAF_AUTOSTEPS_EQUIPMENT; - } else if (!stricmp(token, "autosteps_walk")) { + } else if (!Q_stricmp(token, "autosteps_walk")) { anim->flags |= TAF_AUTOSTEPS | TAF_AUTOSTEPS_EQUIPMENT; - } else if (!stricmp(token, "autosteps_dog")) { + } else if (!Q_stricmp(token, "autosteps_dog")) { anim->flags |= TAF_AUTOSTEPS; } else { TIKI_Error( @@ -272,7 +272,7 @@ void TIKI_ParseAnimationsFail(dloaddef_t *ld) } token = ld->tikiFile.GetToken(true); - if (stricmp(token, "{")) { + if (Q_stricmp(token, "{")) { ld->tikiFile.UnGetToken(); return; } @@ -281,9 +281,9 @@ void TIKI_ParseAnimationsFail(dloaddef_t *ld) while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "{")) { + if (!Q_stricmp(token, "{")) { nestcount++; - } else if (!stricmp(token, "}")) { + } else if (!Q_stricmp(token, "}")) { nestcount--; if (!nestcount) { break; @@ -324,7 +324,7 @@ qboolean TIKI_ParseIncludes(dloaddef_t *ld) while (1) { if (!Q_stricmpn(token, mapname, strlen(token)) || !Q_stricmpn(token, servertype, strlen(token))) { b_incl = true; - } else if (!stricmp(token, "{") || !ld->tikiFile.TokenAvailable(true)) { + } else if (!Q_stricmp(token, "{") || !ld->tikiFile.TokenAvailable(true)) { break; } @@ -386,13 +386,13 @@ void TIKI_ParseAnimations(dloaddef_t *ld) while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "}")) { + if (!Q_stricmp(token, "}")) { if (!b_mapspec) { // Return when there is no mapspec return; } b_mapspec = false; - } else if (!stricmp(token, "$mapspec")) { + } else if (!Q_stricmp(token, "$mapspec")) { token = ld->tikiFile.GetToken(true); if (sv_mapname) { mapname = sv_mapname->string; @@ -401,9 +401,9 @@ void TIKI_ParseAnimations(dloaddef_t *ld) } while (ld->tikiFile.TokenAvailable(true)) { - if (!strncmp(token, mapname, strlen(token))) { + if (!Q_strncmp(token, mapname, strlen(token))) { b_mapspec = true; - } else if (!stricmp(token, "{")) { + } else if (!Q_stricmp(token, "{")) { break; } @@ -468,7 +468,7 @@ void TIKI_ParseAnimations(dloaddef_t *ld) if (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "{")) { + if (!Q_stricmp(token, "{")) { TIKI_ParseAnimationCommands(ld, anim); } else { ld->tikiFile.UnGetToken(); @@ -493,21 +493,21 @@ int TIKI_ParseSurfaceFlag(const char *token) { int flags = 0; - if (!stricmp(token, "skin1")) { + if (!Q_stricmp(token, "skin1")) { flags = TIKI_SURF_SKIN1; - } else if (!stricmp(token, "skin2")) { + } else if (!Q_stricmp(token, "skin2")) { flags = TIKI_SURF_SKIN2; - } else if (!stricmp(token, "skin3")) { + } else if (!Q_stricmp(token, "skin3")) { flags = TIKI_SURF_SKIN3; - } else if (!stricmp(token, "nodraw")) { + } else if (!Q_stricmp(token, "nodraw")) { flags = TIKI_SURF_NODRAW; - } else if (!stricmp(token, "nodamage")) { + } else if (!Q_stricmp(token, "nodamage")) { flags = TIKI_SURF_NODAMAGE; - } else if (!stricmp(token, "crossfade")) { + } else if (!Q_stricmp(token, "crossfade")) { flags = TIKI_SURF_CROSSFADE; - } else if (!stricmp(token, "nomipmaps")) { + } else if (!Q_stricmp(token, "nomipmaps")) { flags = TIKI_SURF_NOMIPMAPS; - } else if (!stricmp(token, "nopicmip")) { + } else if (!Q_stricmp(token, "nopicmip")) { flags = TIKI_SURF_NOPICMIP; } else { TIKI_Error("Unknown surface flag %s\n", token); @@ -741,7 +741,7 @@ qboolean TIKI_LoadSetupCaseHeader( } val = keyValues->find(key); - if (val && !stricmp(val->c_str(), value)) { + if (val && !Q_stricmp(val->c_str(), value)) { match = true; } break; @@ -862,7 +862,7 @@ qboolean TIKI_LoadSetupCase( } for (currentSurface = 0; currentSurface < *numSurfacesSetUp; currentSurface++) { - if (!stricmp(loadsurfaces[currentSurface].name, name)) { + if (!Q_stricmp(loadsurfaces[currentSurface].name, name)) { break; } } @@ -1001,21 +1001,21 @@ qboolean TIKI_ParseSetup(dloaddef_t *ld) while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "scale")) { + if (!Q_stricmp(token, "scale")) { load_scale = ld->tikiFile.GetFloat(false); WriteScale(ld, load_scale); - } else if (!stricmp(token, "lod_scale")) { + } else if (!Q_stricmp(token, "lod_scale")) { lod_scale = ld->tikiFile.GetFloat(false) / 5.0f; WriteLoadScale(ld, lod_scale); - } else if (!stricmp(token, "lod_bias")) { + } else if (!Q_stricmp(token, "lod_bias")) { lod_bias = ld->tikiFile.GetFloat(false); WriteLodBias(ld, lod_bias); - } else if (!stricmp(token, "skelmodel")) { + } else if (!Q_stricmp(token, "skelmodel")) { token = ld->tikiFile.GetToken(false); strcpy(name, ld->tikiFile.currentScript->path); strcat(name, token); WriteSkelmodel(ld, name); - } else if (!stricmp(token, "path")) { + } else if (!Q_stricmp(token, "path")) { token = ld->tikiFile.GetToken(false); strcpy(ld->tikiFile.currentScript->path, token); length = strlen(ld->tikiFile.currentScript->path); @@ -1024,32 +1024,32 @@ qboolean TIKI_ParseSetup(dloaddef_t *ld) if (*token != '/' && *token != '\\') { strcat(ld->tikiFile.currentScript->path, "/"); } - } else if (!stricmp(token, "orgin")) { + } else if (!Q_stricmp(token, "orgin")) { tmpVec[0] = ld->tikiFile.GetFloat(false); tmpVec[1] = ld->tikiFile.GetFloat(false); tmpVec[2] = ld->tikiFile.GetFloat(false); WriteOrigin(ld, tmpVec[0], tmpVec[1], tmpVec[2]); - } else if (!stricmp(token, "lightoffset")) { + } else if (!Q_stricmp(token, "lightoffset")) { tmpVec[0] = ld->tikiFile.GetFloat(false); tmpVec[1] = ld->tikiFile.GetFloat(false); tmpVec[2] = ld->tikiFile.GetFloat(false); WriteLightOffset(ld, tmpVec[0], tmpVec[1], tmpVec[2]); - } else if (!stricmp(token, "radius")) { + } else if (!Q_stricmp(token, "radius")) { tmpFloat = ld->tikiFile.GetFloat(false); WriteRadius(ld, tmpFloat); - } else if (!stricmp(token, "surface")) { + } else if (!Q_stricmp(token, "surface")) { token = ld->tikiFile.GetToken(false); WriteSurface(ld, token); while (ld->tikiFile.TokenAvailable(false)) { token = ld->tikiFile.GetToken(false); - if (!stricmp(token, "flags")) { + if (!Q_stricmp(token, "flags")) { token = ld->tikiFile.GetToken(false); tmpInt = TIKI_ParseSurfaceFlag(token); WriteFlags(ld, tmpInt); - } else if (!stricmp(token, "damage")) { + } else if (!Q_stricmp(token, "damage")) { tmpFloat = ld->tikiFile.GetFloat(false); WriteDamage(ld, tmpFloat); - } else if (!stricmp(token, "shader")) { + } else if (!Q_stricmp(token, "shader")) { token = ld->tikiFile.GetToken(false); if (strstr(token, ".")) { strcpy(name, ld->tikiFile.currentScript->path); @@ -1060,13 +1060,13 @@ qboolean TIKI_ParseSetup(dloaddef_t *ld) } } } - } else if (!stricmp(token, "ischaracter")) { + } else if (!Q_stricmp(token, "ischaracter")) { ld->bIsCharacter = true; - } else if (!stricmp(token, "case")) { + } else if (!Q_stricmp(token, "case")) { if (!TIKI_ParseCase(ld)) { return false; } - } else if (!stricmp(token, "}")) { + } else if (!Q_stricmp(token, "}")) { return true; } else { TIKI_Error( @@ -1102,7 +1102,7 @@ void TIKI_ParseInitCommands(dloaddef_t *ld, dloadinitcmd_t **cmdlist, int maxcmd while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "}")) { + if (!Q_stricmp(token, "}")) { break; } @@ -1157,11 +1157,11 @@ void TIKI_ParseInit(dloaddef_t *ld) while (ld->tikiFile.TokenAvailable(true)) { token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "client")) { + if (!Q_stricmp(token, "client")) { TIKI_ParseInitCommands(ld, ld->loadclientinitcmds, 160, &ld->numclientinitcmds); - } else if (!stricmp(token, "server")) { + } else if (!Q_stricmp(token, "server")) { TIKI_ParseInitCommands(ld, ld->loadserverinitcmds, 160, &ld->numserverinitcmds); - } else if (!stricmp(token, "}")) { + } else if (!Q_stricmp(token, "}")) { break; } else { TIKI_Error( @@ -1195,8 +1195,8 @@ qboolean TIKI_ParseCase(dloaddef_t *ld) __newcase: token = ld->tikiFile.GetToken(false); WriteCaseKey(ld, token); - isheadmodel = !stricmp(token, "headmodel"); - isheadskin = !stricmp(token, "headskin"); + isheadmodel = !Q_stricmp(token, "headmodel"); + isheadskin = !Q_stricmp(token, "headskin"); while (1) { if (!ld->tikiFile.TokenAvailable(true)) { @@ -1209,9 +1209,9 @@ __newcase: } token = ld->tikiFile.GetToken(true); - if (!stricmp(token, "case")) { + if (!Q_stricmp(token, "case")) { goto __newcase; - } else if (!stricmp(token, "{")) { + } else if (!Q_stricmp(token, "{")) { break; } From 2ee1a2099db01d10c5d2e38b1d378e5eeed5aaaa Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:45:50 +0200 Subject: [PATCH 0364/2040] Ignore map name case sensitivity when parsing map-specific animations --- code/tiki/tiki_parse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index 5ea4ad38..f4300ec9 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -401,7 +401,7 @@ void TIKI_ParseAnimations(dloaddef_t *ld) } while (ld->tikiFile.TokenAvailable(true)) { - if (!Q_strncmp(token, mapname, strlen(token))) { + if (!Q_stricmpn(token, mapname, strlen(token))) { b_mapspec = true; } else if (!Q_stricmp(token, "{")) { break; From b7a0607d52a55839b3ab47a01ad0f1e9d06af607 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:55:42 +0200 Subject: [PATCH 0365/2040] Using parameters that take the entity rather than raw values --- code/fgame/actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.h b/code/fgame/actor.h index a31d4fd6..7274f8ce 100644 --- a/code/fgame/actor.h +++ b/code/fgame/actor.h @@ -1714,7 +1714,7 @@ inline bool Actor::CanSeeFOV(Entity *ent) bCanSee = false; - if (InFOV(ent->centroid) && gi.AreasConnected(edict->r.areanum, ent->edict->r.areanum)) { + if (InFOV(ent) && AreasConnected(ent)) { bCanSee = CanSee(ent, 0, 0, false); } From 135b519dd8a37b7edff2ec5970422759b7a0b491 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:47:06 +0200 Subject: [PATCH 0366/2040] Reduced actor's change of getting curious --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 3c417781..997e7798 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -8852,7 +8852,7 @@ void Actor::CuriousSound(int iType, vec3_t sound_origin, float fDistSquared, flo } } - if ((fRangeFactor * m_fSoundAwareness) < (rand() / 21474836.0)) { + if ((fRangeFactor * m_fSoundAwareness) < (rand() / 327.67f)) { return; } From b75c7b64f1480a1e5f6e79c00c0ccd4a2a452659 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:28:34 +0200 Subject: [PATCH 0367/2040] Still allow crouch when glued in 1.0 and in Single-player mode This fixes #303 where the player is standing in the truck in m4l2 --- code/fgame/player_conditionals.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/fgame/player_conditionals.cpp b/code/fgame/player_conditionals.cpp index e5043e33..71dd43ad 100644 --- a/code/fgame/player_conditionals.cpp +++ b/code/fgame/player_conditionals.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -784,7 +784,8 @@ qboolean Player::CondCrouch(Conditional& condition) { // Added in 2.0 // Don't crouch if the player is not moving - if (client->ps.pm_flags & PMF_NO_MOVE) { + if (client->ps.pm_flags & PMF_NO_MOVE + && (g_target_game > target_game_e::TG_MOH || g_gametype->integer != GT_SINGLE_PLAYER)) { // Added in 2.30 // Allow ducking if specified if (!m_pGlueMaster || !m_bGlueDuckable) { @@ -812,7 +813,7 @@ qboolean Player::CondAnimDoneTorso(Conditional& condition) qboolean Player::CondAttackPrimary(Conditional& condition) { - Weapon* weapon; + Weapon *weapon; if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) { return false; @@ -852,7 +853,7 @@ qboolean Player::CondAttackButtonPrimary(Conditional& condition) qboolean Player::CondAttackSecondary(Conditional& condition) { - Weapon* weapon; + Weapon *weapon; if (level.playerfrozen || m_bFrozen || (flags & FL_IMMOBILE)) { return false; @@ -1949,7 +1950,7 @@ Condition Player::Conditions[] = { {"ATTACK_SECONDARY_BUTTON", &Player::CondAttackButtonSecondary }, {"CHECK_MOVEMENT_SPEED", &Player::CondCheckMovementSpeed }, - // Weapon conditions + // Weapon conditions {"ANIMDONE_VM", &Player::CondAnimDoneVM }, {"CLIENT_COMMAND", &Player::CondClientCommand }, {"IS_VM_ANIM", &Player::CondVMAnim }, From 911e87c6ec26ec42ef5360ea1c3af317538ce4b5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:29:41 +0200 Subject: [PATCH 0368/2040] `physics_off`: Don't reset the physics in 1.0 in Single-player mode This fixes #303 in m4l2 where the player doesn't have their gun holstered in the truck --- code/fgame/player.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 40fd9b37..6b5a791d 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -9946,9 +9946,11 @@ void Player::EventGetCurrentDMWeaponType(Event *ev) void Player::PhysicsOff(Event *ev) { - // Added in 2.0 - // Reset the state to STAND before disabling physics - EvaluateState(statemap_Torso->FindState("STAND"), statemap_Legs->FindState("STAND")); + if (g_target_game > TG_MOH || g_gametype->integer != GT_SINGLE_PLAYER) { + // Added in 2.0 + // Reset the state to STAND before disabling physics + EvaluateState(statemap_Torso->FindState("STAND"), statemap_Legs->FindState("STAND")); + } flags |= FL_IMMOBILE; } From d64ef13b795efb64ef3f33dc7ceadecec46b1e2a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:34:48 +0200 Subject: [PATCH 0369/2040] Fixed script_skyorigin never being sent to clients --- code/fgame/scriptslave.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 90c2b365..71b0f33b 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -2113,6 +2113,7 @@ CLASS_DECLARATION(ScriptSlave, ScriptSkyOrigin, "script_skyorigin") { ScriptSkyOrigin::ScriptSkyOrigin() { edict->s.renderfx |= RF_SKYORIGIN; + edict->r.svFlags &= ~SVF_NOCLIENT; setContents(0); setSolidType(SOLID_NOT); } From 57ac7d8c19fb7f228685d57a11d779afec1e6f3b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:36:12 +0200 Subject: [PATCH 0370/2040] Removed code that is already present in CG_SetupFog() and CG_SetupPortalSky() --- code/cgame/cg_view.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/code/cgame/cg_view.c b/code/cgame/cg_view.c index 6e7a63ef..cc2721e3 100644 --- a/code/cgame/cg_view.c +++ b/code/cgame/cg_view.c @@ -560,17 +560,6 @@ static int CG_CalcViewValues(void) CG_CalcVrect(); CG_SetupFog(); - // setup fog and far clipping plane - cg.refdef.farplane_distance = cg.farplane_distance; - VectorCopy(cg.farplane_color, cg.refdef.farplane_color); - cg.refdef.farplane_cull = cg.farplane_cull; - - // setup portal sky - cg.refdef.sky_alpha = cg.sky_alpha; - cg.refdef.sky_portal = cg.sky_portal; - memcpy(cg.refdef.sky_axis, cg.sky_axis, sizeof(cg.sky_axis)); - VectorCopy(cg.sky_origin, cg.refdef.sky_origin); - ps = &cg.predicted_player_state; VectorCopy(ps->origin, cg.refdef.vieworg); From c753dcafd815ba681161db8c8f9193ee65610562 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:36:35 +0200 Subject: [PATCH 0371/2040] SurfIsOffscreen: use raw surface values rather than tess values --- code/renderer/tr_main.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 1fadb640..a836d705 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -993,12 +993,12 @@ qboolean SurfIsOffscreen(const srfSurfaceFace_t* surface, shader_t* shader, int R_RotateForEntity(&tr.refdef.entities[entityNum], &tr.viewParms, &surfOr); } - for ( i = 0; i < tess.numVertexes; i++ ) + for ( i = 0; i < surface->numPoints; i++ ) { int j; unsigned int pointFlags = 0; - R_TransformModelToClip( tess.xyz[i], tr.ori.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); + R_TransformModelToClip( surface->points[i], surfOr.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); for ( j = 0; j < 3; j++ ) { @@ -1026,20 +1026,25 @@ qboolean SurfIsOffscreen(const srfSurfaceFace_t* surface, shader_t* shader, int // based on vertex distance isn't 100% correct (we should be checking for // range to the surface), but it's good enough for the types of portals // we have in the game right now. - numTriangles = tess.numIndexes / 3; + numTriangles = surface->numIndices / 3; - for ( i = 0; i < tess.numIndexes; i += 3 ) + for ( i = 0; i < surface->numIndices; i += 3 ) { vec3_t normal; float dot; float len; + unsigned* indices; - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.ori.origin, normal ); + indices = (unsigned*)(((char*)surface) + surface->ofsIndices); - len = VectorLengthSquared( normal ); // lose the sqrt - if ( len < shortest ) - { - shortest = len; + VectorSubtract( surface->points[indices[i]], surfOr.viewOrigin, normal); + + if (shader->fDistRange > 0) { + len = VectorLengthSquared(normal); // lose the sqrt + if (len < shortest) + { + shortest = len; + } } if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 ) From e1f2433c36206e0852656f4d88c13b8bc738cd50 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:36:58 +0200 Subject: [PATCH 0372/2040] Fixed sky portal rendering This fixes #260 --- code/renderer/tr_sky_portal.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/code/renderer/tr_sky_portal.cpp b/code/renderer/tr_sky_portal.cpp index 66d88b98..d79747c6 100644 --- a/code/renderer/tr_sky_portal.cpp +++ b/code/renderer/tr_sky_portal.cpp @@ -99,9 +99,7 @@ void R_Sky_Render() { return; } - if (tr.viewParms.isPortalSky) - { - ri.Printf(PRINT_WARNING, "WARNING: Recursive skies found! Make that not happen!\n"); + if (tr.viewParms.isPortalSky) { return; } @@ -115,7 +113,6 @@ void R_Sky_Render() { return; } - tr.skyRendered = qtrue; oldParms = tr.viewParms; newParms = tr.viewParms; @@ -133,8 +130,16 @@ void R_Sky_Render() { MatrixMultiply(newParms.ori.axis, tr.refdef.sky_axis, newParms.ori.axis); } - tr.viewParms.isPortalSky = qtrue; VectorCopy(newParms.ori.origin, newParms.pvsOrigin); + newParms.isPortalSky = qtrue; + newParms.farplane_distance = tr.refdef.skybox_farplane; + newParms.renderTerrain = tr.refdef.render_terrain; + + if (oldParms.farplane_bias == 0.0 || oldParms.farplane_distance == 0.0) { + newParms.farplane_bias = 0.0; + } else { + newParms.farplane_bias = newParms.farplane_distance / oldParms.farplane_distance * oldParms.farplane_bias; + } leaf = R_PointInLeaf(newParms.pvsOrigin); if (leaf) { @@ -143,8 +148,8 @@ void R_Sky_Render() { tr.viewParms = oldParms; - tr.viewParms.isPortalSky = qfalse; tr.portalsky.numSurfs = 0; + tr.skyRendered = qtrue; R_RotateForViewer(); R_SetupFrustum(); } From 0181fbcfa09952a4312a94a5b5f17d30ed63332c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 4 Jun 2024 19:52:32 +0200 Subject: [PATCH 0373/2040] Use the weight's bone index if there is no morph --- code/renderer/tr_model.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index 137ae4a4..a50d2931 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -1250,7 +1250,12 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { morph++; } - channelNum = skelmodel->pBones[ morph->morphIndex ].channel; + if (newVerts->numMorphs) { + channelNum = skelmodel->pBones[morph->morphIndex].channel; + } else { + channelNum = skelmodel->pBones[weight->boneIndex].channel; + } + boneNum = tiki->m_boneList.GetLocalFromGlobal( channelNum ); bone = &bones[ boneNum ]; @@ -1282,7 +1287,12 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { morph++; } - bone = &bones[ morph->morphIndex ]; + if (newVerts->numMorphs) { + bone = &bones[morph->morphIndex]; + } else { + bone = &bones[weight->boneIndex]; + } + SkelVertGetNormal( newVerts, bone, normal ); for( weightNum = 0; weightNum < newVerts->numWeights; weightNum++ ) { From 77de0b78baa2c7a5b3f3a6bcb4fb6b069a85693e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 4 Jun 2024 19:56:01 +0200 Subject: [PATCH 0374/2040] First test if the entity has morphs before proceeding to loop through vertices --- code/renderer/tr_model.cpp | 218 ++++++++++++++++++++++++------------- 1 file changed, 141 insertions(+), 77 deletions(-) diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index a50d2931..6ce0c1db 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -1172,9 +1172,6 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { outNormal = &tess.normal[baseVertex]; newVerts = sf->pVerts; - bones = &TIKI_Skel_Bones[backEnd.currentEntity->e.bonestart]; - morphs = &skeletorMorphCache[backEnd.currentEntity->e.morphstart]; - if (render_count == sf->numVerts) { for (i = 0; i < indexes; i++) { @@ -1218,33 +1215,33 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { // // just copy the vertexes // - for( vertNum = 0; vertNum < render_count; vertNum++ ) + bones = &TIKI_Skel_Bones[backEnd.currentEntity->e.bonestart]; + morphs = &skeletorMorphCache[backEnd.currentEntity->e.morphstart]; + + if (backEnd.currentEntity->e.hasMorph) { - vec3_t normal; - vec3_t out; - - VectorClear( out ); - VectorClear( outXyz ); - - weight = ( skelWeight_t * )( ( byte * )newVerts + sizeof( skeletorVertex_t ) + sizeof( skeletorMorph_t ) * newVerts->numMorphs ); - - if( backEnd.currentEntity->e.hasMorph ) + if (mesh > 0) { - vec3_t totalmorph; - - VectorClear( totalmorph ); - morph = ( skeletorMorph_t * )( ( byte * )newVerts + sizeof( skeletorVertex_t ) ); - - if( mesh > 0 ) + for (vertNum = 0; vertNum < render_count; vertNum++) { + vec3_t normal; + vec3_t out; + vec3_t totalmorph; int channelNum; int boneNum; - for( morphNum = 0; morphNum < newVerts->numMorphs; morphNum++ ) { - morphcache = &morphs[ morph->morphIndex ]; + VectorClear(out); + VectorClear(outXyz); + VectorClear(totalmorph); - if( *morphcache ) { - SkelMorphGetXyz( morph, morphcache, totalmorph ); + weight = (skelWeight_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs); + morph = (skeletorMorph_t*)((byte*)newVerts + sizeof(skeletorVertex_t)); + + for (morphNum = 0; morphNum < newVerts->numMorphs; morphNum++) { + morphcache = &morphs[morph->morphIndex]; + + if (*morphcache) { + SkelMorphGetXyz(morph, morphcache, totalmorph); } morph++; @@ -1256,32 +1253,57 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { channelNum = skelmodel->pBones[weight->boneIndex].channel; } - boneNum = tiki->m_boneList.GetLocalFromGlobal( channelNum ); - bone = &bones[ boneNum ]; + boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + bone = &bones[boneNum]; - SkelVertGetNormal( newVerts, bone, normal ); + SkelVertGetNormal(newVerts, bone, normal); - for( weightNum = 0; weightNum < newVerts->numWeights; weightNum++ ) { - channelNum = skelmodel->pBones[ weight->boneIndex ].channel; - boneNum = tiki->m_boneList.GetLocalFromGlobal( channelNum ); - bone = &bones[ boneNum ]; + for (weightNum = 0; weightNum < newVerts->numWeights; weightNum++) { + channelNum = skelmodel->pBones[weight->boneIndex].channel; + boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + bone = &bones[boneNum]; - if( !weightNum ) { - SkelWeightMorphGetXyz( weight, bone, totalmorph, out ); + if (!weightNum) { + SkelWeightMorphGetXyz(weight, bone, totalmorph, out); } else { - SkelWeightGetXyz( weight, bone, out ); + SkelWeightGetXyz(weight, bone, out); } weight++; } - } - else - { - for( morphNum = 0; morphNum < newVerts->numMorphs; morphNum++ ) { - morphcache = &morphs[ morph->morphIndex ]; - if( *morphcache ) { - SkelMorphGetXyz( morph, morphcache, totalmorph ); + VectorCopy(normal, *outNormal); + VectorScale(out, scale, outXyz); + + tess.texCoords[baseVertex + vertNum][0][0] = newVerts->texCoords[0]; + tess.texCoords[baseVertex + vertNum][0][1] = newVerts->texCoords[1]; + // FIXME: fill in lightmapST for completeness? + + newVerts = (skeletorVertex_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs + sizeof(skelWeight_t) * newVerts->numWeights); + outXyz += 4; + outNormal++; + } + } + else + { + for (vertNum = 0; vertNum < render_count; vertNum++) + { + vec3_t normal; + vec3_t out; + vec3_t totalmorph; + + VectorClear(out); + VectorClear(outXyz); + VectorClear(totalmorph); + + weight = (skelWeight_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs); + morph = (skeletorMorph_t*)((byte*)newVerts + sizeof(skeletorVertex_t)); + + for (morphNum = 0; morphNum < newVerts->numMorphs; morphNum++) { + morphcache = &morphs[morph->morphIndex]; + + if (*morphcache) { + SkelMorphGetXyz(morph, morphcache, totalmorph); } morph++; @@ -1293,70 +1315,112 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { bone = &bones[weight->boneIndex]; } - SkelVertGetNormal( newVerts, bone, normal ); + SkelVertGetNormal(newVerts, bone, normal); - for( weightNum = 0; weightNum < newVerts->numWeights; weightNum++ ) { - bone = &bones[ weight->boneIndex ]; + for (weightNum = 0; weightNum < newVerts->numWeights; weightNum++) { + bone = &bones[weight->boneIndex]; - if( !weightNum ) { - SkelWeightMorphGetXyz( weight, bone, totalmorph, out ); + if (!weightNum) { + SkelWeightMorphGetXyz(weight, bone, totalmorph, out); } else { - SkelWeightGetXyz( weight, bone, out ); + SkelWeightGetXyz(weight, bone, out); } weight++; } + + VectorCopy(normal, *outNormal); + VectorScale(out, scale, outXyz); + + tess.texCoords[baseVertex + vertNum][0][0] = newVerts->texCoords[0]; + tess.texCoords[baseVertex + vertNum][0][1] = newVerts->texCoords[1]; + // FIXME: fill in lightmapST for completeness? + + newVerts = (skeletorVertex_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs + sizeof(skelWeight_t) * newVerts->numWeights); + outXyz += 4; + outNormal++; } } - else - { - if( mesh > 0 ) + } + else + { + if (mesh > 0) + { + for (vertNum = 0; vertNum < render_count; vertNum++) { + vec3_t normal; + vec3_t out; int channelNum; int boneNum; - channelNum = skelmodel->pBones[ weight->boneIndex ].channel; - boneNum = tiki->m_boneList.GetLocalFromGlobal( channelNum ); - bone = &bones[ boneNum ]; + VectorClear(out); + VectorClear(outXyz); - SkelVertGetNormal(newVerts, bone, normal); + weight = (skelWeight_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs); - for( weightNum = 0; weightNum < newVerts->numWeights; weightNum++ ) { - channelNum = skelmodel->pBones[ weight->boneIndex ].channel; - boneNum = tiki->m_boneList.GetLocalFromGlobal( channelNum ); - bone = &bones[ boneNum ]; + channelNum = skelmodel->pBones[weight->boneIndex].channel; + boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + bone = &bones[boneNum]; - SkelWeightGetXyz( weight, bone, out ); + SkelVertGetNormal(newVerts, bone, normal); + + for (weightNum = 0; weightNum < newVerts->numWeights; weightNum++) { + channelNum = skelmodel->pBones[weight->boneIndex].channel; + boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + bone = &bones[boneNum]; + + SkelWeightGetXyz(weight, bone, out); weight++; } - } - else - { - bone = &bones[weight->boneIndex]; - SkelVertGetNormal(newVerts, bone, normal); - for( weightNum = 0; weightNum < newVerts->numWeights; weightNum++ ) { - bone = &bones[ weight->boneIndex ]; + VectorCopy(normal, *outNormal); + VectorScale(out, scale, outXyz); - SkelWeightGetXyz( weight, bone, out ); + tess.texCoords[baseVertex + vertNum][0][0] = newVerts->texCoords[0]; + tess.texCoords[baseVertex + vertNum][0][1] = newVerts->texCoords[1]; + // FIXME: fill in lightmapST for completeness? - weight++; - } + newVerts = (skeletorVertex_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs + sizeof(skelWeight_t) * newVerts->numWeights); + outXyz += 4; + outNormal++; } } + else + { + for (vertNum = 0; vertNum < render_count; vertNum++) + { + vec3_t normal; + vec3_t out; - VectorCopy(normal, *outNormal); + VectorClear(out); + VectorClear(outXyz); - VectorScale( out, scale, outXyz ); + weight = (skelWeight_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs); - tess.texCoords[baseVertex + vertNum][0][0] = newVerts->texCoords[0]; - tess.texCoords[baseVertex + vertNum][0][1] = newVerts->texCoords[1]; - // FIXME: fill in lightmapST for completeness? + bone = &bones[weight->boneIndex]; + SkelVertGetNormal(newVerts, bone, normal); - newVerts = ( skeletorVertex_t * )( ( byte * )newVerts + sizeof( skeletorVertex_t ) + sizeof( skeletorMorph_t ) * newVerts->numMorphs + sizeof( skelWeight_t ) * newVerts->numWeights ); - outXyz += 4; - outNormal++; + for (weightNum = 0; weightNum < newVerts->numWeights; weightNum++) { + bone = &bones[weight->boneIndex]; + + SkelWeightGetXyz(weight, bone, out); + + weight++; + } + + VectorCopy(normal, *outNormal); + VectorScale(out, scale, outXyz); + + tess.texCoords[baseVertex + vertNum][0][0] = newVerts->texCoords[0]; + tess.texCoords[baseVertex + vertNum][0][1] = newVerts->texCoords[1]; + // FIXME: fill in lightmapST for completeness? + + newVerts = (skeletorVertex_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs + sizeof(skelWeight_t) * newVerts->numWeights); + outXyz += 4; + outNormal++; + } + } } #if 0 From 2b66672d2df435e696884584445da6c0099e0acc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:50:08 +0200 Subject: [PATCH 0375/2040] Added MAX_GLOBAL_FROM_LOCAL constant and implemented `skelChannelList_s::GlobalChannel` and `skelChannelList_s::LocalChannel` --- code/skeletor/skeletor_utilities.cpp | 12 ++++++++++++ code/tiki/tiki_shared.h | 9 +++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/code/skeletor/skeletor_utilities.cpp b/code/skeletor/skeletor_utilities.cpp index 8dc6f80b..75f28a8c 100644 --- a/code/skeletor/skeletor_utilities.cpp +++ b/code/skeletor/skeletor_utilities.cpp @@ -71,6 +71,18 @@ int FileLength(FILE *pFile) return iEnd; } + +int skelChannelList_s::GlobalChannel(int localchannel) const +{ + assert(localchannel < MAX_GLOBAL_FROM_LOCAL); + return m_chanGlobalFromLocal[localchannel]; +} + +int skelChannelList_s::LocalChannel(int channel) const +{ + return m_chanLocalFromGlobal[channel]; +} + int skelChannelList_s::GetLocalFromGlobal(int globalChannel) const { if (m_chanLocalFromGlobal && globalChannel < m_numLocalFromGlobal) { diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index 763054bc..d3863c6e 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -91,9 +91,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define TIKI_SURF_NOMIPMAPS (1 << 8) #define TIKI_SURF_NOPICMIP (1 << 9) -#define MAX_SKELMODELS 12 -#define MAX_TIKI_SHADER 4 -#define MAX_TIKI_ALIASES 4095 +#define MAX_SKELMODELS 12 +#define MAX_TIKI_SHADER 4 +#define MAX_TIKI_ALIASES 4095 +#define MAX_GLOBAL_FROM_LOCAL 200 typedef struct AliasList_s AliasList_t; typedef struct AliasListNode_s AliasListNode_t; @@ -120,7 +121,7 @@ private: short int *m_chanLocalFromGlobal; public: - short int m_chanGlobalFromLocal[200]; + short int m_chanGlobalFromLocal[MAX_GLOBAL_FROM_LOCAL]; int NumChannels(void) const; void ZeroChannels(void); From c4523db991a8cfc3a70865aa3e8505c9f74bfb28 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:48:29 +0200 Subject: [PATCH 0376/2040] Added GetBoneChannelType --- code/skeletor/bonetable.cpp | 32 +++++++++++++++++++++++++++++ code/skeletor/skeletor_name_lists.h | 1 + 2 files changed, 33 insertions(+) diff --git a/code/skeletor/bonetable.cpp b/code/skeletor/bonetable.cpp index 02c8594a..46a86723 100644 --- a/code/skeletor/bonetable.cpp +++ b/code/skeletor/bonetable.cpp @@ -241,6 +241,38 @@ bool IsBogusChannelName(const char *name) return false; } +int GetBoneChannelType(const char* name) +{ + size_t len; + + if (!name) { + return 2; + } + + if (IsBogusChannelName(name)) { + return 2; + } + + len = strlen(name); + if (len < 4) { + return 3; + } + + if (!strcmp(name + len - 4, " rot")) { + return 0; + } + + if (!strcmp(name + len - 4, " pos")) { + return 1; + } + + if (len >= 6 && !strcmp(name + len - 6, " rotFK")) { + return 2; + } + + return 3; +} + int GetChannelTypeFromName(const char *name) { int i; diff --git a/code/skeletor/skeletor_name_lists.h b/code/skeletor/skeletor_name_lists.h index c26f1ccd..56b5f251 100644 --- a/code/skeletor/skeletor_name_lists.h +++ b/code/skeletor/skeletor_name_lists.h @@ -57,6 +57,7 @@ private: void SetChannelName(ChannelName_t *channel, const char *newName); }; +int GetBoneChannelType(const char* name); int GetChannelTypeFromName(const char *name); #else From 091c8b4d1260f36ce85d3f6aad8040006af75f80 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:40:43 +0200 Subject: [PATCH 0377/2040] Optimized channel data memory and performance (feature from moh 2.0 and above) --- code/skeletor/skeletor.cpp | 64 +-- .../skeletor/skeletor_animation_file_format.h | 4 +- code/skeletor/skeletor_loadanimation.cpp | 406 +++++++++++++----- code/skeletor/skeletorbones.cpp | 48 ++- 4 files changed, 364 insertions(+), 158 deletions(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 1654f49a..40febcfd 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -1047,31 +1047,39 @@ int skeletor_c::GetMorphWeightFrame(int index, float time, int *data) return GetMorphWeightFrame(data); } -vec4_t *DecodeFrameValue(skanChannelHdr *channelFrames, int desiredFrameNum) +float *DecodeFrameValue(skanChannelHdr *channelFrames, int desiredFrameNum) { skanGameFrame *foundFrame; + size_t frameSize; int i; + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float)); + foundFrame = channelFrames->ary_frames; for (i = 0; i < channelFrames->nFramesInChannel; i++) { - if (channelFrames->ary_frames[i].nFrameNum >= desiredFrameNum) { - foundFrame = &channelFrames->ary_frames[i]; + if (foundFrame->nFrameNum >= desiredFrameNum) { break; } + + foundFrame = (skanGameFrame *)((byte *)foundFrame + frameSize); } - return &foundFrame->pChannelData; + if (foundFrame->nFrameNum > desiredFrameNum) { + foundFrame = (skanGameFrame *)((byte *)channelFrames->ary_frames + foundFrame->nPrevFrameIndex * frameSize); + } + + return foundFrame->pChannelData; } int skeletor_c::GetMorphWeightFrame(int *data) { - int numTargets; - int animChannelNum; - int blendNum; - float weight; - int modelChannelNum; - vec4_t *channelData; + int numTargets; + int animChannelNum; + int blendNum; + float weight; + int modelChannelNum; + float *channelData; numTargets = m_morphTargetList.NumChannels(); @@ -1082,38 +1090,36 @@ int skeletor_c::GetMorphWeightFrame(int *data) memset(data, 0, sizeof(*data) * numTargets); for (blendNum = 0; blendNum < m_frameList.numMovementFrames; blendNum++) { - weight = m_frameList.m_blendInfo[blendNum].weight; + const skanBlendInfo& blendInfo = m_frameList.m_blendInfo[blendNum]; + weight = blendInfo.weight; if (weight > 0.001) { - for (modelChannelNum = 0; modelChannelNum < m_morphTargetList.NumChannels(); modelChannelNum++) { - animChannelNum = m_morphTargetList.m_chanGlobalFromLocal[modelChannelNum]; - animChannelNum = m_morphTargetList.GetLocalFromGlobal(animChannelNum); + for (modelChannelNum = 0; modelChannelNum < numTargets; modelChannelNum++) { + animChannelNum = m_morphTargetList.GlobalChannel(modelChannelNum); + animChannelNum = blendInfo.pAnimationData->channelList.GetLocalFromGlobal(animChannelNum); if (animChannelNum >= 0) { - channelData = DecodeFrameValue( - &m_frameList.m_blendInfo[blendNum].pAnimationData->ary_channels[animChannelNum], - m_frameList.m_blendInfo[blendNum].frame - ); - data[modelChannelNum] += (int)((*channelData)[0] * weight); + channelData = + DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame); + data[modelChannelNum] += (int)(channelData[0] * weight); } } } } for (blendNum = 32; blendNum < m_frameList.numActionFrames + 32; blendNum++) { - weight = m_frameList.m_blendInfo[blendNum].weight; + const skanBlendInfo& blendInfo = m_frameList.m_blendInfo[blendNum]; + weight = blendInfo.weight; if (weight > 0.001) { - for (modelChannelNum = 0; modelChannelNum < m_morphTargetList.NumChannels(); modelChannelNum++) { - animChannelNum = m_morphTargetList.m_chanGlobalFromLocal[modelChannelNum]; - animChannelNum = m_morphTargetList.GetLocalFromGlobal(animChannelNum); + for (modelChannelNum = 0; modelChannelNum < numTargets; modelChannelNum++) { + animChannelNum = m_morphTargetList.GlobalChannel(modelChannelNum); + animChannelNum = blendInfo.pAnimationData->channelList.GetLocalFromGlobal(animChannelNum); if (animChannelNum >= 0) { - channelData = DecodeFrameValue( - &m_frameList.m_blendInfo[blendNum].pAnimationData->ary_channels[animChannelNum], - m_frameList.m_blendInfo[blendNum].frame - ); - data[modelChannelNum] += (int)((*channelData)[0] * weight); + channelData = + DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame); + data[modelChannelNum] += (int)(channelData[0] * weight); } } } diff --git a/code/skeletor/skeletor_animation_file_format.h b/code/skeletor/skeletor_animation_file_format.h index 58db9451..0b953174 100644 --- a/code/skeletor/skeletor_animation_file_format.h +++ b/code/skeletor/skeletor_animation_file_format.h @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -59,7 +59,7 @@ typedef struct { typedef struct { short int nFrameNum; short int nPrevFrameIndex; - vec4_t pChannelData; + float pChannelData[1]; } skanGameFrame; typedef struct { diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index 612bb083..c930a469 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -26,52 +26,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "qcommon.h" #include "skeletor.h" -qboolean Compress( - skelAnimGameFrame_t *current, - skelAnimGameFrame_t *last, - int channelIndex, - skelChannelList_c *channelList, - ChannelNameTable *channelNames -) +qboolean Compress(skelAnimGameFrame_t *current, skelAnimGameFrame_t *last, int channelIndex, int numChannels) { float tolerance; float difference; + int i; // high-end PC don't need to compress... return false; - tolerance = current->pChannels[channelIndex][0]; - if (tolerance > -0.000001 && tolerance < 0.000001) { - current->pChannels[channelIndex][0] = 0.0f; + for (i = 0; i < numChannels; i++) { + tolerance = current->pChannels[channelIndex][i]; + if (tolerance > -0.000001 && tolerance < 0.000001) { + current->pChannels[channelIndex][i] = 0.0f; + } } - tolerance = current->pChannels[channelIndex][1]; - if (tolerance > -0.000001 && tolerance < 0.000001) { - current->pChannels[channelIndex][1] = 0.0f; - } - - tolerance = current->pChannels[channelIndex][2]; - if (tolerance > -0.000001 && tolerance < 0.000001) { - current->pChannels[channelIndex][2] = 0.0f; - } - - if (!last) { - return false; - } - - difference = last->pChannels[channelIndex][0] - current->pChannels[channelIndex][0]; - if (difference < -0.001f || difference >= 0.001f) { - return false; - } - - difference = last->pChannels[channelIndex][1] - current->pChannels[channelIndex][1]; - if (difference < -0.001f || difference >= 0.001f) { - return false; - } - - difference = last->pChannels[channelIndex][2] - current->pChannels[channelIndex][2]; - if (difference < -0.001f || difference >= 0.001f) { - return false; + if (last) { + for (i = 0; i < numChannels; i++) { + difference = last->pChannels[channelIndex][i] - current->pChannels[channelIndex][i]; + if (difference < -0.001f || difference >= 0.001f) { + return false; + } + } } return true; @@ -92,7 +69,9 @@ skelAnimDataGameHeader_t *EncodeFrames( skelAnimGameFrame_t *pCurrFrame; skelAnimGameFrame_t *pLastFrame; skanGameFrame *pFrame; + size_t frameSize; int indexLastFrameAdded; + int channelType; pChannel = enAnim->ary_channels; endFrameCap = enAnim->numFrames - 2; @@ -101,45 +80,138 @@ skelAnimDataGameHeader_t *EncodeFrames( pLastFrame = NULL; pCurrFrame = m_frame; - frameCnt = 0; - for (j = 0; j < enAnim->numFrames; j++) { - if (!Compress(pCurrFrame, pLastFrame, i, channelList, channelNames) || j >= endFrameCap) { - frameCnt++; - pLastFrame = pCurrFrame; - } - - pCurrFrame++; - } - - pChannel->ary_frames = (skanGameFrame *)Skel_Alloc(frameCnt * sizeof(skanGameFrame)); - pChannel->nFramesInChannel = frameCnt; - enAnim->nBytesUsed += frameCnt * sizeof(skanGameFrame); - - pLastFrame = NULL; - indexLastFrameAdded = 0; - - pCurrFrame = m_frame; - pFrame = pChannel->ary_frames; - - for (j = 0; j < enAnim->numFrames; j++) { - if (!Compress(pCurrFrame, pLastFrame, i, channelList, channelNames) || j >= endFrameCap) { - pFrame->nFrameNum = j; - pFrame->nPrevFrameIndex = indexLastFrameAdded; - - if (j > 0) { - indexLastFrameAdded++; + channelType = GetBoneChannelType(enAnim->channelList.ChannelName(channelNames, i)); + switch (channelType) { + case 0: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); + frameCnt = 0; + for (j = 0; j < enAnim->numFrames; j++) { + if (!Compress(pCurrFrame, pLastFrame, i, 4) || j >= endFrameCap) { + frameCnt++; + pLastFrame = pCurrFrame; } - pFrame->pChannelData[0] = pCurrFrame->pChannels[i][0]; - pFrame->pChannelData[1] = pCurrFrame->pChannels[i][1]; - pFrame->pChannelData[2] = pCurrFrame->pChannels[i][2]; - pFrame->pChannelData[3] = pCurrFrame->pChannels[i][3]; - pFrame++; - - pLastFrame = pCurrFrame; + pCurrFrame++; } - pCurrFrame++; + pChannel->ary_frames = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->nFramesInChannel = frameCnt; + enAnim->nBytesUsed += frameSize * frameCnt; + + pLastFrame = NULL; + indexLastFrameAdded = 0; + + pCurrFrame = m_frame; + pFrame = pChannel->ary_frames; + + for (j = 0; j < enAnim->numFrames; j++) { + if (!Compress(pCurrFrame, pLastFrame, i, 4) || j >= endFrameCap) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = j; + pFrame->nPrevFrameIndex = indexLastFrameAdded; + + if (j > 0) { + indexLastFrameAdded++; + } + + pFrame->pChannelData[0] = pCurrFrame->pChannels[i][0]; + pFrame->pChannelData[1] = pCurrFrame->pChannels[i][1]; + pFrame->pChannelData[2] = pCurrFrame->pChannels[i][2]; + pFrame->pChannelData[3] = pCurrFrame->pChannels[i][3]; + + pLastFrame = pCurrFrame; + } + + pCurrFrame++; + } + break; + case 1: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); + frameCnt = 0; + for (j = 0; j < enAnim->numFrames; j++) { + if (!Compress(pCurrFrame, pLastFrame, i, 3) || j >= endFrameCap) { + frameCnt++; + pLastFrame = pCurrFrame; + } + + pCurrFrame++; + } + + pChannel->ary_frames = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->nFramesInChannel = frameCnt; + enAnim->nBytesUsed += frameSize * frameCnt; + + pLastFrame = NULL; + indexLastFrameAdded = 0; + + pCurrFrame = m_frame; + pFrame = pChannel->ary_frames; + + for (j = 0; j < enAnim->numFrames; j++) { + if (!Compress(pCurrFrame, pLastFrame, i, 1) || j >= endFrameCap) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = j; + pFrame->nPrevFrameIndex = indexLastFrameAdded; + + if (j > 0) { + indexLastFrameAdded++; + } + + pFrame->pChannelData[0] = pCurrFrame->pChannels[i][0]; + pFrame->pChannelData[1] = pCurrFrame->pChannels[i][1]; + pFrame->pChannelData[2] = pCurrFrame->pChannels[i][2]; + + pLastFrame = pCurrFrame; + } + + pCurrFrame++; + } + break; + case 2: + pChannel->ary_frames = NULL; + pChannel->nFramesInChannel = 0; + break; + case 3: + default: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float)); + frameCnt = 0; + for (j = 0; j < enAnim->numFrames; j++) { + if (!Compress(pCurrFrame, pLastFrame, i, 1) || j >= endFrameCap) { + frameCnt++; + pLastFrame = pCurrFrame; + } + + pCurrFrame++; + } + + pChannel->ary_frames = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->nFramesInChannel = frameCnt; + enAnim->nBytesUsed += frameSize * frameCnt; + + pLastFrame = NULL; + indexLastFrameAdded = 0; + + pCurrFrame = m_frame; + pFrame = pChannel->ary_frames; + + for (j = 0; j < enAnim->numFrames; j++) { + if (!Compress(pCurrFrame, pLastFrame, i, 3) || j >= endFrameCap) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = j; + pFrame->nPrevFrameIndex = indexLastFrameAdded; + + if (j > 0) { + indexLastFrameAdded++; + } + + pFrame->pChannelData[0] = pCurrFrame->pChannels[i][0]; + + pLastFrame = pCurrFrame; + } + + pCurrFrame++; + } + break; } } @@ -335,25 +407,83 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) { skanChannelHdr *pChannel; skanGameFrame *pFrame; + size_t frameSize; int frameCnt; int i, j; - - enAnim->numFrames = MSG_ReadLong(msg); - enAnim->nTotalChannels = MSG_ReadShort(msg); + int channelType; + vec4_t channelData; for (i = 0; i < enAnim->nTotalChannels; i++) { pChannel = &enAnim->ary_channels[i]; - frameCnt = MSG_ReadShort(msg); - pFrame = (skanGameFrame *)Skel_Alloc(frameCnt * sizeof(skanGameFrame)); - pChannel->ary_frames = pFrame; - pChannel->nFramesInChannel = frameCnt; + channelType = GetBoneChannelType(enAnim->channelList.ChannelName(&skeletor_c::m_channelNames, i)); + frameCnt = MSG_ReadShort(msg); - for (j = 0; j < pChannel->nFramesInChannel; j++) { - pFrame = &pChannel->ary_frames[j]; - pFrame->nFrameNum = MSG_ReadShort(msg); - pFrame->nPrevFrameIndex = MSG_ReadShort(msg); - MSG_ReadData(msg, pFrame->pChannelData, sizeof(vec4_t)); + switch (channelType) { + case 0: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); + + pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->ary_frames = pFrame; + pChannel->nFramesInChannel = frameCnt; + + for (j = 0; j < frameCnt; j++) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = MSG_ReadShort(msg); + pFrame->nPrevFrameIndex = MSG_ReadShort(msg); + MSG_ReadData(msg, channelData, sizeof(vec4_t)); + + pFrame->pChannelData[0] = channelData[0]; + pFrame->pChannelData[1] = channelData[1]; + pFrame->pChannelData[2] = channelData[2]; + pFrame->pChannelData[3] = channelData[3]; + } + break; + case 1: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); + + pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->ary_frames = pFrame; + pChannel->nFramesInChannel = frameCnt; + + for (j = 0; j < frameCnt; j++) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = MSG_ReadShort(msg); + pFrame->nPrevFrameIndex = MSG_ReadShort(msg); + MSG_ReadData(msg, channelData, sizeof(vec4_t)); + + pFrame->pChannelData[0] = channelData[0]; + pFrame->pChannelData[1] = channelData[1]; + pFrame->pChannelData[2] = channelData[2]; + } + break; + case 2: + pChannel->ary_frames = NULL; + pChannel->nFramesInChannel = 0; + + for (j = 0; j < frameCnt; j++) { + MSG_ReadShort(msg); + MSG_ReadShort(msg); + MSG_ReadData(msg, channelData, sizeof(vec4_t)); + } + break; + case 3: + default: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float)); + + pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->ary_frames = pFrame; + pChannel->nFramesInChannel = frameCnt; + + for (j = 0; j < frameCnt; j++) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = MSG_ReadShort(msg); + pFrame->nPrevFrameIndex = MSG_ReadShort(msg); + MSG_ReadData(msg, channelData, sizeof(vec4_t)); + + pFrame->pChannelData[0] = channelData[0]; + } + break; } } @@ -364,6 +494,7 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) { skanChannelHdr *pChannel; skanGameFrame *pFrame; + size_t frameSize; int frameCnt; int i, j; const char *name; @@ -376,35 +507,18 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) type = GetChannelTypeFromName(name); frameCnt = MSG_ReadShort(msg); - pFrame = (skanGameFrame *)Skel_Alloc(frameCnt * sizeof(skanGameFrame)); - pChannel->ary_frames = pFrame; - pChannel->nFramesInChannel = frameCnt; + switch (type) { + // + // 4 channels (Quat) + // + case 0: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); + pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->ary_frames = pFrame; + pChannel->nFramesInChannel = frameCnt; - if (type) { - if (type == 1) { - for (j = 0; j < pChannel->nFramesInChannel; j++) { - pFrame = &pChannel->ary_frames[j]; - pFrame->nFrameNum = MSG_ReadShort(msg); - pFrame->nPrevFrameIndex = MSG_ReadShort(msg); - pFrame->pChannelData[0] = MSG_ReadFloat(msg); - pFrame->pChannelData[1] = MSG_ReadFloat(msg); - pFrame->pChannelData[2] = MSG_ReadFloat(msg); - pFrame->pChannelData[3] = 0; - } - } else if (type == 3) { - for (j = 0; j < pChannel->nFramesInChannel; j++) { - pFrame = &pChannel->ary_frames[j]; - pFrame->nFrameNum = MSG_ReadShort(msg); - pFrame->nPrevFrameIndex = MSG_ReadShort(msg); - pFrame->pChannelData[0] = MSG_ReadFloat(msg); - pFrame->pChannelData[1] = 0; - pFrame->pChannelData[2] = 0; - pFrame->pChannelData[3] = 0; - } - } - } else { for (j = 0; j < pChannel->nFramesInChannel; j++) { - pFrame = &pChannel->ary_frames[j]; + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); pFrame->nFrameNum = MSG_ReadShort(msg); pFrame->nPrevFrameIndex = MSG_ReadShort(msg); pFrame->pChannelData[0] = MSG_ReadFloat(msg); @@ -412,6 +526,41 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->pChannelData[2] = MSG_ReadFloat(msg); pFrame->pChannelData[3] = MSG_ReadFloat(msg); } + break; + // + // 3 channels (Position) + // + case 1: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); + pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->ary_frames = pFrame; + pChannel->nFramesInChannel = frameCnt; + + for (j = 0; j < pChannel->nFramesInChannel; j++) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = MSG_ReadShort(msg); + pFrame->nPrevFrameIndex = MSG_ReadShort(msg); + pFrame->pChannelData[0] = MSG_ReadFloat(msg); + pFrame->pChannelData[1] = MSG_ReadFloat(msg); + pFrame->pChannelData[2] = MSG_ReadFloat(msg); + } + break; + // + // 1 channel (frame) + // + case 3: + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float) * 1); + pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); + pChannel->ary_frames = pFrame; + pChannel->nFramesInChannel = frameCnt; + + for (j = 0; j < pChannel->nFramesInChannel; j++) { + pFrame = (skanGameFrame *)((byte *)pChannel->ary_frames + j * frameSize); + pFrame->nFrameNum = MSG_ReadShort(msg); + pFrame->nPrevFrameIndex = MSG_ReadShort(msg); + pFrame->pChannelData[0] = MSG_ReadFloat(msg); + } + break; } } } @@ -419,8 +568,9 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) skelAnimDataGameHeader_t *skeletor_c::LoadProcessedAnim(const char *path, void *buffer, int len, const char *name) { skelAnimDataGameHeader_t *enAnim; - int i; + int i, j; msg_t msg; + msg_t msgForAnim; int numChannels; skelAnimGameFrame_t *newFrame; @@ -467,15 +617,37 @@ skelAnimDataGameHeader_t *skeletor_c::LoadProcessedAnim(const char *path, void * enAnim->bounds[1][0] = MSG_ReadFloat(&msg); enAnim->bounds[1][1] = MSG_ReadFloat(&msg); enAnim->bounds[1][2] = MSG_ReadFloat(&msg); - ReadEncodedFrames(&msg, enAnim); - numChannels = MSG_ReadLong(&msg); + + enAnim->numFrames = MSG_ReadLong(&msg); + enAnim->nTotalChannels = MSG_ReadShort(&msg); + + msgForAnim = msg; + + for (i = 0; i < enAnim->nTotalChannels; i++) { + int frameCnt = MSG_ReadShort(&msgForAnim); + vec4_t channelData; + + for (j = 0; j < frameCnt; j++) { + MSG_ReadShort(&msgForAnim); + MSG_ReadShort(&msgForAnim); + MSG_ReadData(&msgForAnim, channelData, sizeof(vec4_t)); + } + } + + enAnim->nBytesUsed = MSG_ReadLong(&msgForAnim); + + numChannels = MSG_ReadLong(&msgForAnim); enAnim->channelList.ZeroChannels(); for (i = 0; i < numChannels; i++) { - enAnim->channelList.AddChannel(m_channelNames.RegisterChannel(MSG_ReadString(&msg))); + const char *name = MSG_ReadString(&msgForAnim); + + if (enAnim->channelList.AddChannel(m_channelNames.RegisterChannel(name)) != i) { + Com_Printf("^~^~^ Animation '%s' has duplicate channel '%s'\n", path, name); + } } - enAnim->channelList.PackChannels(); + ReadEncodedFrames(&msg, enAnim); return enAnim; } diff --git a/code/skeletor/skeletorbones.cpp b/code/skeletor/skeletorbones.cpp index 4f454d3a..92ca3a19 100644 --- a/code/skeletor/skeletorbones.cpp +++ b/code/skeletor/skeletorbones.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -163,21 +163,47 @@ void SkeletorLoadBonesFromBuffer(skelChannelList_c *boneList, skelHeaderGame_t * } } -float *DecodeRLEValue(skanChannelHdr *channelFrames, int desiredFrameNum) +float *DecodeRLEPosValue(skanChannelHdr *channelFrames, int desiredFrameNum) { skanGameFrame *foundFrame = channelFrames->ary_frames; + size_t frameSize; int i; + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); + for (i = 0; i < channelFrames->nFramesInChannel; i++) { if (foundFrame->nFrameNum >= desiredFrameNum) { break; } - foundFrame++; + foundFrame = (skanGameFrame *)((byte *)foundFrame + frameSize); } if (foundFrame->nFrameNum > desiredFrameNum) { - foundFrame = &channelFrames->ary_frames[foundFrame->nPrevFrameIndex]; + foundFrame = (skanGameFrame *)((byte *)channelFrames->ary_frames + foundFrame->nPrevFrameIndex * frameSize); + } + + return foundFrame->pChannelData; +} + +float *DecodeRLERotValue(skanChannelHdr *channelFrames, int desiredFrameNum) +{ + skanGameFrame *foundFrame = channelFrames->ary_frames; + size_t frameSize; + int i; + + frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); + + for (i = 0; i < channelFrames->nFramesInChannel; i++) { + if (foundFrame->nFrameNum >= desiredFrameNum) { + break; + } + + foundFrame = (skanGameFrame *)((byte *)foundFrame + frameSize); + } + + if (foundFrame->nFrameNum > desiredFrameNum) { + foundFrame = (skanGameFrame *)((byte *)channelFrames->ary_frames + foundFrame->nPrevFrameIndex * frameSize); } return foundFrame->pChannelData; @@ -214,8 +240,9 @@ SkelQuat skelAnimStoreFrameList_c::GetSlerpValue(int globalChannelNum) const if (incomingWeight == 0.0) { continue; } - pIncomingQuat = - (SkelQuat *)DecodeRLEValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); + pIncomingQuat = (SkelQuat *)DecodeRLERotValue( + &pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame + ); totalWeight += incomingWeight; nTotal++; @@ -263,8 +290,9 @@ SkelQuat skelAnimStoreFrameList_c::GetSlerpValue(int globalChannelNum) const if (incomingWeight == 0.0) { continue; } - pIncomingQuat = - (SkelQuat *)DecodeRLEValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); + pIncomingQuat = (SkelQuat *)DecodeRLERotValue( + &pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame + ); totalWeight += incomingWeight; nTotal++; @@ -358,7 +386,7 @@ void skelAnimStoreFrameList_c::GetLerpValue3(int globalChannelNum, SkelVec3 *out localChannelNum = pFrame->pAnimationData->channelList.GetLocalFromGlobal(globalChannelNum); if (localChannelNum >= 0) { incomingWeight = pFrame->weight; - incomingVec = DecodeRLEValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); + incomingVec = DecodeRLEPosValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); totalWeight += incomingWeight; result[0] += incomingVec[0] * incomingWeight; result[1] += incomingVec[1] * incomingWeight; @@ -389,7 +417,7 @@ void skelAnimStoreFrameList_c::GetLerpValue3(int globalChannelNum, SkelVec3 *out localChannelNum = pFrame->pAnimationData->channelList.GetLocalFromGlobal(globalChannelNum); if (localChannelNum >= 0) { incomingWeight = pFrame->weight; - incomingVec = DecodeRLEValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); + incomingVec = DecodeRLEPosValue(&pFrame->pAnimationData->ary_channels[localChannelNum], pFrame->frame); totalWeight += incomingWeight; result[0] += incomingVec[0] * incomingWeight; result[1] += incomingVec[1] * incomingWeight; From 31ea9513570ce60130b82ec25e3f3516d8332601 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:43:08 +0200 Subject: [PATCH 0378/2040] Fixed SkelMorphGetXyz implementation --- code/renderer/tr_model.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index 6ce0c1db..f478554e 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -966,17 +966,7 @@ SkelMorphGetXyz ============= */ static void SkelMorphGetXyz( skeletorMorph_t *morph, int *morphcache, vec3_t out ) { - out[ 0 ] += morph->offset[ 0 ] * *morphcache + - morph->offset[ 1 ] * *morphcache + - morph->offset[ 2 ] * *morphcache; - - out[ 1 ] += morph->offset[ 0 ] * *morphcache + - morph->offset[ 1 ] * *morphcache + - morph->offset[ 2 ] * *morphcache; - - out[ 2 ] += morph->offset[ 0 ] * *morphcache + - morph->offset[ 1 ] * *morphcache + - morph->offset[ 2 ] * *morphcache; + VectorMA(out, *morphcache, morph->offset, out); } /* From 6bb475abe746e95579ab05af2084513f8260d79c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 5 Jun 2024 20:04:11 +0200 Subject: [PATCH 0379/2040] Fixed PowerPC platform support with proper checks for endianness and ppc64 --- TargetArch.cmake | 8 ++++++-- code/qcommon/q_platform.h | 28 ++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/TargetArch.cmake b/TargetArch.cmake index 933c1646..d51cc015 100644 --- a/TargetArch.cmake +++ b/TargetArch.cmake @@ -3,8 +3,12 @@ set(archdetect_c_code " # error cmake_ARCH x86 #elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) # error cmake_ARCH x86_64 -#elif defined(__ppc64__) || defined(__powerpc64__) -# error cmake_ARCH ppc64 +#elif defined(__PPC64__) || defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) +# if __BIG_ENDIAN__ +# error cmake_ARCH ppc64 +# else +# error cmake_ARCH ppc64el +# endif #elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) # error cmake_ARCH ppc #elif defined __s390__ diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 86d28c81..75208757 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -163,11 +163,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PATH_SEP '/' #ifdef __ppc__ -#define ARCH_STRING "ppc" -#define Q3_BIG_ENDIAN +# define ARCH_STRING "ppc" +# define Q3_BIG_ENDIAN #elif defined __i386__ -#define ARCH_STRING "i386" -#define Q3_LITTLE_ENDIAN +# define ARCH_STRING "i386" +# define Q3_LITTLE_ENDIAN #endif #define DLL_EXT ".dylib" @@ -193,8 +193,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # define ARCH_STRING "x86" #elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) # define ARCH_STRING "x86_64" -#elif defined(__ppc64__) || defined(__powerpc64__) -# define ARCH_STRING "ppc64" +#elif defined(__PPC64__) || defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) +# if __BIG_ENDIAN__ +# define ARCH_STRING "ppc64" +# else +# define ARCH_STRING "ppc64el" +# endif #elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) # define ARCH_STRING "ppc" #elif defined __s390__ @@ -229,10 +233,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # endif #endif -#if __FLOAT_WORD_ORDER == __BIG_ENDIAN -#define Q3_BIG_ENDIAN +#if __BIG_ENDIAN__ +# define Q3_BIG_ENDIAN #else -#define Q3_LITTLE_ENDIAN +# define Q3_LITTLE_ENDIAN #endif #define DLL_EXT ".so" @@ -294,10 +298,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define ARCH_STRING "alpha" #endif -#if BYTE_ORDER == BIG_ENDIAN -#define Q3_BIG_ENDIAN +#if __BIG_ENDIAN__ +# define Q3_BIG_ENDIAN #else -#define Q3_LITTLE_ENDIAN +# define Q3_LITTLE_ENDIAN #endif #define DLL_EXT ".so" From 6250380f61d7c66db9abde20560c922bd8929103 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:13:33 +0200 Subject: [PATCH 0380/2040] Added PowerPC into the build system --- .github/workflows/build-cmake.yml | 11 +++++++---- .github/workflows/publish-release.yml | 5 ++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 0c99c3a1..2628b791 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -20,10 +20,13 @@ jobs: strategy: matrix: architecture: [ - {name: 'amd64', triple: 'x86_64-linux-gnu'}, - {name: 'i686', triple: 'i686-linux-gnu'}, - {name: 'arm64', triple: 'aarch64-linux-gnu'}, - {name: 'armhf', triple: 'arm-linux-gnueabihf'} + {name: 'amd64', triple: 'x86_64-linux-gnu'}, + {name: 'i686', triple: 'i686-linux-gnu'}, + {name: 'arm64', triple: 'aarch64-linux-gnu'}, + {name: 'armhf', triple: 'arm-linux-gnueabihf'}, + {name: 'powerpc', triple: 'powerpc-linux-gnu'}, + {name: 'ppc64', triple: 'powerpc64-linux-gnu'}, + {name: 'ppc64el', triple: 'powerpc64le-linux-gnu'} ] name: "Building for platform linux-${{matrix.architecture.name}}" diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 1ff4bcd0..81b35639 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -25,8 +25,11 @@ jobs: target_os: [ 'linux-amd64', 'linux-i686', - 'linux-aarch64', + 'linux-arm64', 'linux-armhf', + 'linux-powerpc', + 'linux-ppc64', + 'linux-ppc64el', 'windows-x64', 'windows-x86', 'windows-x64-pdb', From 1d887b46551c31c565e0ab96156faca59bd93a12 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:21:35 +0200 Subject: [PATCH 0381/2040] Fixed leaf light being incorrectly reassigned --- code/renderer/tr_sphere_shade.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/code/renderer/tr_sphere_shade.cpp b/code/renderer/tr_sphere_shade.cpp index fb411ada..001b94b2 100644 --- a/code/renderer/tr_sphere_shade.cpp +++ b/code/renderer/tr_sphere_shade.cpp @@ -1368,18 +1368,16 @@ int R_GatherLightSources(const vec3_t vPos, vec3_t *pvLightPos, vec3_t *pvLightI iLightCount = 0; if (s_sun.exists) { - if (leaf) { - if (leaf->lights[0] = &tr.sSunLight) { - VectorMA(vPos, 16384.0, s_sun.direction, vEnd); - ri.CM_BoxTrace(&trace, vPos, vEnd, vec3_origin, vec3_origin, 0, CONTENTS_SOLID, 0); + if (leaf && leaf->lights[0] == &tr.sSunLight) { + VectorMA(vPos, 16384.0, s_sun.direction, vEnd); + ri.CM_BoxTrace(&trace, vPos, vEnd, vec3_origin, vec3_origin, 0, CONTENTS_SOLID, 0); - if (trace.surfaceFlags & SURF_SKY) { - VectorMA(vPos, 16384.0, s_sun.direction, pvLightPos[0]); - pvLightIntensity[0][0] = s_sun.color[0] * (1.0 / 510.0); - pvLightIntensity[0][1] = s_sun.color[1] * (1.0 / 510.0); - pvLightIntensity[0][2] = s_sun.color[2] * (1.0 / 510.0); - iLightCount = 1; - } + if (trace.surfaceFlags & SURF_SKY) { + VectorMA(vPos, 16384.0, s_sun.direction, pvLightPos[0]); + pvLightIntensity[0][0] = s_sun.color[0] * (1.0 / 510.0); + pvLightIntensity[0][1] = s_sun.color[1] * (1.0 / 510.0); + pvLightIntensity[0][2] = s_sun.color[2] * (1.0 / 510.0); + iLightCount = 1; } } } From 5f2827e2abc7796eea1206599d1baf3696aa1b5d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 5 Jun 2024 22:32:36 +0200 Subject: [PATCH 0382/2040] Added hardware requirements --- docs/getting_started_installation.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/getting_started_installation.md b/docs/getting_started_installation.md index 129353eb..5f366f2b 100644 --- a/docs/getting_started_installation.md +++ b/docs/getting_started_installation.md @@ -7,6 +7,17 @@ Ensure that you download the binaries compatible with your platform in the relea - A valid MOH:AA installation - On Windows, Microsoft Visual C++ 2015/2017/2019/2022 Redistributable from https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170 may be required. +## System requirements + +This matches the hardware requirements (x86) of the original game: + +|Hardware|Minimum +|--------|------- +|CPU |450 MHz +|Memory |128MB +|Storage |1.2GB +|GPU |16MB + ## Client a) extract archive to your MOHAA installation directory. From 34ea099d8776840057b4d4d00533bee5bcf72483 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 6 Jun 2024 22:18:23 +0200 Subject: [PATCH 0383/2040] Define _FILE_OFFSET_BITS to 64 due to a bug in readdir() affecting 32-bit architectures readdir() would return NULL, setting errno to EOVERFLOW, unable to load pk3 files --- code/sys/sys_unix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c index 63a29644..42b5f1b5 100644 --- a/code/sys/sys_unix.c +++ b/code/sys/sys_unix.c @@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ +#define _FILE_OFFSET_BITS 64 + #include "../qcommon/q_shared.h" #include "../qcommon/qcommon.h" #include "sys_local.h" From e03b976ffdfd768e896513431dd729d051c004b3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:42:10 +0200 Subject: [PATCH 0384/2040] Added missing header on scriptclass.cpp source file --- code/script/scriptclass.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/code/script/scriptclass.cpp b/code/script/scriptclass.cpp index e76d5aa5..379d1339 100644 --- a/code/script/scriptclass.cpp +++ b/code/script/scriptclass.cpp @@ -1,3 +1,27 @@ +/* +=========================================================================== +Copyright (C) 2024 the OpenMoHAA team + +This file is part of OpenMoHAA source code. + +OpenMoHAA source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +OpenMoHAA source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with OpenMoHAA source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// scriptclass.h: Script class. + #include "scriptclass.h" #include "../fgame/scriptmaster.h" #include "../fgame/scriptthread.h" From 468341b7d078cf0250bf1706cea500dfa66a7f95 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:49:29 +0200 Subject: [PATCH 0385/2040] Explicitly mark as override --- code/fgame/damagemodel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/damagemodel.h b/code/fgame/damagemodel.h index eba9bf65..2190568d 100644 --- a/code/fgame/damagemodel.h +++ b/code/fgame/damagemodel.h @@ -39,7 +39,7 @@ public: void Setup(Event *ev); void Damaged(Event *ev); - void Killed(Event *ev); + void Killed(Event *ev) override; void KillTrace(Event *ev); void SpawnOrientedBoundingBox(Event *ev); void EventSetKillThread(Event *ev); From 18e5c6e714624cf2b28539451b1959be099228ba Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:49:51 +0200 Subject: [PATCH 0386/2040] Use unsigned format specifier to match `MAX_VOTEOPTIONS_BUFFER_LENGTH`'s type --- code/fgame/bg_voteoptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/bg_voteoptions.cpp b/code/fgame/bg_voteoptions.cpp index 0edff416..99f38629 100644 --- a/code/fgame/bg_voteoptions.cpp +++ b/code/fgame/bg_voteoptions.cpp @@ -114,7 +114,7 @@ void VoteOptions::SetupVoteOptions(const char *configFileName, int length, const if (length >= MAX_VOTEOPTIONS_BUFFER_LENGTH) { Com_Error( ERR_DROP, - "VoteOptions: Options file '%s' is too big. Max size is %i bytes\n", + "VoteOptions: Options file '%s' is too big. Max size is %u bytes\n", configFileName, MAX_VOTEOPTIONS_BUFFER_LENGTH ); From 884a76db4c6e0f58ee50a4078693544b0f3ada5d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:55:33 +0200 Subject: [PATCH 0387/2040] Drop error instead of throwing an exception to meet non-throwing exception specification --- code/fgame/scriptthread.cpp | 3 ++- code/script/scriptclass.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index 1f28c78f..4f141b12 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -2286,7 +2286,8 @@ ScriptThread::~ScriptThread() assert(m_ScriptVM); if (!m_ScriptVM) { // should never happen - throw ScriptException("Attempting to delete a dead thread."); + //throw ScriptException("Attempting to delete a dead thread."); + gi.Error(ERR_DROP, "Attempting to delete a dead thread."); } vm = m_ScriptVM; diff --git a/code/script/scriptclass.cpp b/code/script/scriptclass.cpp index 379d1339..3ace7aaf 100644 --- a/code/script/scriptclass.cpp +++ b/code/script/scriptclass.cpp @@ -89,7 +89,8 @@ ScriptClass::ScriptClass() ScriptClass::~ScriptClass() { if (m_Script == NULL) { - throw ScriptException("Attempting to delete dead class."); + //throw ScriptException("Attempting to delete dead class."); + gi.Error(ERR_DROP, "Attempting to delete a dead thread."); } KillThreads(); From db7ae4ffefccfe4d04d2df710abff8b9ac1bf04e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:57:14 +0200 Subject: [PATCH 0388/2040] Properly clear the color values --- code/cgame/cg_lightstyles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/cgame/cg_lightstyles.cpp b/code/cgame/cg_lightstyles.cpp index dfb9e76f..3a280a66 100644 --- a/code/cgame/cg_lightstyles.cpp +++ b/code/cgame/cg_lightstyles.cpp @@ -59,7 +59,7 @@ qboolean CG_LightStyleColor(int style, int realtime, vec4_t color, qboolean clam time = realtime / 50; frac = (realtime - (time * 50.0f)) / 50.0f; - memset(color, 0, sizeof(color)); + VectorClear4(color); if ((style < 0) || (style >= (MAX_LIGHTSTYLES * 2))) { cgi.DPrintf("CG_LightStyleColor: style out of range.\n"); return qtrue; From be222b64a1fb48c8977503af4fbe69cb6fd2f323 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:10:01 +0200 Subject: [PATCH 0389/2040] Fixed one tiny instruction mistake that could cause issues with dynamic lights on terrains --- code/renderer/tr_light.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_light.c b/code/renderer/tr_light.c index 6c8c914d..804f096d 100644 --- a/code/renderer/tr_light.c +++ b/code/renderer/tr_light.c @@ -543,7 +543,7 @@ int R_RealDlightTerrain(cTerraPatchUnpacked_t* srf, int dlightBits) { vec[0] += srf->drawinfo.lmapStep; z01 = srf->heightmap[k]; - vec[2] = srf->z0; z00 + z01; + vec[2] = srf->z0 + z00 + z01; added |= R_DlightSample(src, vec, dst); src += 3; From 50264c496803a3684eed83fdfe7b34bf3d56d6b9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:24:21 +0200 Subject: [PATCH 0390/2040] Make sure to cast the float number to int when using it in the format specifier --- code/qcommon/cm_patch.c | 24 ++++++++++++------------ code/renderer/tr_util.cpp | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/qcommon/cm_patch.c b/code/qcommon/cm_patch.c index b2fa6a99..67175192 100644 --- a/code/qcommon/cm_patch.c +++ b/code/qcommon/cm_patch.c @@ -1139,12 +1139,12 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { pf->planes = NULL; Com_DPrintf( "WARNING: CM_PatchCollideFromGrid: Degenerate patch - no planes (%i %i %i)-(%i %i %i)\n", - pf->bounds[0][0], - pf->bounds[0][1], - pf->bounds[0][2], - pf->bounds[1][0], - pf->bounds[1][1], - pf->bounds[1][2]); + (int)pf->bounds[0][0], + (int)pf->bounds[0][1], + (int)pf->bounds[0][2], + (int)pf->bounds[1][0], + (int)pf->bounds[1][1], + (int)pf->bounds[1][2]); } if (numFacets >= 1) { @@ -1155,12 +1155,12 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { pf->facets = NULL; Com_DPrintf( "WARNING: CM_PatchCollideFromGrid: Degenerate patch - no facets (%i %i %i)-(%i %i %i)\n", - pf->bounds[0][0], - pf->bounds[0][1], - pf->bounds[0][2], - pf->bounds[1][0], - pf->bounds[1][1], - pf->bounds[1][2]); + (int)pf->bounds[0][0], + (int)pf->bounds[0][1], + (int)pf->bounds[0][2], + (int)pf->bounds[1][0], + (int)pf->bounds[1][1], + (int)pf->bounds[1][2]); } } diff --git a/code/renderer/tr_util.cpp b/code/renderer/tr_util.cpp index e79816b8..1ac9589a 100644 --- a/code/renderer/tr_util.cpp +++ b/code/renderer/tr_util.cpp @@ -265,7 +265,7 @@ void R_DrawDebugNumber( const vec3_t org, float number, float scale, float r, fl sprintf(format, "%%.%df", precision); text = va(format, number); } else { - text = va("%d", number); + text = va("%d", (int)number); } // NOTE: this cast here is needed! From 74ccb03e543fdcba0fcb3c174cb738844d4dddca Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:34:13 +0200 Subject: [PATCH 0391/2040] Reduced compilation warnings --- code/cgame/cg_archive.cpp | 4 ++-- code/cgame/cg_drawtools.cpp | 2 +- code/client/cl_inv.cpp | 4 ++-- code/fgame/actor.cpp | 2 +- code/fgame/actor_balcony.cpp | 2 +- code/fgame/actor_curious.cpp | 4 ++-- code/fgame/bg_voteoptions.cpp | 4 ++-- code/fgame/g_local.h | 9 +++------ code/fgame/scriptthread.cpp | 2 +- code/gamespy/sv_gqueryreporting.c | 4 ++-- code/qcommon/msg.cpp | 2 +- code/renderer/tr_image.c | 8 ++++---- code/renderer/tr_init.c | 2 +- code/renderer/tr_main.c | 8 ++++---- code/renderer/tr_marks.c | 2 ++ code/renderer/tr_noise.c | 2 -- code/renderer/tr_sphere_shade.cpp | 2 ++ code/renderer/tr_terrain.c | 2 +- code/server/sv_client.c | 4 ++-- code/uilib/uifield.cpp | 2 +- code/uilib/uihorizscroll.cpp | 2 ++ 21 files changed, 37 insertions(+), 36 deletions(-) diff --git a/code/cgame/cg_archive.cpp b/code/cgame/cg_archive.cpp index 3a1b260e..29fa32c7 100644 --- a/code/cgame/cg_archive.cpp +++ b/code/cgame/cg_archive.cpp @@ -113,7 +113,7 @@ void CG_ArchiveModelHandle(MemArchiver& archiver, qhandle_t* handle) if (tmp.length()) { *handle = cgi.R_RegisterModel(tmp.c_str()); } else { - *handle = NULL; + *handle = (qhandle_t)0; } } else { if (*handle) { @@ -135,7 +135,7 @@ void CG_ArchiveShaderHandle(MemArchiver& archiver, qhandle_t* handle) if (tmp.length()) { *handle = cgi.R_RegisterShader(tmp.c_str()); } else { - *handle = NULL; + *handle = (qhandle_t)0; } } else { if (*handle) { diff --git a/code/cgame/cg_drawtools.cpp b/code/cgame/cg_drawtools.cpp index da1fb632..a416eede 100644 --- a/code/cgame/cg_drawtools.cpp +++ b/code/cgame/cg_drawtools.cpp @@ -1180,7 +1180,7 @@ void CG_DrawCrosshair() float x, y; float width, height; - shader = NULL; + shader = (qhandle_t)0; if (!cg_hud->integer || !ui_crosshair->integer) { return; diff --git a/code/client/cl_inv.cpp b/code/client/cl_inv.cpp index a4c50dd4..850d766d 100644 --- a/code/client/cl_inv.cpp +++ b/code/client/cl_inv.cpp @@ -23,8 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "cl_ui.h" typedef struct { - char *string; - int value; + const char *string; + int value; } equipment_event_table_t; static equipment_event_table_t s_equipTable[] = { diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 997e7798..f74215c2 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -5355,7 +5355,7 @@ void Actor::MovePath(float fMoveSpeed) VectorCopy(m_groundPlaneNormal, mm.groundPlaneNormal); VectorCopy2D(mm.obstacle_normal, m_PrevObstacleNormal); - if (m_WallDir == -1) { + if (m_WallDir == (char)-1) { mm.desired_dir[0] = -mm.obstacle_normal[1]; mm.desired_dir[1] = mm.obstacle_normal[0]; } else { diff --git a/code/fgame/actor_balcony.cpp b/code/fgame/actor_balcony.cpp index 538e6563..ab181089 100644 --- a/code/fgame/actor_balcony.cpp +++ b/code/fgame/actor_balcony.cpp @@ -264,7 +264,7 @@ bool Actor::CalcFallPath(void) loop = currentPos; mm.desired_speed = 0; - mm.groundPlane = NULL; + mm.groundPlane = qfalse; mm.walking = false; VectorSet(mm.velocity, 0, 0, -171); diff --git a/code/fgame/actor_curious.cpp b/code/fgame/actor_curious.cpp index fdaab297..19e51e5d 100644 --- a/code/fgame/actor_curious.cpp +++ b/code/fgame/actor_curious.cpp @@ -246,8 +246,8 @@ void Actor::LookAtCuriosity(void) iSeed = 0x19660D * (m_iCuriousTime - 0x2EB71B09 * ((level.inttime - m_iCuriousTime) & 0xFFFFFF00)) + 0x3C6EF35F; - vAngles[0] = m_DesiredLookAngles[0] + (float)iSeed / 0x4444444 * fLookScale; - vAngles[1] = m_DesiredLookAngles[1] + (float)iSeed / 0x2222222 * fLookScale; + vAngles[0] = m_DesiredLookAngles[0] + (float)iSeed / (float)0x4444444 * fLookScale; + vAngles[1] = m_DesiredLookAngles[1] + (float)iSeed / (float)0x2222222 * fLookScale; vAngles[2] = m_DesiredLookAngles[2]; // clamp vAngles[0] = Q_clamp_float(vAngles[0], -90, 90); diff --git a/code/fgame/bg_voteoptions.cpp b/code/fgame/bg_voteoptions.cpp index 99f38629..7a7ed594 100644 --- a/code/fgame/bg_voteoptions.cpp +++ b/code/fgame/bg_voteoptions.cpp @@ -114,7 +114,7 @@ void VoteOptions::SetupVoteOptions(const char *configFileName, int length, const if (length >= MAX_VOTEOPTIONS_BUFFER_LENGTH) { Com_Error( ERR_DROP, - "VoteOptions: Options file '%s' is too big. Max size is %u bytes\n", + "VoteOptions: Options file '%s' is too big. Max size is %lu bytes\n", configFileName, MAX_VOTEOPTIONS_BUFFER_LENGTH ); @@ -564,7 +564,7 @@ void CG_PushCallVoteSubClient_f(void) if (!strlen(cg.clientinfo[i].name)) { continue; } - + VO_ExecuteCommand( va("globalwidgetcommand voteclientlist additem \"%i: %s\" \"callvote %i %i;popmenu 0\"\n", i, diff --git a/code/fgame/g_local.h b/code/fgame/g_local.h index fcf18650..73c8ad5a 100644 --- a/code/fgame/g_local.h +++ b/code/fgame/g_local.h @@ -22,8 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // // g_local.h -- local definitions for game module -#ifndef __G_LOCAL_H__ -#define __G_LOCAL_H__ +#pragma once #include "q_shared.h" #include "bg_public.h" @@ -417,8 +416,8 @@ void G_RunThink(gentity_t *ent); void QDECL G_LogPrintf(const char *fmt, ...); void SendScoreboardMessageToAllClients(void); void QDECL G_Printf(const char *fmt, ...); -void QDECL G_Error(const char *fmt, ...); -void QDECL G_Error(errorParm_t type, const char *fmt, ...); +void QDECL G_Error(const char *fmt, ...) __attribute__ ((noreturn, format(printf, 1, 2))); +void QDECL G_Error(errorParm_t type, const char *fmt, ...) __attribute__((noreturn, format(printf, 2, 3))); // // g_client.c @@ -530,5 +529,3 @@ extern gentity_t *g_entities; #define FOFS(x) ((size_t) & (((gentity_t *)0)->x)) #include "g_utils.h" - -#endif /* g_local.h */ diff --git a/code/fgame/scriptthread.cpp b/code/fgame/scriptthread.cpp index 4f141b12..62e48659 100644 --- a/code/fgame/scriptthread.cpp +++ b/code/fgame/scriptthread.cpp @@ -4632,7 +4632,7 @@ void ScriptThread::RestoreSound(Event *ev) time = delaytime * 1000.0f; - gi.SendServerCommand(player != NULL ? player->edict - g_entities : NULL, "restoresound %0.2f %f", time, max_vol); + gi.SendServerCommand(player != NULL ? player->edict - g_entities : 0, "restoresound %0.2f %f", time, max_vol); } void ScriptThread::EventHudDraw3d(Event *ev) diff --git a/code/gamespy/sv_gqueryreporting.c b/code/gamespy/sv_gqueryreporting.c index 2e464d4b..4828db27 100644 --- a/code/gamespy/sv_gqueryreporting.c +++ b/code/gamespy/sv_gqueryreporting.c @@ -295,8 +295,8 @@ static void send_echo(qr_t qrec, struct sockaddr *sender, char *outbuf, const ch static void send_final(qr_t qrec, struct sockaddr *sender, char *outbuf, char *validation) { char keyvalue[256]; - char encrypted_val[128]; - char encoded_val[200]; + uchar encrypted_val[128]; + uchar encoded_val[200]; int keylen; if (*validation) { diff --git a/code/qcommon/msg.cpp b/code/qcommon/msg.cpp index 77f4c338..1555aba6 100644 --- a/code/qcommon/msg.cpp +++ b/code/qcommon/msg.cpp @@ -2756,7 +2756,7 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, // su44: trying to find the cause of "unrecognized entity field type" error. // Number of changed fields (lc) should never be larger than total field count.... if(numFields < lc) { - Com_Error( ERR_DROP, "MSG_ReadDeltaEntity: number of changed fields (%i) is higher than total field count (%i)\n", + Com_Error( ERR_DROP, "MSG_ReadDeltaEntity: number of changed fields (%i) is higher than total field count (%zu)\n", lc, numFields); } diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 350e6835..50013d6c 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -947,7 +947,7 @@ image_t* R_CreateImage( if (glCompressMode) { UploadCompressed( - (unsigned*)pic, + (byte*)pic, image->width, image->height, image->numMipmaps, @@ -962,7 +962,7 @@ image_t* R_CreateImage( } else { Upload32( - (unsigned*)pic, + (unsigned int*)pic, image->width, image->height, image->numMipmaps, @@ -1089,7 +1089,7 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height ) } if ( bmpHeader.fileSize != length ) { - ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); + ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%lu vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); } if ( bmpHeader.compression != 0 ) { @@ -1213,7 +1213,7 @@ static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *wid // parse the PCX file // pcx = (pcx_t *)raw; - raw = &pcx->data; + raw = (byte*)pcx->data; xmax = LittleShort(pcx->xmax); ymax = LittleShort(pcx->ymax); diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index 963b302f..3ab56925 100644 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -1275,7 +1275,7 @@ void R_Init( void ) { // Swap_Init(); - if ( (int)tess.xyz & 15 ) { + if ( (size_t)tess.xyz & 15 ) { Com_Printf( "WARNING: tess.xyz not 16 byte aligned\n" ); } Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index a836d705..800ff499 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -1229,8 +1229,8 @@ recurse: that a median-of-three algorithm does not, in general, increase performance. */ - mid = lo + (size / 2) * width; /* find middle element */ - SwapDrawSurf(mid, lo); /* swap it to beginning of array */ + mid = lo + (size / 2) * width; /* find middle element */ + SwapDrawSurf((drawSurf_t*)mid, (drawSurf_t*)lo); /* swap it to beginning of array */ /* We now wish to partition the array into three pieces, one consisiting of elements <= partition element, one of elements @@ -1271,7 +1271,7 @@ recurse: A[loguy] > A[lo], A[higuy] < A[lo], loguy < hi, highy > lo */ - SwapDrawSurf(loguy, higuy); + SwapDrawSurf((drawSurf_t*)loguy, (drawSurf_t*)higuy); /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top of loop is re-established */ @@ -1285,7 +1285,7 @@ recurse: A[i] <= A[lo] for lo <= i <= higuy, A[i] = A[lo] for higuy < i < loguy */ - SwapDrawSurf(lo, higuy); /* put partition element in place */ + SwapDrawSurf((drawSurf_t*)lo, (drawSurf_t*)higuy); /* put partition element in place */ /* OK, now we have the following: A[i] >= A[higuy] for loguy <= i <= hi, diff --git a/code/renderer/tr_marks.c b/code/renderer/tr_marks.c index 0ce4db24..8c15f000 100644 --- a/code/renderer/tr_marks.c +++ b/code/renderer/tr_marks.c @@ -833,6 +833,8 @@ void R_BoxSurfacesForBModel_r(bmodel_t* pBmodel, const vec3_t mins, const vec3_t case SF_GRID: surf->viewCount = tr.viewCount; break; + default: + break; } } else diff --git a/code/renderer/tr_noise.c b/code/renderer/tr_noise.c index 7e172fbe..9789433c 100644 --- a/code/renderer/tr_noise.c +++ b/code/renderer/tr_noise.c @@ -31,8 +31,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static float s_noise_table[NOISE_SIZE]; static int s_noise_perm[NOISE_SIZE]; -#define LERP( a, b, w ) ( a * ( 1.0f - w ) + b * w ) - static float GetNoiseValue( int x, int y, int z, int t ) { int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t ); diff --git a/code/renderer/tr_sphere_shade.cpp b/code/renderer/tr_sphere_shade.cpp index 001b94b2..0a039ef2 100644 --- a/code/renderer/tr_sphere_shade.cpp +++ b/code/renderer/tr_sphere_shade.cpp @@ -250,6 +250,8 @@ static void RB_OptimizeLights() VectorNormalize2(pLight->vOrigin, pLight->vDirection); } break; + default: + break; } } } diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index 2e921216..b22be9dc 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -1185,7 +1185,7 @@ void R_AddTerrainSurfaces() if (ter_count->integer && (g_nSplit || g_nMerge)) { if (ter_count->integer == 1 || g_nSplit * 2 != g_nMerge) { Com_DPrintf( - "%5d tris / %5d verts / %4d splits / %4d merges\n", + "%5zu tris / %5zu verts / %4d splits / %4d merges\n", g_nTris - g_tri.nFree, g_nVerts - g_vert.nFree, g_nSplit, diff --git a/code/server/sv_client.c b/code/server/sv_client.c index 81006431..e262ca9c 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -1519,7 +1519,7 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) { // Since 2.0, displays chat messages // NOTE: this should be handled by fgame, not server // - Com_Printf("%s (%d): %s", cl->name, cl - svs.clients, s); + Com_Printf("%s (%ld): %s", cl->name, cl - svs.clients, s); } if (clientOK) { @@ -1530,7 +1530,7 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) { if (ge->errorMessage) { // if an error has occured while processing the command, halt the server - Com_Error(ERR_DROP, ge->errorMessage); + Com_Error(ERR_DROP, "%s", ge->errorMessage); } } } diff --git a/code/uilib/uifield.cpp b/code/uilib/uifield.cpp index a2a19b3f..952e3f7f 100644 --- a/code/uilib/uifield.cpp +++ b/code/uilib/uifield.cpp @@ -287,7 +287,7 @@ void UIField::CharEvent(int ch) // if the character was inserted at the end of the string, // make sure it remains NULL-terminated if (m_edit.m_cursor == len) { - m_edit.m_buffer[m_edit.m_cursor] = NULL; + m_edit.m_buffer[m_edit.m_cursor] = 0; } if (m_cvarname.length()) { diff --git a/code/uilib/uihorizscroll.cpp b/code/uilib/uihorizscroll.cpp index 54f14b83..14730727 100644 --- a/code/uilib/uihorizscroll.cpp +++ b/code/uilib/uihorizscroll.cpp @@ -161,6 +161,8 @@ void UIHorizScroll::DrawThumb(void) m_local_alpha ); break; + default: + break; } } From ebd885f053ab39cfa93967607c3c2e233629bf63 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:36:55 +0200 Subject: [PATCH 0392/2040] Fixed Subclient not having the correct client name --- code/fgame/bg_voteoptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/bg_voteoptions.cpp b/code/fgame/bg_voteoptions.cpp index 7a7ed594..714eafe0 100644 --- a/code/fgame/bg_voteoptions.cpp +++ b/code/fgame/bg_voteoptions.cpp @@ -568,7 +568,7 @@ void CG_PushCallVoteSubClient_f(void) VO_ExecuteCommand( va("globalwidgetcommand voteclientlist additem \"%i: %s\" \"callvote %i %i;popmenu 0\"\n", i, - cg.clientinfo[i], + cg.clientinfo[i].name, index, i) ); From 0fa380ecfff52fd6e3a783d7d4a85cc1fcc37738 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 22:01:24 +0200 Subject: [PATCH 0393/2040] Correctly read the BSP checksum on big-endian systems --- code/qcommon/cm_load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/qcommon/cm_load.c b/code/qcommon/cm_load.c index 0b11e7b6..b0a38e57 100644 --- a/code/qcommon/cm_load.c +++ b/code/qcommon/cm_load.c @@ -766,7 +766,7 @@ unsigned CM_Checksum( dheader_t *header ) { return LittleLong(Com_BlockChecksum(checksums, 11 * 4)); */ - return header->checksum; + return LittleLong(header->checksum); } /* @@ -883,7 +883,7 @@ void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) { FS_Read( &header, sizeof( dheader_t ), h ); - last_checksum = header.checksum; + last_checksum = LittleLong(header.checksum); *checksum = last_checksum; for (i=0 ; i Date: Fri, 7 Jun 2024 22:08:46 +0200 Subject: [PATCH 0394/2040] Ignore endianness on skd/skb header signature, as it's a string --- code/tiki/tiki_skel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/tiki/tiki_skel.cpp b/code/tiki/tiki_skel.cpp index ebc99e4f..42d20c9f 100644 --- a/code/tiki/tiki_skel.cpp +++ b/code/tiki/tiki_skel.cpp @@ -573,7 +573,7 @@ qboolean TIKI_LoadSKB(const char *path, skelcache_t *cache) memset(cache, 0, sizeof(skelcache_t)); strncpy(cache->path, path, sizeof(cache->path)); - header = LittleLong(pheader->ident); + header = pheader->ident; if (header != TIKI_SKB_HEADER_IDENT) { TIKI_Error("TIKI_LoadSKB: Tried to load '%s' as a skeletal base frame (File has invalid header)\n", path); TIKI_Free(pheader); @@ -842,7 +842,7 @@ qboolean TIKI_LoadSKD(const char *path, skelcache_t *cache) strncpy(cache->path, path, sizeof(cache->path)); // Check the signature - header = LittleLong(pheader->ident); + header = pheader->ident; if (header != TIKI_SKD_HEADER_IDENT) { TIKI_Error("TIKI_LoadSKD: Tried to load '%s' as a skeletal base frame (File has invalid header)\n", path); TIKI_FreeFile(pheader); From e3b9e48d8c9c99fc1cb0496d6b5fe30c56803fac Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 7 Jun 2024 22:38:45 +0200 Subject: [PATCH 0395/2040] Added TIKI_SKEL_LOD_INDEXES --- code/tiki/tiki_shared.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index d3863c6e..f9259d6f 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -55,6 +55,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define TIKI_FRAME_FIRST 0 // exec at first frame #define TIKI_FRAME_MAXFRAMERATE 60 +#define TIKI_SKEL_LOD_INDEXES 10 + // skb skeletor #define TIKI_SKB_HEADER_IDENT (*(int *)"SKL ") #define TIKI_SKB_HEADER_VER_3 3 @@ -71,11 +73,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define TIKI_SKC_HEADER_VERSION 14 // tiki limitations -#define TIKI_MAX_BONES 100 -#define TIKI_MAX_VERTEXES 1000 -#define TIKI_MAX_TRIANGLES 2000 -#define TIKI_MAX_SKELCACHE 1024 -#define TIKI_MAX_COMMANDS 128 +#define TIKI_MAX_BONES 100 +#define TIKI_MAX_VERTEXES 1000 +#define TIKI_MAX_TRIANGLES 2000 +#define TIKI_MAX_SKELCACHE 1024 +#define TIKI_MAX_COMMANDS 128 #define TIKI_MAX_ENTITIES 2048 #define TIKI_MAX_ENTITY_CACHE_PER_ENT 2 @@ -199,7 +201,7 @@ typedef struct { int ofsBones; int ofsSurfaces; int ofsEnd; - int lodIndex[10]; + int lodIndex[TIKI_SKEL_LOD_INDEXES]; int numBoxes; int ofsBoxes; int numMorphTargets; @@ -254,7 +256,7 @@ typedef struct skelHeaderGame_s { int numBones; struct boneData_s *pBones; skelSurfaceGame_t *pSurfaces; - int lodIndex[10]; + int lodIndex[TIKI_SKEL_LOD_INDEXES]; int numBoxes; struct skelHitBox_s *pBoxes; struct lodControl_s *pLOD; From 28ea95b9ffd493d00030a1ca6d6f3fa28b42a6c9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 00:08:54 +0200 Subject: [PATCH 0396/2040] Added scale field --- code/tiki/tiki_shared.h | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index f9259d6f..dc6de490 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -193,19 +193,21 @@ typedef struct dtiki_s { } dtiki_t; typedef struct { - int ident; - int version; - char name[64]; - int numSurfaces; - int numBones; - int ofsBones; - int ofsSurfaces; - int ofsEnd; - int lodIndex[TIKI_SKEL_LOD_INDEXES]; - int numBoxes; - int ofsBoxes; - int numMorphTargets; - int ofsMorphTargets; + int ident; + int version; + char name[64]; + int numSurfaces; + int numBones; + int ofsBones; + int ofsSurfaces; + int ofsEnd; + int lodIndex[TIKI_SKEL_LOD_INDEXES]; + int numBoxes; + int ofsBoxes; + int numMorphTargets; + int ofsMorphTargets; + // Added in 2.0 (SKD version 6) + float scale; } skelHeader_t; typedef struct { From a1e0bc5d7c4ab585be8e379c8f29653b45468577 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 00:40:52 +0200 Subject: [PATCH 0397/2040] Implemented TIKI_SwapSkel (used on Big-Endian systems) --- code/qcommon/tiki_main.cpp | 169 +++++++++++++++++++++++++++++++++++++ code/qcommon/tiki_main.h | 1 + 2 files changed, 170 insertions(+) diff --git a/code/qcommon/tiki_main.cpp b/code/qcommon/tiki_main.cpp index 629866e4..9bf56356 100644 --- a/code/qcommon/tiki_main.cpp +++ b/code/qcommon/tiki_main.cpp @@ -220,3 +220,172 @@ dtikianim_t *TIKI_FillTIKIStructureSkel(dloaddef_t *ld) return TIKI_InitTiki(ld, PAD(animdefsize + defsize, sizeof(void *))); } + +/* +=============== +TIKI_SwapSkel + +Swap the skeleton header on Big-Endian systems +=============== +*/ +void TIKI_SwapSkel(skelHeader_t* pheader) +{ +#ifdef Q3_BIG_ENDIAN + skelSurface_t* pSurf; + int i, j, k; + + //pheader->ident = LittleLong(pheader->ident); + pheader->version = LittleLong(pheader->version); + pheader->numSurfaces = LittleLong(pheader->numSurfaces); + pheader->numBones = LittleLong(pheader->numBones); + pheader->ofsBones = LittleLong(pheader->ofsBones); + pheader->ofsSurfaces = LittleLong(pheader->ofsSurfaces); + pheader->ofsEnd = LittleLong(pheader->ofsEnd); + + if (pheader->version >= TIKI_SKB_HEADER_VERSION) { + for (i = 0; i < TIKI_SKEL_LOD_INDEXES; i++) { + pheader->lodIndex[i] = LittleLong(pheader->lodIndex[i]); + } + + pheader->numBoxes = LittleLong(pheader->numBoxes); + pheader->ofsBoxes = LittleLong(pheader->ofsBoxes); + } + + if (pheader->version >= TIKI_SKD_HEADER_OLD_VERSION) { + pheader->numMorphTargets = LittleLong(pheader->numMorphTargets); + pheader->ofsMorphTargets = LittleLong(pheader->ofsMorphTargets); + } + + if (pheader->version >= TIKI_SKD_HEADER_VERSION) { + pheader->scale = LittleFloat(pheader->scale); + } + + if (pheader->version >= TIKI_SKD_HEADER_OLD_VERSION) { + boneFileData_t* boneBuffer; + + boneBuffer = (boneFileData_t*)((byte*)pheader + pheader->ofsBones); + for (i = 0; i < pheader->numBones; i++) { + boneBuffer->boneType = (boneType_t)LittleLong(boneBuffer->boneType); + boneBuffer->ofsBaseData = LittleLong(boneBuffer->ofsBaseData); + boneBuffer->ofsChannelNames = LittleLong(boneBuffer->ofsChannelNames); + boneBuffer->ofsBoneNames = LittleLong(boneBuffer->ofsBoneNames); + boneBuffer->ofsEnd = LittleLong(boneBuffer->ofsEnd); + + boneBuffer = (boneFileData_t*)((byte*)boneBuffer + boneBuffer->ofsEnd); + } + } else { + skelBoneName_t* TIKI_bones; + + TIKI_bones = (skelBoneName_t*)((byte*)pheader + pheader->ofsBones); + + for (i = 0; i < pheader->numBones; i++) { + TIKI_bones->parent = LittleShort(TIKI_bones->parent); + TIKI_bones->boxIndex = LittleShort(TIKI_bones->boxIndex); + TIKI_bones->flags = LittleLong(TIKI_bones->flags); + + TIKI_bones++; + } + } + + pSurf = (skelSurface_t*)((byte*)pheader + pheader->ofsSurfaces); + for (i = 0; i < pheader->numSurfaces; i++) { + skeletorVertex_t* pVert; + skeletorMorph_t* pMorph; + skelWeight_t* pWeight; + int* pTriangles; + int* pCollapse, * pCollapseIndex; + + pSurf->ident = LittleLong(pSurf->ident); + pSurf->numTriangles = LittleLong(pSurf->numTriangles); + pSurf->numVerts = LittleLong(pSurf->numVerts); + pSurf->staticSurfProcessed = LittleLong(pSurf->staticSurfProcessed); + pSurf->ofsTriangles = LittleLong(pSurf->ofsTriangles); + pSurf->ofsVerts = LittleLong(pSurf->ofsVerts); + pSurf->ofsCollapse = LittleLong(pSurf->ofsCollapse); + pSurf->ofsEnd = LittleLong(pSurf->ofsEnd); + + if (pheader->version >= TIKI_SKB_HEADER_VERSION) { + pSurf->ofsCollapseIndex = LittleLong(pSurf->ofsCollapseIndex); + } + + pTriangles = (int*)((byte*)pSurf + pSurf->ofsTriangles); + for (j = 0; j < pSurf->numTriangles; j++) { + pTriangles[j * 3 + 0] = LittleLong(pTriangles[j * 3 + 0]); + pTriangles[j * 3 + 1] = LittleLong(pTriangles[j * 3 + 1]); + pTriangles[j * 3 + 2] = LittleLong(pTriangles[j * 3 + 2]); + } + + if (pheader->version >= TIKI_SKD_HEADER_OLD_VERSION) { + pVert = (skeletorVertex_t*)((byte*)pSurf + pSurf->ofsVerts); + + for (j = 0; j < pSurf->numVerts; j++) { + pVert->normal[0] = LittleFloat(pVert->normal[0]); + pVert->normal[1] = LittleFloat(pVert->normal[1]); + pVert->normal[2] = LittleFloat(pVert->normal[2]); + pVert->texCoords[0] = LittleFloat(pVert->texCoords[0]); + pVert->texCoords[1] = LittleFloat(pVert->texCoords[1]); + + pVert->numMorphs = LittleLong(pVert->numMorphs); + pMorph = (skeletorMorph_t*)((byte*)pVert + sizeof(*pVert)); + + for (k = 0; k < pVert->numMorphs; k++, pMorph++) { + pMorph->morphIndex = LittleLong(pMorph->morphIndex); + pMorph->offset[0] = LittleFloat(pMorph->offset[0]); + pMorph->offset[1] = LittleFloat(pMorph->offset[1]); + pMorph->offset[2] = LittleFloat(pMorph->offset[2]); + } + + pVert->numWeights = LittleLong(pVert->numWeights); + pWeight = (skelWeight_t*)pMorph; + + for (k = 0; k < pVert->numWeights; k++, pWeight++) { + pWeight->boneIndex = LittleLong(pWeight->boneIndex); + pWeight->boneWeight = LittleFloat(pWeight->boneWeight); + pWeight->offset[0] = LittleFloat(pWeight->offset[0]); + pWeight->offset[1] = LittleFloat(pWeight->offset[1]); + pWeight->offset[2] = LittleFloat(pWeight->offset[2]); + } + + pVert = (skeletorVertex_t*)pWeight; + } + } else { + pVert = (skeletorVertex_t*)((byte*)pSurf + pSurf->ofsVerts); + + for (j = 0; j < pSurf->numVerts; j++) { + pVert->normal[0] = LittleFloat(pVert->normal[0]); + pVert->normal[1] = LittleFloat(pVert->normal[1]); + pVert->normal[2] = LittleFloat(pVert->normal[2]); + pVert->texCoords[0] = LittleFloat(pVert->texCoords[0]); + pVert->texCoords[1] = LittleFloat(pVert->texCoords[1]); + pVert->numWeights = LittleLong(pVert->numWeights); + + pWeight = (skelWeight_t*)((byte*)pVert + sizeof(*pVert)); + + for (k = 0; k < pVert->numWeights; k++, pWeight++) { + pWeight->boneIndex = LittleLong(pWeight->boneIndex); + pWeight->boneWeight = LittleFloat(pWeight->boneWeight); + pWeight->offset[0] = LittleFloat(pWeight->offset[0]); + pWeight->offset[1] = LittleFloat(pWeight->offset[1]); + pWeight->offset[2] = LittleFloat(pWeight->offset[2]); + } + + pVert = (skeletorVertex_t*)pWeight; + } + } + + pCollapse = (int*)((byte*)pSurf + pSurf->ofsCollapse); + for (j = 0; j < pSurf->numVerts; j++) { + pCollapse[j] = LittleLong(pCollapse[j]); + } + + if (pheader->version >= TIKI_SKB_HEADER_VERSION) { + pCollapseIndex = (int*)((byte*)pSurf + pSurf->ofsCollapseIndex); + for (j = 0; j < pSurf->numVerts; j++) { + pCollapseIndex[j] = LittleLong(pCollapseIndex[j]); + } + } + + pSurf = (skelSurface_t*)((byte*)pSurf + pSurf->ofsEnd); + } +#endif +} diff --git a/code/qcommon/tiki_main.h b/code/qcommon/tiki_main.h index b0f63109..7230dad7 100644 --- a/code/qcommon/tiki_main.h +++ b/code/qcommon/tiki_main.h @@ -40,6 +40,7 @@ extern "C" { TIKI_SetupIndividualSurface(const char *filename, dtikisurface_t *surf, const char *name, dloadsurface_t *loadsurf); size_t TIKI_CalcAnimDefSize(dloaddef_t *ld); dtikianim_t *TIKI_FillTIKIStructureSkel(dloaddef_t *ld); + void TIKI_SwapSkel(skelHeader_t* pheader); #ifdef __cplusplus } From e27f2443e843880974bcdb6667b7ab6b3bb74bca Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 00:53:39 +0200 Subject: [PATCH 0398/2040] Fixed skel loading on big-endian systems --- code/tiki/tiki_skel.cpp | 154 ++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 78 deletions(-) diff --git a/code/tiki/tiki_skel.cpp b/code/tiki/tiki_skel.cpp index 42d20c9f..b267117e 100644 --- a/code/tiki/tiki_skel.cpp +++ b/code/tiki/tiki_skel.cpp @@ -156,21 +156,17 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) byte *max_gs_ptr; byte *gs_ptr = NULL; - pSurf = (skelSurface_t *)((byte *)pHeader + LittleLong(pHeader->ofsSurfaces)); + pSurf = (skelSurface_t *)((byte *)pHeader + pHeader->ofsSurfaces); nSurfBytes = 0; - int numSurfaces = 0, version; - CopyLittleLong(&numSurfaces, &pHeader->numSurfaces); - CopyLittleLong(&version, &pHeader->version); - - for (i = 0; i < numSurfaces; i++) { - skeletorVertex_t *pVert = (skeletorVertex_t *)((byte *)pSurf + LittleLongPtr(pSurf->ofsVerts)); - const int numVerts = LittleLongPtr(pSurf->numVerts); + for (i = 0; i < pHeader->numSurfaces; i++) { + skeletorVertex_t *pVert = (skeletorVertex_t *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsVerts)); + const int numVerts = LongNoSwapPtr(&pSurf->numVerts); nVertBytes = 0; for (j = 0; j < numVerts; j++) { - const int numMorphs = LittleLongPtr(pVert->numMorphs); - const int numWeights = LittleLongPtr(pVert->numWeights); + const int numMorphs = LongNoSwapPtr(&pVert->numMorphs); + const int numWeights = LongNoSwapPtr(&pVert->numWeights); int iOffset = sizeof(skeletorMorph_t) * numMorphs; iOffset += sizeof(skelWeight_t) * numWeights; @@ -182,7 +178,7 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) nSurfBytes += sizeof(skelSurfaceGame_t); // triangles - nSurfBytes += LittleLongPtr(pSurf->numTriangles) * sizeof(skelIndex_t) * 3; + nSurfBytes += LongNoSwapPtr(&pSurf->numTriangles) * sizeof(skelIndex_t) * 3; nSurfBytes = PAD(nSurfBytes, sizeof(void *)); // vertices nSurfBytes += nVertBytes; @@ -190,38 +186,36 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) // collapse nSurfBytes += numVerts * sizeof(skelIndex_t); - if (version > TIKI_SKB_HEADER_VER_3) { + if (pHeader->version > TIKI_SKB_HEADER_VER_3) { // collapse indices nSurfBytes += numVerts * sizeof(skelIndex_t); } - pSurf = (skelSurface_t *)((byte *)pSurf + LittleLongPtr(pSurf->ofsEnd)); + pSurf = (skelSurface_t *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsEnd)); } - nBoneBytes = LittleLong(pHeader->numBones) * sizeof(boneData_t); + nBoneBytes = pHeader->numBones * sizeof(boneData_t); nBoxBytes = 0; nMorphBytes = 0; - if (version > TIKI_SKB_HEADER_VERSION) { + if (pHeader->version > TIKI_SKB_HEADER_VERSION) { char *pMorphTargets; intptr_t nLen; - nBoxBytes = LittleLong(pHeader->numBoxes) * sizeof(skelHitBox_t); - const int ofsMorphTargets = LittleLongPtr(pHeader->ofsMorphTargets); - const int numMorphTargets = LittleLongPtr(pHeader->numMorphTargets); - pMorphTargets = (char *)((byte *)pHeader + ofsMorphTargets); + nBoxBytes = pHeader->numBoxes * sizeof(skelHitBox_t); + pMorphTargets = (char *)((byte *)pHeader + pHeader->ofsMorphTargets); - if (ofsMorphTargets > 0 || (ofsMorphTargets + numMorphTargets) < length) { - for (i = 0; i < numMorphTargets; i++) { + if (pHeader->ofsMorphTargets > 0 || (pHeader->ofsMorphTargets + pHeader->numMorphTargets) < length) { + for (i = 0; i < pHeader->numMorphTargets; i++) { nLen = strlen(pMorphTargets) + 1; nMorphBytes += nLen; pMorphTargets += nLen; } } else { - nMorphBytes = numMorphTargets; + nMorphBytes = pHeader->numMorphTargets; } - } else if (version == TIKI_SKB_HEADER_VERSION) { - nBoxBytes = LittleLong(pHeader->numBoxes) * sizeof(skelHitBox_t); + } else if (pHeader->version == TIKI_SKB_HEADER_VERSION) { + nBoxBytes = pHeader->numBoxes * sizeof(skelHitBox_t); } cache->size = sizeof(skelHeaderGame_t); @@ -238,51 +232,51 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) byte *max_ptr = start_ptr + cache->size; byte *ptr = start_ptr + sizeof(skelHeaderGame_t); - pSkel->version = version; - pSkel->numSurfaces = numSurfaces; - pSkel->numBones = LittleLong(pHeader->numBones); + pSkel->version = pHeader->version; + pSkel->numSurfaces = pHeader->numSurfaces; + pSkel->numBones = pHeader->numBones; pSkel->pSurfaces = (skelSurfaceGame_t *)ptr; ptr += nSurfBytes; ptr = (byte *)PADP(ptr, sizeof(void *)); pSkel->pBones = (boneData_t *)ptr; ptr += nBoneBytes; ptr = (byte *)PADP(ptr, sizeof(void *)); - pSkel->numBoxes = LittleLong(pHeader->numBoxes); + pSkel->numBoxes = pHeader->numBoxes; pSkel->pBoxes = (skelHitBox_t *)ptr; ptr += nBoxBytes; ptr = (byte *)PADP(ptr, sizeof(void *)); pSkel->pLOD = NULL; - pSkel->numMorphTargets = LittleLong(pHeader->numMorphTargets); + pSkel->numMorphTargets = pHeader->numMorphTargets; pSkel->pMorphTargets = (char *)ptr; ptr += nMorphBytes; ptr = (byte *)PADP(ptr, sizeof(void *)); memcpy(pSkel->name, pHeader->name, sizeof(pSkel->name)); for (i = 0; i < sizeof(pSkel->lodIndex) / sizeof(pSkel->lodIndex[0]); i++) { - CopyLittleLong(&pSkel->lodIndex[0], &pHeader->lodIndex[0]); + Com_Memcpy(&pSkel->lodIndex[i], &pHeader->lodIndex[i], sizeof(pSkel->lodIndex[i])); } - pSurf = (skelSurface_t *)((byte *)pHeader + LittleLongPtr(pHeader->ofsSurfaces)); + pSurf = (skelSurface_t *)((byte *)pHeader + pHeader->ofsSurfaces); pGameSurf = pSkel->pSurfaces; - for (i = 0; i < numSurfaces; i++) { + for (i = 0; i < pHeader->numSurfaces; i++) { size_t nBytesUsed; skeletorVertex_t *pVert; - const int numTriangles = LittleLongPtr(pSurf->numTriangles); - const int numVerts = LittleLongPtr(pSurf->numVerts); + const int numTriangles = LongNoSwapPtr(&pSurf->numTriangles); + const int numVerts = LongNoSwapPtr(&pSurf->numVerts); nTriBytes = numTriangles * sizeof(skelIndex_t) * 3; nSurfBytes = 0; - if (version > TIKI_SKB_HEADER_VER_3) { + if (pHeader->version > TIKI_SKB_HEADER_VER_3) { nSurfBytes = numVerts * sizeof(skelIndex_t); } - pVert = (skeletorVertex_t *)((byte *)pSurf + LittleLongPtr(pSurf->ofsVerts)); + pVert = (skeletorVertex_t *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsVerts)); nVertBytes = 0; for (j = 0; j < numVerts; j++) { - const int numMorphs = LittleLongPtr(pVert->numMorphs); - const int numWeights = LittleLongPtr(pVert->numWeights); + const int numMorphs = LongNoSwapPtr(&pVert->numMorphs); + const int numWeights = LongNoSwapPtr(&pVert->numWeights); int iOffset = sizeof(skeletorMorph_t) * numMorphs; iOffset += sizeof(skelWeight_t) * numWeights; @@ -303,7 +297,7 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) max_gs_ptr = (byte *)pGameSurf + nBytesUsed; gs_ptr = start_gs_ptr + sizeof(skelSurfaceGame_t); - pGameSurf->ident = LittleLongPtr(pSurf->ident); + pGameSurf->ident = LongNoSwapPtr(&pSurf->ident); pGameSurf->numTriangles = numTriangles; pGameSurf->numVerts = numVerts; pGameSurf->pStaticXyz = NULL; @@ -317,7 +311,7 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) gs_ptr = (byte *)PADP(gs_ptr, sizeof(void *)); pGameSurf->pCollapse = (skelIndex_t *)gs_ptr; gs_ptr += sizeof(*pGameSurf->pCollapse) * numVerts; - if (version > TIKI_SKB_HEADER_VER_3) { + if (pHeader->version > TIKI_SKB_HEADER_VER_3) { pGameSurf->pCollapseIndex = (skelIndex_t*)gs_ptr; gs_ptr += sizeof(*pGameSurf->pCollapseIndex) * numVerts; } @@ -325,9 +319,9 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) memcpy(pGameSurf->name, pSurf->name, sizeof(pGameSurf->name)); if (pGameSurf->numTriangles) { - const int *pTriangles = (const int *)((byte *)pSurf + LittleLongPtr(pSurf->ofsTriangles)); + const int *pTriangles = (const int *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsTriangles)); for (j = 0; j < numTriangles * 3; j++) { - CopyLittleLong(&pGameSurf->pTriangles[j], &pTriangles[j]); + Com_Memcpy(&pGameSurf->pTriangles[j], &pTriangles[j], sizeof(pGameSurf->pTriangles[j])); } } else { pGameSurf->pTriangles = NULL; @@ -335,21 +329,21 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) if (pGameSurf->numVerts) { skeletorVertex_t *skelVert = pGameSurf->pVerts; - pVert = (skeletorVertex_t *)((char *)pSurf + LittleLongPtr(pSurf->ofsVerts)); + pVert = (skeletorVertex_t *)((char *)pSurf + LongNoSwapPtr(&pSurf->ofsVerts)); for (j = 0; j < pGameSurf->numVerts; j++) { - const int numMorphs = LittleLongPtr(pVert->numMorphs); - const int numWeights = LittleLongPtr(pVert->numWeights); + const int numMorphs = LongNoSwapPtr(&pVert->numMorphs); + const int numWeights = LongNoSwapPtr(&pVert->numWeights); int iOffset = sizeof(skeletorMorph_t) * numMorphs; iOffset += sizeof(skelWeight_t) * numWeights; iOffset += sizeof(skeletorVertex_t); - skelVert->normal[0] = LittleFloatPtr(pVert->normal[0]); - skelVert->normal[1] = LittleFloatPtr(pVert->normal[1]); - skelVert->normal[2] = LittleFloatPtr(pVert->normal[2]); - skelVert->texCoords[0] = LittleFloatPtr(pVert->texCoords[0]); - skelVert->texCoords[1] = LittleFloatPtr(pVert->texCoords[1]); + skelVert->normal[0] = FloatNoSwapPtr(&pVert->normal[0]); + skelVert->normal[1] = FloatNoSwapPtr(&pVert->normal[1]); + skelVert->normal[2] = FloatNoSwapPtr(&pVert->normal[2]); + skelVert->texCoords[0] = FloatNoSwapPtr(&pVert->texCoords[0]); + skelVert->texCoords[1] = FloatNoSwapPtr(&pVert->texCoords[1]); skelVert->numWeights = numWeights; skelVert->numMorphs = numMorphs; @@ -357,20 +351,20 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) skeletorMorph_t *pMorph = (skeletorMorph_t *)((byte *)pVert + sizeof(skeletorVertex_t)); skeletorMorph_t *skelMorph = (skeletorMorph_t *)((byte *)skelVert + sizeof(skeletorVertex_t)); for (k = 0; k < numMorphs; k++, pMorph++, skelMorph++) { - skelMorph->morphIndex = LittleLongPtr(pMorph->morphIndex); - skelMorph->offset[0] = LittleFloatPtr(pMorph->offset[0]); - skelMorph->offset[1] = LittleFloatPtr(pMorph->offset[1]); - skelMorph->offset[2] = LittleFloatPtr(pMorph->offset[2]); + skelMorph->morphIndex = LongNoSwapPtr(&pMorph->morphIndex); + skelMorph->offset[0] = FloatNoSwapPtr(&pMorph->offset[0]); + skelMorph->offset[1] = FloatNoSwapPtr(&pMorph->offset[1]); + skelMorph->offset[2] = FloatNoSwapPtr(&pMorph->offset[2]); } skelWeight_t *pWeight = (skelWeight_t *)((byte *)pMorph); skelWeight_t *skelWeight = (skelWeight_t *)((byte *)skelMorph); for (k = 0; k < numWeights; k++, skelWeight++, pWeight++) { - skelWeight->boneIndex = LittleLongPtr(pWeight->boneIndex); - skelWeight->boneWeight = LittleFloatPtr(pWeight->boneWeight); - skelWeight->offset[0] = LittleFloatPtr(pWeight->offset[0]); - skelWeight->offset[1] = LittleFloatPtr(pWeight->offset[1]); - skelWeight->offset[2] = LittleFloatPtr(pWeight->offset[2]); + skelWeight->boneIndex = LongNoSwapPtr(&pWeight->boneIndex); + skelWeight->boneWeight = FloatNoSwapPtr(&pWeight->boneWeight); + skelWeight->offset[0] = FloatNoSwapPtr(&pWeight->offset[0]); + skelWeight->offset[1] = FloatNoSwapPtr(&pWeight->offset[1]); + skelWeight->offset[2] = FloatNoSwapPtr(&pWeight->offset[2]); } pVert = (skeletorVertex_t *)((byte *)pVert + iOffset); @@ -379,15 +373,15 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) assert((byte *)skelVert - (byte *)pGameSurf <= (byte *)pGameSurf->pCollapse - (byte *)pGameSurf); - const int *pCollapse = (const int *)((byte *)pSurf + LittleLongPtr(pSurf->ofsCollapse)); + const int *pCollapse = (const int *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsCollapse)); for (j = 0; j < numVerts; j++) { - pGameSurf->pCollapse[j] = LittleLongPtr(pCollapse[j]); + pGameSurf->pCollapse[j] = LongNoSwapPtr(&pCollapse[j]); } - if (version > TIKI_SKB_HEADER_VER_3) { - const int *pCollapseIndex = (const int *)((byte *)pSurf + LittleLongPtr(pSurf->ofsCollapseIndex)); + if (pHeader->version > TIKI_SKB_HEADER_VER_3) { + const int *pCollapseIndex = (const int *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsCollapseIndex)); for (j = 0; j < numVerts; j++) { - pGameSurf->pCollapseIndex[j] = LittleLongPtr(pCollapseIndex[j]); + pGameSurf->pCollapseIndex[j] = LongNoSwapPtr(&pCollapseIndex[j]); } } else { pGameSurf->pCollapseIndex = NULL; @@ -398,10 +392,10 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) pGameSurf->pCollapseIndex = NULL; } - if (i != numSurfaces - 1) { + if (i != pHeader->numSurfaces - 1) { pGameSurf->pNext = (skelSurfaceGame_t *)gs_ptr; pGameSurf = pGameSurf->pNext; - pSurf = (skelSurface_t *)((byte *)pSurf + LittleLongPtr(pSurf->ofsEnd)); + pSurf = (skelSurface_t *)((byte *)pSurf + LongNoSwapPtr(&pSurf->ofsEnd)); } } @@ -410,8 +404,8 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) assert(((byte *)pGameSurf - (byte *)pSkel) <= cache->size); if (nBoneBytes) { - if (version <= TIKI_SKB_HEADER_VERSION) { - skelBoneName_t *TIKI_bones = (skelBoneName_t *)((byte *)pHeader + LittleLongPtr(pHeader->ofsBones)); + if (pHeader->version <= TIKI_SKB_HEADER_VERSION) { + skelBoneName_t *TIKI_bones = (skelBoneName_t *)((byte *)pHeader + LongNoSwapPtr(&pHeader->ofsBones)); for (i = 0; i < pSkel->numBones; i++) { const char *boneName; @@ -425,10 +419,10 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) TIKI_bones++; } } else { - boneFileData_t *boneBuffer = (boneFileData_t *)((byte *)pHeader + LittleLongPtr(pHeader->ofsBones)); + boneFileData_t *boneBuffer = (boneFileData_t *)((byte *)pHeader + LongNoSwapPtr(&pHeader->ofsBones)); for (i = 0; i < pSkel->numBones; i++) { LoadBoneFromBuffer2(boneBuffer, &pSkel->pBones[i]); - boneBuffer = (boneFileData_t *)((byte *)boneBuffer + LittleLongPtr(boneBuffer->ofsEnd)); + boneBuffer = (boneFileData_t *)((byte *)boneBuffer + LongNoSwapPtr(&boneBuffer->ofsEnd)); } } } else { @@ -436,7 +430,7 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) pSkel->pBones = NULL; } - if (version <= TIKI_SKB_HEADER_VER_3) { + if (pHeader->version <= TIKI_SKB_HEADER_VER_3) { pSkel->numBoxes = 0; pSkel->pBoxes = NULL; pSkel->numMorphTargets = 0; @@ -445,7 +439,7 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) } if (nBoxBytes) { - const int ofsBoxes = LittleLongPtr(pHeader->ofsBoxes); + const int ofsBoxes = LongNoSwapPtr(&pHeader->ofsBoxes); if (ofsBoxes <= 0 || (nBoxBytes + ofsBoxes) >= length) { Com_Printf("^~^~^ Box data is corrupted for '%s'\n", cache->path); @@ -459,14 +453,14 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) pSkel->pBoxes = NULL; } - if (version <= TIKI_SKB_HEADER_VERSION) { + if (pHeader->version <= TIKI_SKB_HEADER_VERSION) { pSkel->numMorphTargets = 0; pSkel->pMorphTargets = NULL; return; } if (nMorphBytes) { - const int ofsMorphTargets = LittleLongPtr(pHeader->ofsBoxes); + const int ofsMorphTargets = LongNoSwapPtr(&pHeader->ofsBoxes); if (ofsMorphTargets <= 0 || (nMorphBytes + ofsMorphTargets) >= length) { Com_Printf("^~^~^ Morph targets data is corrupted for '%s'\n", cache->path); @@ -656,7 +650,7 @@ qboolean TIKI_LoadSKB(const char *path, skelcache_t *cache) newSurf->ofsCollapse += sizeof(unsigned int) * newSurf->numVerts; } if (newSurf->ofsCollapseIndex > newSurf->ofsVerts) { - newSurf->ofsCollapse += sizeof(unsigned int) * newSurf->numVerts; + newSurf->ofsCollapseIndex += sizeof(unsigned int) * newSurf->numVerts; } if (newSurf->ofsTriangles > newSurf->ofsVerts) { newSurf->ofsTriangles += sizeof(unsigned int) * newSurf->numVerts; @@ -832,7 +826,7 @@ qboolean TIKI_LoadSKD(const char *path, skelcache_t *cache) } // The SKD must have at least one surface - if (pheader->numSurfaces <= 0) { + if (LittleLong(pheader->numSurfaces) <= 0) { TIKI_Error("^~^~^ TIKI_LoadSKD: %s has no surfaces\n", path); TIKI_FreeFile(pheader); return qfalse; @@ -857,12 +851,15 @@ qboolean TIKI_LoadSKD(const char *path, skelcache_t *cache) return qfalse; } + TIKI_SwapSkel(pheader); + surf = (skelSurface_t *)((byte *)pheader + pheader->ofsSurfaces); for (i = 0; i < pheader->numSurfaces; i++) { if (surf->numVerts > TIKI_MAX_VERTEXES) { TIKI_Error( - "TIKI_LoadSKD: %s has more than %i verts on a surface (%i)", path, TIKI_MAX_VERTEXES, surf->numVerts + "TIKI_LoadSKD: %s has more than %i verts on a surface (%i)", path, TIKI_MAX_VERTEXES, + surf->numVerts ); TIKI_FreeFile(pheader); return qfalse; @@ -896,7 +893,8 @@ qboolean TIKI_LoadSKD(const char *path, skelcache_t *cache) // Get the lod file associated with the skeleton GetLODFile(cache); TIKI_SortLOD(cache->skel); - return 1; + + return true; } /* From b54db17069d9f5f9dcbe323be63e22083d758294 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:03:08 +0200 Subject: [PATCH 0399/2040] Added unsigned swaps --- code/qcommon/q_platform.h | 7 +++++++ code/qcommon/q_shared.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 75208757..25feb84c 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -392,7 +392,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA void CopyShortSwap(void* dest, const void* src); void CopyLongSwap(void* dest, const void* src); short ShortSwap(short l); +unsigned short UnsignedShortSwap(unsigned short l); int LongSwap(int l); +unsigned int UnsignedLongSwap(unsigned int l); float FloatSwap(const float* f); short ShortSwapPtr(const void* l); int LongSwapPtr(const void* l); @@ -413,7 +415,9 @@ float FloatNoSwapPtr(const void* l); // #define LittleShort(x) ShortSwap(x) +#define LittleUnsignedShort(x) UnsignedShortSwap(x) #define LittleLong(x) LongSwap(x) +#define LittleUnsignedLong(x) UnsignedLongSwap(x) #define LittleFloat(x) FloatSwap(&x) #define LittleShortPtr(x) ShortSwapPtr(&x) #define LittleLongPtr(x) LongSwapPtr(&x) @@ -431,6 +435,7 @@ float FloatNoSwapPtr(const void* l); #define CopyLittleLong(dest, src) Com_Memcpy(dest, src, 4) #define LittleShort +#define LittleUnsignedShort #define LittleLong #define LittleFloat #define LittleShortPtr(x) ShortNoSwapPtr(&x) @@ -438,7 +443,9 @@ float FloatNoSwapPtr(const void* l); #define LittleFloatPtr(x) FloatNoSwapPtr(&x) #define BigShort(x) ShortSwap(x) +#define BigUnsignedShort(x) UnsignedShortSwap(x) #define BigLong(x) LongSwap(x) +#define BigUnsignedLong(x) UnsignedLongSwap(x) #define BigFloat(x) FloatSwap(&x) #define BigShortPtr(x) ShortSwapPtr(&x) #define BigLongPtr(x) LongSwapPtr(&x) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 293e1afc..164284f2 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -1502,11 +1502,26 @@ short ShortSwap(short l) return (b1 << 8) + b2; } +unsigned short UnsignedShortSwap(unsigned short l) +{ + byte b1, b2; + + b1 = l & 255; + b2 = (l >> 8) & 255; + + return (b1 << 8) + b2; +} + short ShortNoSwap(short l) { return l; } +unsigned short UnsignedShortNoSwap(unsigned short l) +{ + return l; +} + int LongSwap(int l) { byte b1, b2, b3, b4; @@ -1519,11 +1534,28 @@ int LongSwap(int l) return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4; } +unsigned int UnsignedLongSwap(unsigned int l) +{ + byte b1, b2, b3, b4; + + b1 = l & 255; + b2 = (l >> 8) & 255; + b3 = (l >> 16) & 255; + b4 = (l >> 24) & 255; + + return ((unsigned int)b1 << 24) + ((unsigned int)b2 << 16) + ((unsigned int)b3 << 8) + b4; +} + int LongNoSwap(int l) { return l; } +unsigned int UnsignedLongNoSwap(unsigned int l) +{ + return l; +} + qint64 Long64Swap(qint64 ll) { qint64 result; From 819dffcb869a43de5d47a5f00e9c94ead296b355 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:05:47 +0200 Subject: [PATCH 0400/2040] Added MAX_TERRAIN_VARNODES --- code/qcommon/qfiles.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index 405f0108..c367ab00 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -424,6 +424,8 @@ typedef struct fcm_s { int iHeight; } fcm_t; +#define MAX_TERRAIN_VARNODES 63 + typedef struct varnode_s { unsigned short flags; } varnode_t; @@ -448,7 +450,7 @@ typedef struct cTerraPatch_s { short iSouth; short iWest; - varnode_t varTree[ 2 ][ 63 ]; + varnode_t varTree[2][MAX_TERRAIN_VARNODES]; unsigned char heightmap[ 9 * 9 ]; } cTerraPatch_t; From 6796a8b3fe61b27715e3aca9ff843f4cbb1b340b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:08:58 +0200 Subject: [PATCH 0401/2040] Properly swap terrain patch values on big-endian systems --- code/qcommon/cm_load.c | 1 + code/qcommon/cm_terrain.c | 34 ++++++++++++++++++++++++++++++++++ code/qcommon/cm_terrain.h | 1 + 3 files changed, 36 insertions(+) diff --git a/code/qcommon/cm_load.c b/code/qcommon/cm_load.c index b0a38e57..5c8e0578 100644 --- a/code/qcommon/cm_load.c +++ b/code/qcommon/cm_load.c @@ -709,6 +709,7 @@ void CMod_LoadTerrain( gamelump_t *lump ) { CM_PrepareGenerateTerrainCollide(); for( i = 0; i < numTerraPatches; i++ ) { + CM_SwapTerraPatch(&terraPatches[i]); // Generate collision CM_GenerateTerrainCollide( &terraPatches[ i ], &cm.terrain[ i ].tc ); cm.terrain[ i ].contents = cm.shaders[ terraPatches[ i ].iShader ].contentFlags; diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 82dee2ed..168766c0 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -1481,3 +1481,37 @@ int CM_TerrainSquareType(int iTerrainPatch, int i, int j) { return cm.terrain[iTerrainPatch].tc.squares[i][j].eMode; } + +/* +==================== +CM_SwapTerraPatch + +Swaps the patch on big-endian +==================== +*/ +void CM_SwapTerraPatch(cTerraPatch_t* pPatch) { +#ifdef Q3_BIG_ENDIAN + int i; + + pPatch->texCoord[0][0][0] = LittleFloat(pPatch->texCoord[0][0][0]); + pPatch->texCoord[0][0][1] = LittleFloat(pPatch->texCoord[0][0][1]); + pPatch->texCoord[0][1][0] = LittleFloat(pPatch->texCoord[0][1][0]); + pPatch->texCoord[0][1][1] = LittleFloat(pPatch->texCoord[0][1][1]); + pPatch->texCoord[1][0][0] = LittleFloat(pPatch->texCoord[1][0][0]); + pPatch->texCoord[1][0][1] = LittleFloat(pPatch->texCoord[1][0][1]); + pPatch->texCoord[1][1][0] = LittleFloat(pPatch->texCoord[1][1][0]); + pPatch->texCoord[1][1][1] = LittleFloat(pPatch->texCoord[1][1][1]); + pPatch->iBaseHeight = LittleShort(pPatch->iBaseHeight); + pPatch->iShader = LittleUnsignedShort(pPatch->iShader); + pPatch->iLightMap = LittleUnsignedShort(pPatch->iLightMap); + pPatch->iNorth = LittleShort(pPatch->iNorth); + pPatch->iEast = LittleShort(pPatch->iEast); + pPatch->iSouth = LittleShort(pPatch->iSouth); + pPatch->iWest = LittleShort(pPatch->iWest); + + for (i = 0; i < MAX_TERRAIN_VARNODES; i++) { + pPatch->varTree[0][i].flags = LittleUnsignedShort(pPatch->varTree[0][i].flags); + pPatch->varTree[1][i].flags = LittleUnsignedShort(pPatch->varTree[1][i].flags); + } +#endif +} diff --git a/code/qcommon/cm_terrain.h b/code/qcommon/cm_terrain.h index 7d2e7df0..f29597bc 100644 --- a/code/qcommon/cm_terrain.h +++ b/code/qcommon/cm_terrain.h @@ -64,6 +64,7 @@ extern "C" { void CM_PrepareGenerateTerrainCollide(void); void CM_GenerateTerrainCollide(cTerraPatch_t *patch, terrainCollide_t *tc); int CM_TerrainSquareType(int iTerrainPatch, int i, int j); + void CM_SwapTerraPatch(cTerraPatch_t* pPatch); #ifdef __cplusplus } From a5535fa78963f3dade5c0517d81a3825269fb4bd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:40:36 +0200 Subject: [PATCH 0402/2040] Make sure to initialize the widget's command handler to NULL. This should fix #305 --- code/uilib/uiwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/uilib/uiwidget.cpp b/code/uilib/uiwidget.cpp index 39151320..3f0dca85 100644 --- a/code/uilib/uiwidget.cpp +++ b/code/uilib/uiwidget.cpp @@ -679,6 +679,7 @@ UIWidget::UIWidget() m_visible = true; m_enabled = true; m_canactivate = false; + m_commandhandler = NULL; m_font = NULL; m_material = NULL; m_hovermaterial = NULL; From 41244095b1fb204439745a3aeca5a4b8c3c18dac Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:47:18 +0200 Subject: [PATCH 0403/2040] CMod_LoadTerrainIndexes: big-endian compatibility --- code/qcommon/cm_load.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/cm_load.c b/code/qcommon/cm_load.c index 5c8e0578..d3ef6509 100644 --- a/code/qcommon/cm_load.c +++ b/code/qcommon/cm_load.c @@ -744,7 +744,7 @@ void CMod_LoadTerrainIndexes( gamelump_t *lump ) { for( i = 0; i < cm.numLeafTerrains; i++, in++ ) { - cm.leafterrains[ i ] = &cm.terrain[ *in ]; + cm.leafterrains[ i ] = &cm.terrain[ LittleShort( *in ) ]; } } From 28c6e3b3982540de1c92630eb87986da581b5fa1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:48:30 +0200 Subject: [PATCH 0404/2040] Properly swap terrain patches for rendering on big-endian architectures --- code/renderer/tr_bsp.c | 3 ++- code/renderer/tr_local.h | 1 + code/renderer/tr_terrain.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 15541cdd..3d42dd44 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -566,6 +566,7 @@ void R_LoadTerrain(gamelump_t* lump) { out = s_worldData.terraPatches; for (i = 0; i < s_worldData.numTerraPatches; in++, out++, i++) { + R_SwapTerraPatch(in); R_UnpackTerraPatch(in, out); } } @@ -597,7 +598,7 @@ void R_LoadTerrainIndexes(gamelump_t* lump) { out = s_worldData.visTerraPatches; for (i = 0; i < s_worldData.numVisTerraPatches; in++, out++, i++) { - *out = &s_worldData.terraPatches[*in]; + *out = &s_worldData.terraPatches[LittleShort(*in)]; } } diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 0f027be2..c2bfa15e 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -2146,6 +2146,7 @@ void R_AddTerrainMarkSurfaces(); void R_InitTerrain(); void R_TerrainPrepareFrame(); qboolean R_TerrainHeightForPoly(cTerraPatchUnpacked_t* pPatch, polyVert_t* pVerts, int nVerts); +void R_SwapTerraPatch(cTerraPatch_t* pPatch); /* ============================================================= diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index b22be9dc..e870b85e 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -1395,3 +1395,37 @@ void R_InitTerrain() g_fDistanceTable[i] = 443.5 / sqrt(1.0 - dot); } } + +/* +==================== +R_SwapTerraPatch + +Swaps the patch on big-endian +==================== +*/ +void R_SwapTerraPatch(cTerraPatch_t* pPatch) { +#ifdef Q3_BIG_ENDIAN + int i; + + pPatch->texCoord[0][0][0] = LittleFloat(pPatch->texCoord[0][0][0]); + pPatch->texCoord[0][0][1] = LittleFloat(pPatch->texCoord[0][0][1]); + pPatch->texCoord[0][1][0] = LittleFloat(pPatch->texCoord[0][1][0]); + pPatch->texCoord[0][1][1] = LittleFloat(pPatch->texCoord[0][1][1]); + pPatch->texCoord[1][0][0] = LittleFloat(pPatch->texCoord[1][0][0]); + pPatch->texCoord[1][0][1] = LittleFloat(pPatch->texCoord[1][0][1]); + pPatch->texCoord[1][1][0] = LittleFloat(pPatch->texCoord[1][1][0]); + pPatch->texCoord[1][1][1] = LittleFloat(pPatch->texCoord[1][1][1]); + pPatch->iBaseHeight = LittleShort(pPatch->iBaseHeight); + pPatch->iShader = LittleUnsignedShort(pPatch->iShader); + pPatch->iLightMap = LittleUnsignedShort(pPatch->iLightMap); + pPatch->iNorth = LittleShort(pPatch->iNorth); + pPatch->iEast = LittleShort(pPatch->iEast); + pPatch->iSouth = LittleShort(pPatch->iSouth); + pPatch->iWest = LittleShort(pPatch->iWest); + + for (i = 0; i < MAX_TERRAIN_VARNODES; i++) { + pPatch->varTree[0][i].flags = LittleUnsignedShort(pPatch->varTree[0][i].flags); + pPatch->varTree[1][i].flags = LittleUnsignedShort(pPatch->varTree[1][i].flags); + } +#endif +} From 5155c101362e8a6dcfc5480f442b00fb4684cd17 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:40:35 +0200 Subject: [PATCH 0405/2040] Fixed scripts not working on big-endian architectures --- code/script/scriptcompiler.cpp | 47 +++++++++++++++++++--------------- code/script/scriptcompiler.h | 3 +++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index 17dfcf18..f3fdcf3c 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -146,7 +146,7 @@ void ScriptCompiler::AddJumpBackLocation(unsigned char *pos) { int offset = (code_pos - pos); - EmitOpcodeValue(offset, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)offset, sizeof(unsigned int)); ClearPrevOpcode(); } @@ -154,7 +154,7 @@ void ScriptCompiler::AddJumpToLocation(unsigned char *pos) { int offset = (pos - code_pos - 1); - EmitOpcodeValue(offset, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)offset, sizeof(unsigned int)); ClearPrevOpcode(); } @@ -280,7 +280,7 @@ void ScriptCompiler::EmitAssignmentStatement(sval_t lhs, unsigned int sourcePos) EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].byteValue, sourcePos); } - EmitOpcodeValue(index, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } void ScriptCompiler::EmitBoolJumpFalse(unsigned int sourcePos) @@ -394,7 +394,7 @@ void ScriptCompiler::EmitConstArrayOpcode(int iCount) SetOpcodeVarStackOffset(OP_LOAD_CONST_ARRAY1, 1 - iCount); EmitOpcode(OP_LOAD_CONST_ARRAY1, -1); - EmitOpcodeValue(iCount, sizeof(short)); + EmitOpcodeValue((short)iCount, sizeof(short)); } void ScriptCompiler::EmitContinue(unsigned int sourcePos) @@ -507,10 +507,10 @@ void ScriptCompiler::EmitField(sval_t listener_val, sval_t field_val, unsigned i || (eventnum && BuiltinReadVariable(sourcePos, listener_val.node[1].byteValue, eventnum))) { EmitValue(listener_val); EmitOpcode(OP_STORE_FIELD, sourcePos); - EmitOpcodeValue(index, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } else if (PrevOpcode() != (OP_LOAD_GAME_VAR + listener_val.node[1].byteValue) || prev_index != index) { EmitOpcode(OP_STORE_GAME_VAR + listener_val.node[1].byteValue, sourcePos); - EmitOpcodeValue(index, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } else { AbsorbPrevOpcode(); EmitOpcode(OP_LOAD_STORE_GAME_VAR + listener_val.node[1].byteValue, sourcePos); @@ -645,16 +645,16 @@ void ScriptCompiler::EmitInteger(unsigned int value, unsigned int sourcePos) EmitOpcode(OP_STORE_INT0, sourcePos); } else if (value < 127) { EmitOpcode(OP_STORE_INT1, sourcePos); - EmitOpcodeValue(value, sizeof(byte)); + EmitOpcodeValue((byte)value, sizeof(byte)); } else if (value < 32767) { EmitOpcode(OP_STORE_INT2, sourcePos); - EmitOpcodeValue(value, sizeof(short)); + EmitOpcodeValue((short)value, sizeof(short)); } else if (value < 8388607) { EmitOpcode(OP_STORE_INT3, sourcePos); - EmitOpcodeValue(value, sizeof(short3)); + EmitOpcodeValue((short3)value, sizeof(short3)); } else { EmitOpcode(OP_STORE_INT4, sourcePos); - EmitOpcodeValue(value, sizeof(int)); + EmitOpcodeValue((int)value, sizeof(int)); } } @@ -799,12 +799,12 @@ void ScriptCompiler::EmitMethodExpression(int iParamCount, int eventnum, unsigne SetOpcodeVarStackOffset(OP_EXEC_METHOD_COUNT1, -iParamCount); EmitOpcode(OP_EXEC_METHOD_COUNT1, sourcePos); - EmitOpcodeValue(iParamCount, sizeof(byte)); + EmitOpcodeValue((byte)iParamCount, sizeof(byte)); } else { EmitOpcode(OP_EXEC_METHOD0 + iParamCount, sourcePos); } - EmitOpcodeValue(eventnum, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)eventnum, sizeof(unsigned int)); } void ScriptCompiler::EmitNil(unsigned int sourcePos) @@ -907,7 +907,7 @@ void ScriptCompiler::EmitOpcode(int opcode, unsigned int sourcePos) prev_opcodes[prev_opcode_pos].VarStackOffset = iVarStackOffset; prev_opcodes[(prev_opcode_pos + 1) % 100].opcode = OP_PREVIOUS; - EmitOpcodeValue(opcode, sizeof(byte)); + EmitOpcodeValue((byte)opcode, sizeof(byte)); } void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) @@ -933,7 +933,7 @@ void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].byteValue, sourcePos); unsigned int index = Director.AddString(name); - EmitOpcodeValue(index, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } } @@ -979,7 +979,7 @@ void ScriptCompiler::EmitRef(sval_t val, unsigned int sourcePos) EmitValue(val.node[1]); EmitOpcode(OP_STORE_FIELD_REF, sourcePos); - EmitOpcodeValue(index, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } void ScriptCompiler::EmitStatementList(sval_t val) @@ -1000,7 +1000,7 @@ void ScriptCompiler::EmitString(str value, unsigned int sourcePos) } EmitOpcode(OP_STORE_STRING, sourcePos); - EmitOpcodeValue(index, sizeof(unsigned int)); + EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } void ScriptCompiler::EmitSwitch(sval_t val, unsigned int sourcePos) @@ -1130,12 +1130,12 @@ __emit: SetOpcodeVarStackOffset(OP_EXEC_CMD_COUNT1, -(int32_t)iParamCount); EmitOpcode(OP_EXEC_CMD_COUNT1, val.node[3].sourcePosValue); - EmitOpcodeValue(iParamCount, sizeof(byte)); + EmitOpcodeValue((byte)iParamCount, sizeof(byte)); } else { EmitOpcode(OP_EXEC_CMD0 + iParamCount, val.node[3].sourcePosValue); } - EmitOpcodeValue((op_ev_t)eventnum, sizeof(unsigned int)); + EmitOpcodeValue((op_ev_t)eventnum, sizeof(op_ev_t)); break; } @@ -1170,12 +1170,12 @@ __emit: SetOpcodeVarStackOffset(OP_EXEC_CMD_COUNT1, -(int32_t)iParamCount); EmitOpcode(OP_EXEC_CMD_METHOD_COUNT1, val.node[4].sourcePosValue); - EmitOpcodeValue(iParamCount, sizeof(byte)); + EmitOpcodeValue((byte)iParamCount, sizeof(byte)); } else { EmitOpcode(OP_EXEC_CMD_METHOD0 + iParamCount, val.node[4].sourcePosValue); } - EmitOpcodeValue(eventnum, sizeof(unsigned int)); + EmitOpcodeValue((op_ev_t)eventnum, sizeof(op_ev_t)); break; } @@ -1626,6 +1626,13 @@ void ScriptCompiler::EmitOpcodeValue(const Value& value, size_t size) code_pos += size; } +template +void ScriptCompiler::EmitOpcodeValue(const Value& value) +{ + Com_Memcpy(code_pos, &value, sizeof(value)); + code_pos += sizeof(value); +} + template void ScriptCompiler::EmitAt(unsigned char *location, const Value& value, size_t size) { diff --git a/code/script/scriptcompiler.h b/code/script/scriptcompiler.h index 34c53dcc..81e85be2 100644 --- a/code/script/scriptcompiler.h +++ b/code/script/scriptcompiler.h @@ -160,6 +160,9 @@ private: template void EmitOpcodeValue(const Value& value, size_t size); + template + void EmitOpcodeValue(const Value& value); + template void EmitAt(unsigned char *location, const Value& value, size_t size); From c1604c0c8cd75c335f89233d918571fb183ec247 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:59:52 +0200 Subject: [PATCH 0406/2040] Handle animation file endianness --- code/tiki/tiki_files.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index f50421ba..8ebe3ca0 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -565,6 +565,21 @@ skelAnimDataGameHeader_t *SkeletorCacheFileCallback(const char *path) if (version == TIKI_SKC_HEADER_OLD_VERSION) { Com_Printf("WARNING- DOWNGRADING TO OLD ANIMATION FORMAT FOR FILE: %s\n", path); + + // + // Handle the endianness + // + pHeader->flags = LittleLong(pHeader->flags); + pHeader->nBytesUsed = LittleLong(pHeader->nBytesUsed); + pHeader->frameTime = LittleFloat(pHeader->frameTime); + pHeader->totalDelta.x = LittleFloat(pHeader->totalDelta.x); + pHeader->totalDelta.y = LittleFloat(pHeader->totalDelta.y); + pHeader->totalDelta.z = LittleFloat(pHeader->totalDelta.z); + pHeader->totalAngleDelta = LittleFloat(pHeader->totalAngleDelta); + pHeader->numChannels = LittleLong(pHeader->numChannels); + pHeader->ofsChannelNames = LittleLong(pHeader->ofsChannelNames); + pHeader->numFrames = LittleLong(pHeader->numFrames); + finishedHeader = skeletor_c::ConvertSkelFileToGame(pHeader, iBuffLength, path); if (convertAnims && convertAnims->integer) { skeletor_c::SaveProcessedAnim(finishedHeader, path, pHeader); From 005afcd53d094d409ee67c3f0d276421b34987c1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 15:05:10 +0200 Subject: [PATCH 0407/2040] Simplified `CM_PickTerrainSquareMode` --- code/qcommon/cm_terrain.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/code/qcommon/cm_terrain.c b/code/qcommon/cm_terrain.c index 168766c0..8893481d 100644 --- a/code/qcommon/cm_terrain.c +++ b/code/qcommon/cm_terrain.c @@ -200,15 +200,25 @@ void CM_PickTerrainSquareMode(terrainCollideSquare_t *square, vec3_t vTest, int int flags0, flags1; varnodeIndex_t *vni; - vni = &g_vni[(patch->flags & 0x80) ? 1 : 0][i][j][0]; + if (patch->flags & 0x80) { + vni = g_vni[1][i][j]; + } else { + vni = g_vni[0][i][j]; + } - flags0 = - ((unsigned short)(patch->varTree[vni->iTreeAndMask & 1][vni->iNode].flags & 0xFFFE & vni->iTreeAndMask) != 0); - flags1 = - ((unsigned short)(patch->varTree[vni[1].iTreeAndMask & 1][vni[1].iNode].flags & 0xFFFE & vni[1].iTreeAndMask) - != 0); + if ((vni[0].iTreeAndMask & patch->varTree[vni[0].iTreeAndMask & 1][vni[0].iNode].flags & 0xFFFE) != 0) { + flags0 = 2; + } else { + flags0 = 0; + } - square->eMode = modeTable[(j + i) & 1 | 2 * flags0 | 4 * flags1]; + if ((vni[1].iTreeAndMask & patch->varTree[vni[1].iTreeAndMask & 1][vni[1].iNode].flags & 0xFFFFFFFE) != 0) { + flags1 = 4; + } else { + flags1 = 0; + } + + square->eMode = modeTable[(j + i) & 1 | flags0 | flags1]; if (square->eMode == 2) { if (DotProduct(vTest, square->plane[0]) < square->plane[0][3]) { From ab91ade685b406e2f1b26ae16e8cd4ac04e158c5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 19:56:24 +0200 Subject: [PATCH 0408/2040] Explicitly use signed char for patch xy because some platforms use unsigned char by default --- code/qcommon/qfiles.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index c367ab00..d43426d3 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -438,8 +438,8 @@ typedef struct cTerraPatch_s { vec2_t texCoord[ 2 ][ 2 ]; - char x; - char y; + signed char x; + signed char y; short iBaseHeight; unsigned short iShader; From 0333fd86f82474df60804fee4f89e03fa6e2806c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 8 Jun 2024 21:52:28 +0200 Subject: [PATCH 0409/2040] MSG_DeltaNeeded_ver_15 was never called --- code/qcommon/msg.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/qcommon/msg.cpp b/code/qcommon/msg.cpp index 1555aba6..3655a30a 100644 --- a/code/qcommon/msg.cpp +++ b/code/qcommon/msg.cpp @@ -2645,11 +2645,12 @@ void MSG_WritePackedCoordExtra(msg_t* msg, float fromValue, float toValue, int b } } -qboolean MSG_DeltaNeeded(const void* fromField, const void* toField, int fieldType, int bits) -{ - // Unoptimized in base game - // Doesn't compare packed values - return *(int*)fromField != *(int*)toField; +qboolean MSG_DeltaNeeded(const void* fromField, const void* toField, int fieldType, int bits) { + if (MSG_IsProtocolVersion15()) { + return MSG_DeltaNeeded_ver_15(fromField, toField, fieldType, bits); + } else { + return MSG_DeltaNeeded_ver_6(fromField, toField, fieldType, bits); + } } float MSG_ReadPackedVelocity(msg_t* msg, int bits) From 72824267366bee71180a8a8a52207aec92bea035 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 00:02:00 +0200 Subject: [PATCH 0410/2040] Improved the networking code for big-endian architectures --- code/qcommon/msg.cpp | 153 ++++++++++++++++++++++++++++------------- code/qcommon/qcommon.h | 2 +- 2 files changed, 108 insertions(+), 47 deletions(-) diff --git a/code/qcommon/msg.cpp b/code/qcommon/msg.cpp index 3655a30a..b1bd6ee6 100644 --- a/code/qcommon/msg.cpp +++ b/code/qcommon/msg.cpp @@ -1280,13 +1280,30 @@ typedef enum netFieldType_e { typedef struct { const char *name; size_t offset; + size_t size; // bits: 0 = float int bits; int type; } netField_t; +byte* LittleOffset(void* value, size_t size, size_t targetSize) { +#ifdef Q3_BIG_ENDIAN + return (byte*)value + size - targetSize; +#else + return (byte*)value; +#endif +} + +void CopyToLittleField(void* toF, const void* value, size_t size, size_t targetSize) { + Com_Memcpy(toF, LittleOffset((byte*)value, size, targetSize), targetSize); +} + +void CopyFromLittleField(void* value, const void* fromF, size_t size, size_t targetSize) { + Com_Memcpy(LittleOffset((byte*)value, size, targetSize), fromF, targetSize); +} + // using the stringizing operator to save typing... -#define NETF(x) #x,(size_t)&((entityState_t*)0)->x +#define NETF(x) #x,(size_t)&((entityState_t*)0)->x,sizeof(entityState_t::x) netField_t entityStateFields_ver_15[] = { @@ -1610,7 +1627,7 @@ netField_t* MSG_GetEntityStateFields(size_t& outNumFields) #define FLOAT_INT_BITS 13 #define FLOAT_INT_BIAS (1<<(FLOAT_INT_BITS-1)) -void MSG_ReadRegular_ver_15(msg_t* sb, int bits, void* toF) +void MSG_ReadRegular_ver_15(msg_t* sb, int bits, int size, void* toF) { if (bits == 0) { @@ -1642,20 +1659,21 @@ void MSG_ReadRegular_ver_15(msg_t* sb, int bits, void* toF) else { if (MSG_ReadBits(sb, 1)) { - *(int*)toF = MSG_ReadBits(sb, bits); + int tmp = MSG_ReadBits(sb, bits); + CopyToLittleField(toF, &tmp, sizeof(int), size); } else { - *(int*)toF = 0; + Com_Memset(toF, 0, size); } } } -void MSG_ReadRegularSimple_ver_15(msg_t* sb, int bits, void* toF) +void MSG_ReadRegularSimple_ver_15(msg_t* sb, int bits, int size, void* toF) { - MSG_ReadRegular_ver_15(sb, bits, toF); + MSG_ReadRegular_ver_15(sb, bits, size, toF); } -void MSG_WriteRegular_ver_15(msg_t* sb, int bits, const void* toF) +void MSG_WriteRegular_ver_15(msg_t* sb, int bits, int size, const void* toF) { float fullFloat; int trunc; @@ -1688,20 +1706,36 @@ void MSG_WriteRegular_ver_15(msg_t* sb, int bits, const void* toF) } } else { - if (!*(int*)toF) { + qboolean hasValue = qfalse; + for (size_t i = 0; i < size; ++i) + { + if (((byte*)toF)[i] != 0) + { + hasValue = qtrue; + break; + } + } + + if (!hasValue) { MSG_WriteBits(sb, 0, 1); } else { + // + // Added in OPM + // Properly swap on little-endian architectures + int tmp = 0; + CopyFromLittleField(&tmp, toF, sizeof(int), size); + MSG_WriteBits(sb, 1, 1); // integer - MSG_WriteBits(sb, *(int*)toF, bits); + MSG_WriteBits(sb, tmp, bits); } } } -void MSG_WriteRegularSimple_ver_15(msg_t* sb, int bits, const void* toF) +void MSG_WriteRegularSimple_ver_15(msg_t* sb, int bits, int size, const void* toF) { - MSG_WriteRegular_ver_15(sb, bits, toF); + MSG_WriteRegular_ver_15(sb, bits, size, toF); } void MSG_WriteEntityNum_ver_15(msg_t* sb, short number) @@ -1715,7 +1749,7 @@ unsigned short MSG_ReadEntityNum_ver_15(msg_t* sb) return (unsigned short)(MSG_ReadBits(sb, GENTITYNUM_BITS) - 1) % MAX_GENTITIES; } -void MSG_ReadRegular_ver_6(msg_t* sb, int bits, void* toF) +void MSG_ReadRegular_ver_6(msg_t* sb, int bits, int size, void* toF) { if (bits == 0) { @@ -1738,15 +1772,16 @@ void MSG_ReadRegular_ver_6(msg_t* sb, int bits, void* toF) else { if (MSG_ReadBits(sb, 1)) { - *(int*)toF = MSG_ReadBits(sb, bits); + int tmp = MSG_ReadBits(sb, bits); + CopyToLittleField(toF, &tmp, sizeof(int), size); } else { - *(int*)toF = 0; + Com_Memset(toF, 0, size); } } } -void MSG_ReadRegularSimple_ver_6(msg_t* sb, int bits, void* toF) +void MSG_ReadRegularSimple_ver_6(msg_t* sb, int bits, int size, void* toF) { if (bits == 0) { // float @@ -1764,11 +1799,12 @@ void MSG_ReadRegularSimple_ver_6(msg_t* sb, int bits, void* toF) } else { // integer - *(int*)toF = MSG_ReadBits(sb, bits); + int tmp = MSG_ReadBits(sb, bits); + CopyToLittleField(toF, &tmp, sizeof(int), size); } } -void MSG_WriteRegular_ver_6(msg_t* sb, int bits, const void* toF) +void MSG_WriteRegular_ver_6(msg_t* sb, int bits, int size, const void* toF) { float fullFloat; int trunc; @@ -1802,14 +1838,20 @@ void MSG_WriteRegular_ver_6(msg_t* sb, int bits, const void* toF) MSG_WriteBits(sb, 0, 1); } else { + // + // Added in OPM + // Properly swap on little-endian architectures + int tmp = 0; + CopyFromLittleField(&tmp, toF, sizeof(int), size); + MSG_WriteBits(sb, 1, 1); // integer - MSG_WriteBits(sb, *(int*)toF, bits); + MSG_WriteBits(sb, tmp, bits); } } } -void MSG_WriteRegularSimple_ver_6(msg_t* sb, int bits, const void* toF) +void MSG_WriteRegularSimple_ver_6(msg_t* sb, int bits, int size, const void* toF) { float fullFloat; int trunc; @@ -1833,7 +1875,14 @@ void MSG_WriteRegularSimple_ver_6(msg_t* sb, int bits, const void* toF) } else { // integer - MSG_WriteBits(sb, *(int*)toF, bits); + // + // Added in OPM + // Properly swap on little-endian architectures + int tmp = 0; + CopyFromLittleField(&tmp, toF, sizeof(int), size); + + // integer + MSG_WriteBits(sb, tmp, bits); } } @@ -1847,39 +1896,39 @@ unsigned short MSG_ReadEntityNum_ver_6(msg_t* sb) return MSG_ReadBits(sb, GENTITYNUM_BITS) % MAX_GENTITIES; } -void MSG_ReadRegular(msg_t* sb, int bits, void* toF) +void MSG_ReadRegular(msg_t* sb, int bits, int size, void* toF) { if (MSG_IsProtocolVersion15()) { - return MSG_ReadRegular_ver_15(sb, bits, toF); + return MSG_ReadRegular_ver_15(sb, bits, size, toF); } else { - return MSG_ReadRegular_ver_6(sb, bits, toF); + return MSG_ReadRegular_ver_6(sb, bits, size, toF); } } -void MSG_ReadRegularSimple(msg_t* sb, int bits, void* toF) +void MSG_ReadRegularSimple(msg_t* sb, int bits, int size, void* toF) { if (MSG_IsProtocolVersion15()) { - return MSG_ReadRegularSimple_ver_15(sb, bits, toF); + return MSG_ReadRegularSimple_ver_15(sb, bits, size, toF); } else { - return MSG_ReadRegularSimple_ver_6(sb, bits, toF); + return MSG_ReadRegularSimple_ver_6(sb, bits, size, toF); } } -void MSG_WriteRegular(msg_t* sb, int bits, const void* toF) +void MSG_WriteRegular(msg_t* sb, int bits, int size, const void* toF) { if (MSG_IsProtocolVersion15()) { - return MSG_WriteRegular_ver_15(sb, bits, toF); + return MSG_WriteRegular_ver_15(sb, bits, size, toF); } else { - return MSG_WriteRegular_ver_6(sb, bits, toF); + return MSG_WriteRegular_ver_6(sb, bits, size, toF); } } -void MSG_WriteRegularSimple(msg_t* sb, int bits, const void* toF) +void MSG_WriteRegularSimple(msg_t* sb, int bits, int size, const void* toF) { if (MSG_IsProtocolVersion15()) { - return MSG_WriteRegularSimple_ver_15(sb, bits, toF); + return MSG_WriteRegularSimple_ver_15(sb, bits, size, toF); } else { - return MSG_WriteRegularSimple_ver_6(sb, bits, toF); + return MSG_WriteRegularSimple_ver_6(sb, bits, size, toF); } } @@ -1950,7 +1999,7 @@ void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entity for ( i = 0, field = entityStateFields ; i < numFields; i++, field++ ) { fromF = (int *)( (byte *)from + field->offset ); toF = (int *)( (byte *)to + field->offset ); - deltasNeeded[i] = MSG_DeltaNeeded(fromF, toF, field->type, field->bits); + deltasNeeded[i] = MSG_DeltaNeeded(fromF, toF, field->type, field->bits, field->size); if (deltasNeeded[i]) { lc = i+1; } @@ -1992,7 +2041,7 @@ void MSG_WriteDeltaEntity( msg_t *msg, struct entityState_s *from, struct entity switch ( field->type ) { // normal style case netFieldType_e::regular: - MSG_WriteRegular(msg, field->bits, toF); + MSG_WriteRegular(msg, field->bits, field->size, toF); break; case netFieldType_e::angle: MSG_WritePackedAngle(msg, *(float*)toF, field->bits); @@ -2283,13 +2332,16 @@ void MSG_WritePackedCoordExtra_ver_15(msg_t* msg, float fromValue, float toValue MSG_WriteDeltaCoordExtra(msg, packedFrom, packedTo); } -qboolean MSG_DeltaNeeded_ver_15(const void* fromField, const void* toField, int fieldType, int bits) +qboolean MSG_DeltaNeeded_ver_15(const void* fromField, const void* toField, int fieldType, int bits, int size) { int packedFrom; int packedTo; int maxValue; + int xoredValue; + int i; - if (*(int*)fromField == *(int*)toField) { + if (!memcmp(fromField, toField, size)) { + // same values, not needed return qfalse; } @@ -2301,7 +2353,16 @@ qboolean MSG_DeltaNeeded_ver_15(const void* fromField, const void* toField, int } maxValue = (1 << abs(bits)) - 1; - return ((*(int*)fromField ^ *(int*)toField) & maxValue) != 0; + xoredValue = 0; + + for (i = 0; i < size; i++) { + byte fromVal, toVal; + + fromVal = ((byte*)fromField)[i]; + toVal = ((byte*)toField)[i]; + xoredValue += fromVal ^ toVal; + } + return (xoredValue & maxValue) != 0; case netFieldType_e::angle: packedFrom = MSG_PackAngle(*(float*)fromField, bits); packedTo = MSG_PackAngle(*(float*)toField, bits); @@ -2524,11 +2585,11 @@ void MSG_WritePackedCoordExtra_ver_6(msg_t* msg, float fromValue, float toValue, // Don't implement } -qboolean MSG_DeltaNeeded_ver_6(const void* fromField, const void* toField, int fieldType, int bits) +qboolean MSG_DeltaNeeded_ver_6(const void* fromField, const void* toField, int fieldType, int bits, int size) { // Unoptimized in base game // Doesn't compare packed values - return *(int*)fromField != *(int*)toField; + return memcmp(fromField, toField, size); } float MSG_ReadPackedAngle(msg_t* msg, int bits) { @@ -2645,11 +2706,11 @@ void MSG_WritePackedCoordExtra(msg_t* msg, float fromValue, float toValue, int b } } -qboolean MSG_DeltaNeeded(const void* fromField, const void* toField, int fieldType, int bits) { +qboolean MSG_DeltaNeeded(const void* fromField, const void* toField, int fieldType, int bits, int size) { if (MSG_IsProtocolVersion15()) { - return MSG_DeltaNeeded_ver_15(fromField, toField, fieldType, bits); + return MSG_DeltaNeeded_ver_15(fromField, toField, fieldType, bits, size); } else { - return MSG_DeltaNeeded_ver_6(fromField, toField, fieldType, bits); + return MSG_DeltaNeeded_ver_6(fromField, toField, fieldType, bits, size); } } @@ -2788,7 +2849,7 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, } else { switch (field->type) { case netFieldType_e::regular: - MSG_ReadRegular(msg, field->bits, toF); + MSG_ReadRegular(msg, field->bits, field->size, toF); break; case netFieldType_e::angle: // angles, what a mess! it wouldnt surprise me if something goes wrong here ;) *(float*)toF = MSG_ReadPackedAngle(msg, field->bits); @@ -3073,7 +3134,7 @@ plyer_state_t communication */ // using the stringizing operator to save typing... -#define PSF(x) #x,(size_t)&((playerState_t*)0)->x +#define PSF(x) #x,(size_t)&((playerState_t*)0)->x,sizeof(playerState_t::x) netField_t playerStateFields_ver_15[] = { @@ -3267,7 +3328,7 @@ void MSG_WriteDeltaPlayerstate(msg_t *msg, struct playerState_s *from, struct pl switch ( field->type ) { case netFieldType_e::regular: - MSG_WriteRegularSimple(msg, field->bits, toF); + MSG_WriteRegularSimple(msg, field->bits, field->size, toF); break; case netFieldType_e::angle: MSG_WritePackedAngle(msg, *(float*)toF, field->bits); @@ -3456,7 +3517,7 @@ void MSG_ReadDeltaPlayerstate(msg_t *msg, playerState_t *from, playerState_t *to } else { switch ( field->type ) { case netFieldType_e::regular: - MSG_ReadRegularSimple(msg, field->bits, toF); + MSG_ReadRegularSimple(msg, field->bits, field->size, toF); break; case netFieldType_e::angle: *(float*)toF = MSG_ReadPackedAngle(msg, field->bits); diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index dd1cabcc..8ddcf7d4 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -154,7 +154,7 @@ int MSG_PackScale(float scale, int bits); int MSG_PackAlpha(float alpha, int bits); int MSG_PackCoord(float coord); int MSG_PackCoordExtra(float coord); -qboolean MSG_DeltaNeeded(const void* fromField, const void* toField, int fieldType, int bits); +qboolean MSG_DeltaNeeded(const void* fromField, const void* toField, int fieldType, int bits, int size); void MSG_WritePackedAngle(msg_t* msg, float value, int bits); void MSG_WritePackedAnimTime(msg_t* msg, float fromValue, float toValue, float frameTime, int bits); From a7c506747538b144db9f74a58738dee5d8604eab Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 00:05:32 +0200 Subject: [PATCH 0411/2040] Fixed the execution of a method on the correct class --- code/script/scriptcompiler.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index f3fdcf3c..928de100 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -273,11 +273,11 @@ void ScriptCompiler::EmitAssignmentStatement(sval_t lhs, unsigned int sourcePos) listener_val = lhs.node[1]; if (listener_val.node[0].type != ENUM_listener - || (eventnum && BuiltinWriteVariable(sourcePos, listener_val.node[1].byteValue, eventnum))) { + || (eventnum && BuiltinWriteVariable(sourcePos, listener_val.node[1].intValue, eventnum))) { EmitValue(listener_val); EmitOpcode(OP_LOAD_FIELD_VAR, sourcePos); } else { - EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].byteValue, sourcePos); + EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].intValue, sourcePos); } EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); @@ -504,16 +504,16 @@ void ScriptCompiler::EmitField(sval_t listener_val, sval_t field_val, unsigned i prev_index = GetOpcodeValue(sizeof(unsigned int), sizeof(unsigned int)); if (listener_val.node[0].type != ENUM_listener - || (eventnum && BuiltinReadVariable(sourcePos, listener_val.node[1].byteValue, eventnum))) { + || (eventnum && BuiltinReadVariable(sourcePos, listener_val.node[1].intValue, eventnum))) { EmitValue(listener_val); EmitOpcode(OP_STORE_FIELD, sourcePos); EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); - } else if (PrevOpcode() != (OP_LOAD_GAME_VAR + listener_val.node[1].byteValue) || prev_index != index) { - EmitOpcode(OP_STORE_GAME_VAR + listener_val.node[1].byteValue, sourcePos); + } else if (PrevOpcode() != (OP_LOAD_GAME_VAR + listener_val.node[1].intValue) || prev_index != index) { + EmitOpcode(OP_STORE_GAME_VAR + listener_val.node[1].intValue, sourcePos); EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); } else { AbsorbPrevOpcode(); - EmitOpcode(OP_LOAD_STORE_GAME_VAR + listener_val.node[1].byteValue, sourcePos); + EmitOpcode(OP_LOAD_STORE_GAME_VAR + listener_val.node[1].intValue, sourcePos); code_pos += sizeof(unsigned int); } } @@ -926,11 +926,11 @@ void ScriptCompiler::EmitParameter(sval_t lhs, unsigned int sourcePos) int eventnum = Event::FindSetterEventNum(name); if (listener_val.node[0].type != ENUM_listener - || (eventnum && BuiltinWriteVariable(sourcePos, listener_val.node[1].byteValue, eventnum))) { + || (eventnum && BuiltinWriteVariable(sourcePos, listener_val.node[1].intValue, eventnum))) { CompileError(sourcePos, "built-in field '%s' not allowed", name); } else { EmitOpcode(OP_STORE_PARAM, sourcePos); - EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].byteValue, sourcePos); + EmitOpcode(OP_LOAD_GAME_VAR + listener_val.node[1].intValue, sourcePos); unsigned int index = Director.AddString(name); EmitOpcodeValue((unsigned int)index, sizeof(unsigned int)); @@ -1266,7 +1266,7 @@ __emit: break; case ENUM_listener: - EmitOpcode(OP_STORE_GAME + val.node[1].byteValue, val.node[2].sourcePosValue); + EmitOpcode(OP_STORE_GAME + val.node[1].intValue, val.node[2].sourcePosValue); break; case ENUM_NIL: From de621f6acb3832d60f60e9eed5e68fb27496e0e2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 00:59:23 +0200 Subject: [PATCH 0412/2040] Made short3 implementation endianness independant This fixes scripts not working properly as script variables key are using short3 --- code/qcommon/short3.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/qcommon/short3.h b/code/qcommon/short3.h index 33c80e0d..542850d4 100644 --- a/code/qcommon/short3.h +++ b/code/qcommon/short3.h @@ -39,8 +39,8 @@ private: short3_data_t data; protected: - int get() const { return *( int * )this & 0xFFFFFF; } - void set( int value ) { data.highmid = value; data.low = *( ( unsigned char * )&value + 2 ); } + int get() const { return data.highmid | (data.low << 16); } + void set( int value ) { data.highmid = value & 0xFFFF; data.low = value >> 16; } public : operator int( void ) const { return get(); } From d3d2082e41ea3c37dad5d34f62c12875f8096084 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:08:01 +0200 Subject: [PATCH 0413/2040] Removed useless print --- code/fgame/navigate.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/fgame/navigate.cpp b/code/fgame/navigate.cpp index b7b76eb9..887bc04e 100644 --- a/code/fgame/navigate.cpp +++ b/code/fgame/navigate.cpp @@ -2698,8 +2698,6 @@ qboolean CheckMove(Vector& origin, Vector& pos, short int *path_fallheight, floa if (DotProduct2D(dir, mm.desired_dir) <= 0.1f) { error = mm.origin[2] - pos[2]; - gi.Printf("error = %f\n", error); - *path_fallheight = (short)fallheight; if (fabs(error) <= 94.0f) { if (error <= 0.0f || mm.groundPlane) { From 69766ae87a6db6656d64cb22e778f0e52b554fdf Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:19:31 +0200 Subject: [PATCH 0414/2040] Added SwapValue --- code/qcommon/q_platform.h | 5 +++++ code/qcommon/q_shared.c | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 25feb84c..d7fcce1e 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -402,6 +402,7 @@ short ShortNoSwapPtr(const void* l); int LongNoSwapPtr(const void* l); float FloatSwapPtr(const void* l); float FloatNoSwapPtr(const void* l); +void SwapValue(void* dest, size_t size); #if defined( Q3_BIG_ENDIAN ) && defined( Q3_LITTLE_ENDIAN ) #error "Endianness defined as both big and little" @@ -422,12 +423,14 @@ float FloatNoSwapPtr(const void* l); #define LittleShortPtr(x) ShortSwapPtr(&x) #define LittleLongPtr(x) LongSwapPtr(&x) #define LittleFloatPtr(x) FloatSwapPtr(&x) +#define LittleSwap(x, size) SwapValue(x, size) #define BigShort #define BigLong #define BigFloat #define BigShortPtr(x) ShortNoSwapPtr(&x) #define BigLongPtr(x) LongNoSwapPtr(&x) +#define BigSwap(x, size) x #elif defined( Q3_LITTLE_ENDIAN ) @@ -441,6 +444,7 @@ float FloatNoSwapPtr(const void* l); #define LittleShortPtr(x) ShortNoSwapPtr(&x) #define LittleLongPtr(x) LongNoSwapPtr(&x) #define LittleFloatPtr(x) FloatNoSwapPtr(&x) +#define LittleSwap(x, size) x #define BigShort(x) ShortSwap(x) #define BigUnsignedShort(x) UnsignedShortSwap(x) @@ -449,6 +453,7 @@ float FloatNoSwapPtr(const void* l); #define BigFloat(x) FloatSwap(&x) #define BigShortPtr(x) ShortSwapPtr(&x) #define BigLongPtr(x) LongSwapPtr(&x) +#define BigSwap(x, size) SwapValue(x, size) #else #error "Endianness not defined" diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 164284f2..485f016b 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -1492,6 +1492,21 @@ void CopyLongSwap(void* dest, const void* src) to[3] = from[0]; } +void SwapValue(void* dest, size_t size) { + byte* data = (byte*)dest; + + // swap values + for (size_t i = size / 2; i > 0; --i) + { + uint8_t* in = data + i - 1; + uint8_t* out = data + size - i; + + const uint8_t tmp = *in; + *in = *out; + *out = tmp; + } +} + short ShortSwap(short l) { byte b1, b2; From 8aacdcefb8ca02dde87aa70c8a852fe0fec04982 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:14:11 +0200 Subject: [PATCH 0415/2040] Fixed lz77 endianness --- code/qcommon/lz77.cpp | 228 +++++++++++++++++++++--------------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/code/qcommon/lz77.cpp b/code/qcommon/lz77.cpp index 779fb634..cf105e76 100644 --- a/code/qcommon/lz77.cpp +++ b/code/qcommon/lz77.cpp @@ -151,59 +151,59 @@ cLZ77::cLZ77() unsigned int cLZ77::CompressData( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len ) { - uint8_t* ip; // eax - unsigned int v7; // edi - unsigned int v8; // edx - unsigned int v9; // edx - unsigned int v10; // esi - unsigned int m_off; // edx - uint8_t* v12; // ebp - unsigned int v13; // edx - unsigned int v14; // esi - unsigned int v15; // edx - unsigned int v16; // ebp - uint8_t* v17; // esi - unsigned int v18; // edx - uint8_t* v19; // esi - uint8_t* v20; // eax - int v22; // eax - uint8_t v23; // bl - uint8_t* v24; // esi - unsigned int v25; // edx - uint8_t* v26; // esi - uint8_t* m_pos; // eax - uint8_t* v28; // ebp - bool v29; // zf - uint8_t v30; // al - uint8_t v31; // dl - uint8_t v32; // dl - uint8_t v33; // al - uint8_t v34; // al - uint8_t v35; // dl - uint8_t v36; // dl - uint8_t v37; // al - uint8_t v38; // al - uint8_t v39; // dl - uint8_t* in_end; // edi - uint8_t* v41; // eax - uint8_t* v42; // esi - unsigned int v43; // edx - unsigned int v44; // eax - uint8_t* v45; // edi - uint8_t* i; // edx - uint8_t* v47; // edi - unsigned int v48; // edx - unsigned int v49; // edx - unsigned int m_len; // eax - uint8_t* v51; // edi - uint8_t* v52; // edi - uint8_t* ii; // esi - uint8_t* v54; // edi - unsigned int v55; // edx - char v56; // dl - uint8_t* v57; // eax - uint8_t v58; // dl - uint8_t* v59; // edi + uint8_t* ip; + unsigned int v7; + unsigned int v8; + unsigned int v9; + unsigned int v10; + unsigned int m_off; + uint8_t* v12; + unsigned int v13; + unsigned int v14; + unsigned int v15; + unsigned int v16; + uint8_t* v17; + unsigned int v18; + uint8_t* v19; + uint8_t* v20; + int v22; + uint8_t v23; + uint8_t* v24; + unsigned int v25; + uint8_t* v26; + uint8_t* m_pos; + uint8_t* v28; + bool v29; + uint8_t v30; + uint8_t v31; + uint8_t v32; + uint8_t v33; + uint8_t v34; + uint8_t v35; + uint8_t v36; + uint8_t v37; + uint8_t v38; + uint8_t v39; + uint8_t* in_end; + uint8_t* v41; + uint8_t* v42; + unsigned int v43; + unsigned int v44; + uint8_t* v45; + uint8_t* i; + uint8_t* v47; + unsigned int v48; + unsigned int v49; + unsigned int m_len; + uint8_t* v51; + uint8_t* v52; + uint8_t* ii; + uint8_t* v54; + unsigned int v55; + char v56; + uint8_t* v57; + uint8_t v58; + uint8_t* v59; this->in_end = &in[in_len]; this->ip_end = &in[in_len - 13]; @@ -583,65 +583,65 @@ LABEL_19: *************************************************************************/ int cLZ77::Decompress( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len ) { - unsigned int v5; // eax - uint8_t* v6; // esi - unsigned int v7; // eax - uint8_t* v8; // esi - int v9; // edx - uint8_t* v10; // edx - uint8_t* v11; // ebp - unsigned int v12; // eax - uint8_t* v13; // esi - uint8_t* v14; // edi - uint8_t* v15; // esi - uint8_t* v16; // esi - uint8_t* v17; // esi - uint8_t* op; // edi - uint8_t* v19; // eax - uint8_t* v20; // eax - uint8_t* v21; // ebp - uint8_t* v22; // edi - uint8_t* v23; // edi - uint8_t* ip; // ebp - uint8_t* v25; // esi - uint8_t* v26; // esi - int v27; // ebp - uint8_t* v28; // edi - uint8_t* v29; // esi - uint8_t* v30; // edx - uint8_t* v31; // eax - uint8_t* v32; // edi - uint8_t* v33; // esi - unsigned int v34; // eax - uint8_t* v35; // edx - int v36; // edx - uint8_t* v37; // esi - uint8_t* v38; // edi - uint8_t* v39; // edx - uint8_t* v40; // edi - uint8_t* v41; // edx - int v42; // edx - uint8_t* v43; // ebp - uint8_t* v44; // ebp - uint8_t* v45; // edi - uint8_t* v46; // edx - unsigned int v47; // eax - uint8_t* v48; // ebp - uint8_t* v49; // esi - uint8_t* v50; // ebp - uint8_t* v51; // edi - uint8_t* v52; // esi - uint8_t* v53; // edx - uint8_t* v54; // ebp - uint8_t* v55; // edi - uint8_t* v56; // edi - uint8_t* v57; // eax - uint8_t* v58; // eax - uint8_t* v59; // edx - uint8_t* v60; // eax - uint8_t* v61; // edi - uint8_t* v62; // eax - uint8_t* ip_end; // ecx + unsigned int v5; + uint8_t* v6; + unsigned int v7; + uint8_t* v8; + int v9; + uint8_t* v10; + uint8_t* v11; + unsigned int v12; + uint8_t* v13; + uint8_t* v14; + uint8_t* v15; + uint8_t* v16; + uint8_t* v17; + uint8_t* op; + uint8_t* v19; + uint8_t* v20; + uint8_t* v21; + uint8_t* v22; + uint8_t* v23; + uint8_t* ip; + uint8_t* v25; + uint8_t* v26; + int v27; + uint8_t* v28; + uint8_t* v29; + uint8_t* v30; + uint8_t* v31; + uint8_t* v32; + uint8_t* v33; + unsigned int v34; + uint8_t* v35; + int v36; + uint8_t* v37; + uint8_t* v38; + uint8_t* v39; + uint8_t* v40; + uint8_t* v41; + int v42; + uint8_t* v43; + uint8_t* v44; + uint8_t* v45; + uint8_t* v46; + unsigned int v47; + uint8_t* v48; + uint8_t* v49; + uint8_t* v50; + uint8_t* v51; + uint8_t* v52; + uint8_t* v53; + uint8_t* v54; + uint8_t* v55; + uint8_t* v56; + uint8_t* v57; + uint8_t* v58; + uint8_t* v59; + uint8_t* v60; + uint8_t* v61; + uint8_t* v62; + uint8_t* ip_end; this->ip_end = in + in_len; *out_len = 0; @@ -802,7 +802,7 @@ LABEL_5: v37 = this->op; v38 = this->ip; this->m_pos = v37 - 1; - v39 = v37 - (*(uint16_t*)v38 >> 2) - 1; + v39 = v37 - (LittleShort(*(unsigned short*)v38) >> 2) - 1; this->ip = v38 + 2; goto LABEL_36; } @@ -835,7 +835,7 @@ LABEL_5: v42 = *this->ip++; v34 += v42 + 7; } - this->m_pos -= *(unsigned short*)this->ip >> 2; + this->m_pos -= LittleShort(*(unsigned short*)this->ip) >> 2; this->ip += 2; if (this->m_pos == v37) break; From 57175cfa5c3206f83178bdc516284ef4b4ebdd63 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 16:45:10 +0200 Subject: [PATCH 0416/2040] Simplified the decompression algorithm and fixed it for big-endian --- code/qcommon/lz77.cpp | 385 +++++++++++++----------------------------- 1 file changed, 120 insertions(+), 265 deletions(-) diff --git a/code/qcommon/lz77.cpp b/code/qcommon/lz77.cpp index cf105e76..57eacd3e 100644 --- a/code/qcommon/lz77.cpp +++ b/code/qcommon/lz77.cpp @@ -583,337 +583,192 @@ LABEL_19: *************************************************************************/ int cLZ77::Decompress( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len ) { - unsigned int v5; - uint8_t* v6; - unsigned int v7; - uint8_t* v8; - int v9; - uint8_t* v10; - uint8_t* v11; - unsigned int v12; - uint8_t* v13; - uint8_t* v14; - uint8_t* v15; - uint8_t* v16; - uint8_t* v17; - uint8_t* op; - uint8_t* v19; - uint8_t* v20; - uint8_t* v21; - uint8_t* v22; - uint8_t* v23; - uint8_t* ip; - uint8_t* v25; - uint8_t* v26; - int v27; - uint8_t* v28; - uint8_t* v29; - uint8_t* v30; - uint8_t* v31; - uint8_t* v32; - uint8_t* v33; - unsigned int v34; - uint8_t* v35; - int v36; - uint8_t* v37; - uint8_t* v38; - uint8_t* v39; - uint8_t* v40; - uint8_t* v41; - int v42; - uint8_t* v43; - uint8_t* v44; - uint8_t* v45; - uint8_t* v46; - unsigned int v47; - uint8_t* v48; - uint8_t* v49; - uint8_t* v50; - uint8_t* v51; - uint8_t* v52; - uint8_t* v53; - uint8_t* v54; - uint8_t* v55; - uint8_t* v56; - uint8_t* v57; - uint8_t* v58; - uint8_t* v59; - uint8_t* v60; - uint8_t* v61; - uint8_t* v62; - uint8_t* ip_end; + unsigned int t; - this->ip_end = in + in_len; + this->ip_end = &in[in_len]; *out_len = 0; this->op = out; this->ip = in; - if (*in > 17u) + if (*this->ip > 17u) { - v5 = *in - 17; - this->ip = in + 1; - if (v5 < 4) - goto LABEL_49; + t = *this->ip++ - 17; + if (t <= 3) + goto LABEL_52; do { - *this->op = *this->ip; - v6 = this->ip + 1; - --v5; - ++this->op; - this->ip = v6; - } while (v5); + *this->op++ = *this->ip++; + --t; + } while (t); goto LABEL_17; } + LABEL_5: - v7 = *this->ip; - v8 = this->ip + 1; - this->ip = v8; - if (v7 < 16) + t = *this->ip++; + if (t <= 15) { - if (!v7) + if (!t) { - for (; !*v8; this->ip = v8) + while (!*this->ip) { - v7 += 255; - ++v8; + t += 255; + ++this->ip; } - v9 = *v8; - this->ip = v8 + 1; - v7 += v9 + 15; + t += 15 + *this->ip++; } - *(int*)this->op = *(int*)this->ip; - v10 = this->op + 4; - v11 = this->ip + 4; - v12 = v7 - 1; - this->op = v10; - this->ip = v11; - v13 = v11; - if (v12) + *(unsigned int*)this->op = *(unsigned int*)this->ip; + this->op += 4; + this->ip += 4; + if (--t) { - if (v12 < 4) + if (t <= 3) { do { - *this->op = *this->ip; - v16 = this->ip + 1; - --v12; - ++this->op; - this->ip = v16; - } while (v12); + *this->op++ = *this->ip++; + --t; + } while (t); } else { do { - v12 -= 4; - *(int*)v10 = *(int*)v13; - v14 = this->op + 4; - v13 = this->ip + 4; - this->op = v14; - v10 = v14; - this->ip = v13; - } while (v12 >= 4); - for (; v12; this->ip = v15) - { - *this->op = *this->ip; - v15 = this->ip + 1; - --v12; - ++this->op; - } + *(unsigned int*)this->op = *(unsigned int*)this->ip; + this->op += 4; + this->ip += 4; + t -= 4; + } while (t > 3); + for (; t; --t) + *this->op++ = *this->ip++; } } LABEL_17: - v7 = *this->ip; - v17 = this->ip + 1; - this->ip = v17; - if (v7 < 16) + t = *this->ip++; + if (t <= 0xF) { - op = this->op; - v19 = op - (v7 >> 2) - 2049; - this->m_pos = v19; - v20 = v19 - 4 * *v17; - this->m_pos = v20; - this->ip = v17 + 1; - *op = *v20; - v21 = this->op + 1; - v22 = this->m_pos + 1; - this->op = v21; - this->m_pos = v22; - *v21 = *v22; - LABEL_47: - v59 = this->m_pos + 1; - v60 = ++this->op; - this->m_pos = v59; - *v60 = *v59; + this->m_pos = this->op - 2049; + this->m_pos -= t >> 2; + this->m_pos -= 4 * *this->ip++; + *this->op = *this->m_pos++; + *++this->op = *this->m_pos++; + *++this->op = *this->m_pos; ++this->op; - goto LABEL_48; + goto LABEL_51; } } while (1) { - if (v7 >= 64) + if (t > 0x3F) { - v23 = this->op; - ip = this->ip; - v25 = v23 - ((v7 >> 2) & 7) - 1; - this->m_pos = v25; - v26 = v25 - 8 * *ip; - this->ip = ip + 1; - v27 = (v7 >> 5) - 1; - this->m_pos = v26; - *v23 = *v26; - v28 = this->op + 1; - v29 = this->m_pos + 1; - this->op = v28; - this->m_pos = v29; - *v28 = *v29; - v30 = this->op + 1; - v31 = this->m_pos + 1; - this->op = v30; - this->m_pos = v31; + this->m_pos = this->op - 1; + this->m_pos -= (t >> 2) & 7; + this->m_pos -= 8 * *this->ip++; + t = (t >> 5) - 1; + *this->op = *this->m_pos++; + *++this->op = *this->m_pos++; + ++this->op; do { - *v30 = *this->m_pos; - v32 = this->op + 1; - v33 = this->m_pos + 1; - --v27; - this->op = v32; - v30 = v32; - this->m_pos = v33; - } while (v27); - goto LABEL_48; + *this->op++ = *this->m_pos++; + --t; + } while (t); + goto LABEL_51; } - if (v7 >= 32) + if (t > 0x1F) { - v34 = v7 & 31; - if (!v34) + t &= 0x1Fu; + if (!t) { - if (!*this->ip) + while (!*this->ip) { - do - { - v34 += 255; - v35 = this->ip + 1; - this->ip = v35; - } while (!*v35); + t += 255; + ++this->ip; } - v36 = *this->ip++; - v34 += v36 + 31; + t += 31 + *this->ip++; } - v37 = this->op; - v38 = this->ip; - this->m_pos = v37 - 1; - v39 = v37 - (LittleShort(*(unsigned short*)v38) >> 2) - 1; - this->ip = v38 + 2; - goto LABEL_36; + this->m_pos = this->op - 1; + this->m_pos -= LittleUnsignedShort(*(unsigned short*)this->ip) >> 2; + this->ip += 2; + goto LABEL_42; } - v37 = this->op; - if (v7 < 0x10) + if (t <= 0xF) { - v56 = this->ip; - v57 = v37 - (v7 >> 2) - 1; - this->m_pos = v57; - v58 = v57 - 4 * *v56; - this->m_pos = v58; - this->ip = v56 + 1; - *v37 = *v58; - goto LABEL_47; + this->m_pos = this->op - 1; + this->m_pos -= t >> 2; + this->m_pos -= 4 * *this->ip++; + *this->op = *this->m_pos++; + *++this->op = *this->m_pos; + ++this->op; + goto LABEL_51; } - v40 = v37 - 2048 * (v7 & 8); - v34 = v7 & 7; - this->m_pos = v40; - if (!v34) + this->m_pos = this->op; + this->m_pos -= 2048 * (t & 8); + t &= 7u; + if (!t) { - if (!*this->ip) + while (!*this->ip) { - do - { - v34 += 255; - v41 = this->ip + 1; - this->ip = v41; - } while (!*v41); + t += 255; + ++this->ip; } - v42 = *this->ip++; - v34 += v42 + 7; + t += 7 + *this->ip++; } - this->m_pos -= LittleShort(*(unsigned short*)this->ip) >> 2; + this->m_pos -= LittleUnsignedShort(*(unsigned short*)this->ip) >> 2; this->ip += 2; - if (this->m_pos == v37) + if (this->m_pos == this->op) break; - v39 = this->m_pos - 0x4000; - LABEL_36: - this->m_pos = v39; - if (v34 < 6 || v37 - v39 < 4) + this->m_pos -= 0x4000; + LABEL_42: + if (t <= 5 || this->op - this->m_pos <= 3) { - *v37 = *this->m_pos; - v50 = this->op + 1; - v51 = this->m_pos + 1; - this->op = v50; - this->m_pos = v51; - *v50 = *v51; - v52 = this->op + 1; - v53 = this->m_pos + 1; - this->op = v52; - this->m_pos = v53; + *this->op = *this->m_pos++; + *++this->op = *this->m_pos++; + ++this->op; do { - *v52 = *this->m_pos; - v54 = this->op + 1; - v55 = this->m_pos + 1; - --v34; - this->op = v54; - v52 = v54; - this->m_pos = v55; - } while (v34); + *this->op++ = *this->m_pos++; + --t; + } while (t); } else { - *(int*)v37 = *(int*)v39; - v44 = this->op + 4; - v45 = this->m_pos + 4; - this->op = v44; - v46 = v44; - this->m_pos = v45; - v47 = v34 - 2; + *(unsigned int*)this->op = *(unsigned int*)this->m_pos; + this->op += 4; + this->m_pos += 4; + t -= 2; do { - v47 -= 4; - *(int*)v46 = *(int*)this->m_pos; - v46 = this->op + 4; - v48 = this->m_pos + 4; - this->op = v46; - this->m_pos = v48; - } while (v47 >= 4); - for (; v47; this->m_pos = v49) - { - *this->op = *this->m_pos; - v49 = this->m_pos + 1; - --v47; - ++this->op; - } + *(unsigned int*)this->op = *(unsigned int*)this->m_pos; + this->op += 4; + this->m_pos += 4; + t -= 4; + } while (t > 3); + for (; t; --t) + *this->op++ = *this->m_pos++; } - LABEL_48: - v5 = *(this->ip - 2) & 3; - if ((*(this->ip - 2) & 3) == 0) + LABEL_51: + t = *(this->ip - 2) & 3; + + if (!t) goto LABEL_5; + + LABEL_52: do { - LABEL_49: - *this->op = *this->ip; - v61 = this->ip + 1; - --v5; - ++this->op; - this->ip = v61; - } while (v5); - v7 = *v61; - this->ip = v61 + 1; + *this->op++ = *this->ip++; + --t; + } while (t); + + t = *this->ip++; } + *out_len = this->op - out; - v62 = this->ip; - ip_end = this->ip_end; - if (v62 == ip_end) + + if (this->ip == this->ip_end) return 0; - else - return (v62 < ip_end) - 2; + + if (this->ip >= this->ip_end) + return -2; + return -1; } static unsigned char in[ 0x40000 ]; From 0ce70b9f8f9c2da3cfd5994a9befc1fd95693a41 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 16:52:10 +0200 Subject: [PATCH 0417/2040] Improved/fixed archive support for big-endian platforms --- code/fgame/archive.cpp | 148 ++++++++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 39 deletions(-) diff --git a/code/fgame/archive.cpp b/code/fgame/archive.cpp index fbeb14aa..28b91b36 100644 --- a/code/fgame/archive.cpp +++ b/code/fgame/archive.cpp @@ -66,7 +66,7 @@ static const char *typenames[] = { "object", "objectpointer", "safepointer", "eventpointer", "quaternion", "entity", "bool", "position", "size"}; -#define ArchiveHeader (*(int *)"MHAA") +#define ArchiveHeader (LittleLong(*(int *)"MHAA")) #define ArchiveVersion 14 // This must be changed any time the format changes! #define ArchiveInfo "OPENMOHAA Archive Version 14" // This must be changed any time the format changes! @@ -208,6 +208,7 @@ qboolean ArchiveFile::OpenRead(const char *name) new_len = 0; Read(&new_len, sizeof(uint32_t)); + new_len = LittleLong(new_len); tempbuf = (byte *)gi.Malloc(new_len); if (g_lz77.Decompress(pos, length - 8, tempbuf, &iCSVGLength) || iCSVGLength != new_len) { @@ -487,11 +488,44 @@ File Archive functions //#define ARCHIVE_USE_TYPES 1 -#define ARCHIVE(func, type) \ - void Archiver::Archive##func(type *v) \ - \ - { \ - ArchiveData(ARC_##func, v, sizeof(type)); \ +template +void ArchiveSwapValue(v* value) { + LittleSwap(value, sizeof(v)); +} + +template +void ArchiveSwapValue(v* value, size_t size) { + for (size_t i = 0; i < size; i++) { + LittleSwap(&value[i], sizeof(value[i])); + } +} + +template<> +void ArchiveSwapValue(Vector* value) { + for (int i = 0; i < 3; i++) { + (*value)[i] = LittleFloat((*value)[i]); + } +} + +template<> +void ArchiveSwapValue(Quat* value) { + for (int i = 0; i < 4; i++) { + (*value)[i] = LittleFloat((*value)[i]); + } +} + +#define ARCHIVE(func, type) \ + void Archiver::Archive##func(type *v) \ + { \ + int i; \ + if (archivemode == ARCHIVE_WRITE) { \ + type nv = *v; \ + ArchiveSwapValue(&nv); \ + ArchiveData(ARC_##func, &nv, sizeof(type)); \ + } else { \ + ArchiveData(ARC_##func, v, sizeof(type)); \ + ArchiveSwapValue(v); \ + } \ } ARCHIVE(Vector, Vector); @@ -525,17 +559,41 @@ void Archiver::ArchiveSvsTime(int *time) void Archiver::ArchiveVec2(vec2_t vec) { - ArchiveData(ARC_Vec2, vec, sizeof(vec2_t)); + int i; + if (archivemode == ARCHIVE_WRITE) { + vec2_t nv = { vec[0], vec[1] }; + ArchiveSwapValue(nv, 2); + ArchiveData(ARC_Vec2, nv, sizeof(vec2_t)); + } else { + ArchiveData(ARC_Vec2, vec, sizeof(vec2_t)); + ArchiveSwapValue(vec, 2); + } } void Archiver::ArchiveVec3(vec3_t vec) { - ArchiveData(ARC_Vec3, vec, sizeof(vec3_t)); + int i; + if (archivemode == ARCHIVE_WRITE) { + vec3_t nv = { vec[0], vec[1], vec[2]}; + ArchiveSwapValue(nv, 3); + ArchiveData(ARC_Vec3, nv, sizeof(vec3_t)); + } else { + ArchiveData(ARC_Vec3, vec, sizeof(vec3_t)); + ArchiveSwapValue(vec, 3); + } } void Archiver::ArchiveVec4(vec4_t vec) { - ArchiveData(ARC_Vec4, vec, sizeof(vec4_t)); + int i; + if (archivemode == ARCHIVE_WRITE) { + vec4_t nv = { vec[0], vec[1], vec[2], vec[3] }; + ArchiveSwapValue(nv, 4); + ArchiveData(ARC_Vec4, nv, sizeof(vec4_t)); + } else { + ArchiveData(ARC_Vec4, vec, sizeof(vec4_t)); + ArchiveSwapValue(vec, 4); + } } void Archiver::ArchiveObjectPointer(LightClass **ptr) @@ -544,7 +602,9 @@ void Archiver::ArchiveObjectPointer(LightClass **ptr) if (archivemode == ARCHIVE_READ) { pointer_fixup_t *fixup; + ArchiveData(ARC_ObjectPointer, &index, sizeof(index)); + index = LittleLong(index); // // see if the variable was NULL @@ -567,6 +627,8 @@ void Archiver::ArchiveObjectPointer(LightClass **ptr) } else { index = ARCHIVE_NULL_POINTER; } + + index = LittleLong(index); ArchiveData(ARC_ObjectPointer, &index, sizeof(index)); } } @@ -577,7 +639,9 @@ void Archiver::ArchiveObjectPointer(Class **ptr) if (archivemode == ARCHIVE_READ) { pointer_fixup_t *fixup; + ArchiveData(ARC_ObjectPointer, &index, sizeof(index)); + index = LittleLong(index); // // see if the variable was NULL @@ -600,6 +664,8 @@ void Archiver::ArchiveObjectPointer(Class **ptr) } else { index = ARCHIVE_NULL_POINTER; } + + index = LittleLong(index); ArchiveData(ARC_ObjectPointer, &index, sizeof(index)); } } @@ -612,6 +678,7 @@ void Archiver::ArchiveSafePointer(SafePtrBase *ptr) pointer_fixup_t *fixup; ArchiveData(ARC_SafePointer, &index, sizeof(index)); + index = LittleLong(index); // // see if the variable was NULL @@ -638,6 +705,7 @@ void Archiver::ArchiveSafePointer(SafePtrBase *ptr) } else { index = ARCHIVE_NULL_POINTER; } + index = LittleLong(index); ArchiveData(ARC_SafePointer, &index, sizeof(index)); } } @@ -646,12 +714,13 @@ void Archiver::ArchiveEventPointer(Event **ev) { int index; +#ifdef ARCHIVE_USE_TYPES + CheckType(ARC_EventPointer); +#endif + if (archivemode == ARCHIVE_READ) { #ifndef NDEBUG CheckRead(); -#endif -#ifdef ARCHIVE_USE_TYPES - CheckType(ARC_EventPointer); #endif ArchiveInteger(&index); @@ -673,10 +742,6 @@ void Archiver::ArchiveEventPointer(Event **ev) index = ARCHIVE_NULL_POINTER; } -#ifdef ARCHIVE_USE_TYPES - WriteType(ARC_EventPointer); -#endif - ArchiveInteger(&index); if (*ev) { (*ev)->Archive(*this); @@ -691,6 +756,10 @@ void Archiver::ArchiveRaw(void *data, size_t size) void Archiver::ArchiveString(str *string) { +#ifdef ARCHIVE_USE_TYPES + CheckType(ARC_String); +#endif + if (archivemode == ARCHIVE_READ) { fileSize_t s; char *data; @@ -698,10 +767,6 @@ void Archiver::ArchiveString(str *string) #ifndef NDEBUG CheckRead(); #endif -#ifdef ARCHIVE_USE_TYPES - CheckType(ARC_String); -#endif - if (!fileerror) { s = ReadSize(); if (!fileerror) { @@ -719,13 +784,12 @@ void Archiver::ArchiveString(str *string) } } } else { + fileSize_t s; + #ifndef NDEBUG CheckWrite(); #endif -#ifdef ARCHIVE_USE_TYPES - WriteType(ARC_String); -#endif - WriteSize((fileSize_t)string->length()); + WriteSize(string->length()); archivefile.Write(string->c_str(), string->length()); } } @@ -1019,6 +1083,7 @@ fileSize_t Archiver::ReadSize(void) s = 0; if (!fileerror) { archivefile.Read(&s, sizeof(s)); + LittleSwap(&s, sizeof(s)); } return s; @@ -1039,6 +1104,7 @@ void Archiver::CheckSize(int type, fileSize_t size) void Archiver::WriteSize(fileSize_t size) { + LittleSwap(&size, sizeof(size)); archivefile.Write(&size, sizeof(fileSize_t)); } @@ -1048,6 +1114,7 @@ int Archiver::ReadType(void) if (!fileerror) { archivefile.Read(&t, sizeof(t)); + t = LittleLong(t); return t; } @@ -1066,29 +1133,35 @@ void Archiver::CheckType(int type) assert((type >= 0) && (type < ARC_NUMTYPES)); - if (!fileerror) { - t = ReadType(); - if (t != type) { - if (t < ARC_NUMTYPES) { - FileError("Expecting %s, Should be %s", typenames[type], typenames[t]); - assert(0); - } else { - FileError("Expecting %s, Should be %i (Unknown type)", typenames[type], t); + if (archivemode == ARCHIVE_READ) { + if (!fileerror) { + t = ReadType(); + if (t != type) { + if (t < ARC_NUMTYPES) { + FileError("Expecting %s, Should be %s", typenames[type], typenames[t]); + assert(0); + } + else { + FileError("Expecting %s, Should be %i (Unknown type)", typenames[type], t); + } } } + } else { + int nt = LittleLong(type); + archivefile.Write(&nt, sizeof(nt)); } } void Archiver::ArchiveData(int type, void *data, size_t size) { +#ifdef ARCHIVE_USE_TYPES + CheckType(type); +#endif + if (archivemode == ARCHIVE_READ) { #ifndef NDEBUG CheckRead(); #endif -#ifdef ARCHIVE_USE_TYPES - CheckType(type); -#endif - if (!fileerror && size) { m_iNumBytesIO += size; archivefile.Read(data, size); @@ -1097,9 +1170,6 @@ void Archiver::ArchiveData(int type, void *data, size_t size) #ifndef NDEBUG CheckWrite(); #endif -#ifdef ARCHIVE_USE_TYPES - WriteType(type); -#endif if (!fileerror && size) { m_iNumBytesIO += size; From cb59edc9630c957cba98d6d3976bffd8b2980059 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 16:56:42 +0200 Subject: [PATCH 0418/2040] Handle script exceptions in G_ServerSpawned --- code/fgame/g_main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index 83561eae..6e971646 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -360,7 +360,11 @@ Called when server finished initializating */ void G_ServerSpawned(void) { - level.ServerSpawned(); + try { + level.ServerSpawned(); + } catch (const ScriptException& e) { + G_ExitWithError(e.string.c_str()); + } } /* From 1fd238567edd9dfc826c32d15ed5fae053527050 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:55:57 +0200 Subject: [PATCH 0419/2040] Fixed animation loading endian --- code/skeletor/skeletor_loadanimation.cpp | 63 ++++++++++++++++-------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index c930a469..c1740af0 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -221,7 +221,7 @@ skelAnimDataGameHeader_t *EncodeFrames( skelAnimDataGameHeader_t * skeletor_c::ConvertSkelFileToGame(skelAnimDataFileHeader_t *pHeader, int iBuffLength, const char *path) { - int i; + int i, j; skelAnimFileFrame_t *pFileFrame; skelAnimGameFrame_t *pGameFrame; skelChannelName_t *pChannelNames; @@ -230,6 +230,9 @@ skeletor_c::ConvertSkelFileToGame(skelAnimDataFileHeader_t *pHeader, int iBuffLe skelAnimGameFrame_t *newFrame; int channelIndex; + static_assert(sizeof(skelAnimDataFileHeader_t) == 96, "Skeletor anim header size doesn't match!"); + static_assert(sizeof(skelAnimFileFrame_t) == 48, "Skeletor anim file frame size doesn't match!"); + if (pHeader->numFrames <= 0) { return NULL; } @@ -239,17 +242,30 @@ skeletor_c::ConvertSkelFileToGame(skelAnimDataFileHeader_t *pHeader, int iBuffLe newFrame = pGameFrame; for (i = 0; i < pHeader->numFrames; i++) { - newFrame->bounds[0] = pFileFrame->bounds[0]; - newFrame->bounds[1] = pFileFrame->bounds[1]; - newFrame->delta = pFileFrame->delta; - newFrame->angleDelta = pFileFrame->angleDelta; + vec4_t* pChannels; + + newFrame->bounds[0][0] = LittleFloat(pFileFrame->bounds[0][0]); + newFrame->bounds[0][1] = LittleFloat(pFileFrame->bounds[0][1]); + newFrame->bounds[1][2] = LittleFloat(pFileFrame->bounds[0][2]); + newFrame->bounds[1][0] = LittleFloat(pFileFrame->bounds[1][0]); + newFrame->bounds[1][1] = LittleFloat(pFileFrame->bounds[1][1]); + newFrame->bounds[1][2] = LittleFloat(pFileFrame->bounds[1][2]); + newFrame->delta[0] = LittleFloat(pFileFrame->delta[0]); + newFrame->delta[1] = LittleFloat(pFileFrame->delta[1]); + newFrame->delta[2] = LittleFloat(pFileFrame->delta[2]); + newFrame->angleDelta = LittleFloat(pFileFrame->angleDelta); + // + // Load channels + // newFrame->pChannels = new vec4_t[pHeader->numChannels]; - memcpy( - newFrame->pChannels, - (char *)pHeader - + (sizeof(vec4_t) * (3 * pHeader->numFrames - 3) + sizeof(vec4_t) * pHeader->numChannels * i + 96), - pHeader->numChannels * sizeof(vec4_t) - ); + pChannels = (vec4_t*)((byte*)pHeader + (sizeof(skelAnimDataFileHeader_t) + sizeof(skelAnimFileFrame_t) * (pHeader->numFrames - 1) + sizeof(vec4_t) * pHeader->numChannels * i)); + for (j = 0; j < pHeader->numChannels; j++) { + newFrame->pChannels[j][0] = LittleFloat(pChannels[j][0]); + newFrame->pChannels[j][1] = LittleFloat(pChannels[j][1]); + newFrame->pChannels[j][2] = LittleFloat(pChannels[j][2]); + newFrame->pChannels[j][3] = LittleFloat(pChannels[j][3]); + } + AddToBounds(newFrame->bounds, pFileFrame->bounds); pFileFrame++; @@ -376,10 +392,17 @@ void WriteEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) MSG_WriteShort(msg, pChannel->nFramesInChannel); for (j = 0; j < pChannel->nFramesInChannel; j++) { + vec3_t channelData; + pFrame = &pChannel->ary_frames[i]; MSG_WriteShort(msg, pFrame->nFrameNum); MSG_WriteShort(msg, pFrame->nPrevFrameIndex); - MSG_WriteData(msg, pFrame->pChannelData, sizeof(vec4_t)); + + channelData[0] = LittleFloat(pFrame->pChannelData[0]); + channelData[1] = LittleFloat(pFrame->pChannelData[1]); + channelData[2] = LittleFloat(pFrame->pChannelData[2]); + channelData[3] = LittleFloat(pFrame->pChannelData[3]); + MSG_WriteData(msg, channelData, sizeof(vec4_t)); } } @@ -433,10 +456,10 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->nPrevFrameIndex = MSG_ReadShort(msg); MSG_ReadData(msg, channelData, sizeof(vec4_t)); - pFrame->pChannelData[0] = channelData[0]; - pFrame->pChannelData[1] = channelData[1]; - pFrame->pChannelData[2] = channelData[2]; - pFrame->pChannelData[3] = channelData[3]; + pFrame->pChannelData[0] = LittleFloat(channelData[0]); + pFrame->pChannelData[1] = LittleFloat(channelData[1]); + pFrame->pChannelData[2] = LittleFloat(channelData[2]); + pFrame->pChannelData[3] = LittleFloat(channelData[3]); } break; case 1: @@ -452,9 +475,9 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->nPrevFrameIndex = MSG_ReadShort(msg); MSG_ReadData(msg, channelData, sizeof(vec4_t)); - pFrame->pChannelData[0] = channelData[0]; - pFrame->pChannelData[1] = channelData[1]; - pFrame->pChannelData[2] = channelData[2]; + pFrame->pChannelData[0] = LittleFloat(channelData[0]); + pFrame->pChannelData[1] = LittleFloat(channelData[1]); + pFrame->pChannelData[2] = LittleFloat(channelData[2]); } break; case 2: @@ -481,7 +504,7 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->nPrevFrameIndex = MSG_ReadShort(msg); MSG_ReadData(msg, channelData, sizeof(vec4_t)); - pFrame->pChannelData[0] = channelData[0]; + pFrame->pChannelData[0] = LittleFloat(channelData[0]); } break; } From 2b01f092b33e64aa414514aa01a48029dce17cb3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:23:06 +0200 Subject: [PATCH 0420/2040] Fixed german model always being set to `german_wehrmacht_soldier` --- code/fgame/player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 6b5a791d..59e79c2f 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -2430,8 +2430,8 @@ void Player::InitModel(void) if (g_gametype->integer == GT_SINGLE_PLAYER) { setModel("models/player/" + str(g_playermodel->string) + ".tik"); } else if (dm_team == TEAM_AXIS) { - if (Q_stricmpn(client->pers.dm_playermodel, "german", 6) - && Q_stricmpn(client->pers.dm_playermodel, "axis", 4) + if (Q_stricmpn(client->pers.dm_playergermanmodel, "german", 6) + && Q_stricmpn(client->pers.dm_playergermanmodel, "axis", 4) // // 2.30 models // From 8e0aa5185ba3cc5ce7d3b3f95af38ec15cc87800 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:40:03 +0200 Subject: [PATCH 0421/2040] Fixed CGM endianness --- code/server/sv_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 0be5e071..0cc0f1b4 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -203,11 +203,11 @@ static void MSG_WriteCGMBits (cgm_t *pCGM, int value, int bits) pCGM->cursize++; } else if(bits <= 16) { // append short (two bytes) - *((short*)(&pCGM->data[pCGM->cursize])) = LittleShort(value); + *((short*)(&pCGM->data[pCGM->cursize])) = value; pCGM->cursize+=2; } else if(bits <= 32) { // append integer (4 bytes) - *((int*)(&pCGM->data[pCGM->cursize])) = LittleLong(value); + *((int*)(&pCGM->data[pCGM->cursize])) = value; pCGM->cursize+=4; } // save datatype From 13c63d3e1f9c5789435b8701d173655957b40508 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:51:39 +0200 Subject: [PATCH 0422/2040] Fixed wrong condition with msg broadcast visibility --- code/server/sv_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_game.c b/code/server/sv_game.c index 0cc0f1b4..14df8cc3 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -491,7 +491,7 @@ void MSG_SetBroadcastVisible(const vec_t* vPos, const vec_t* vPosB) clientcluster = CM_LeafCluster(leafnum); clientpvs = CM_ClusterPVS(clientcluster); - if (CM_AreasConnected(clientarea, posarea) && (!vPosB || !CM_AreasConnected(clientarea, posBarea))) { + if (!CM_AreasConnected(clientarea, posarea) && (!vPosB || !CM_AreasConnected(clientarea, posBarea))) { continue; } From 618223f01be4d9f4ff2706d2090dcf6f60524670 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:32:15 +0200 Subject: [PATCH 0423/2040] Ignore NumShaders in protocol version 8 and below --- code/fgame/level.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/fgame/level.cpp b/code/fgame/level.cpp index f2bff60c..b0bbe7f4 100644 --- a/code/fgame/level.cpp +++ b/code/fgame/level.cpp @@ -2312,6 +2312,12 @@ void Level::EventRainShaderGet(Event *ev) void Level::EventRainNumShadersSet(Event *ev) { + if (g_protocol <= protocol_e::PROTOCOL_MOH) { + // There is a mistake in 1.11 and below where the NumShader event doesn't work + // Because the response points to EventRainShaderSet + return; + } + gi.setConfigstring(CS_RAIN_NUMSHADERS, ev->GetString(1)); } From 8b16e948298b40d2f953f45d297b3c4153af4593 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:56:19 +0200 Subject: [PATCH 0424/2040] Fixed grenade bounce sound overly playing --- code/fgame/weaputils.cpp | 86 +++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index f675709b..4e036956 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -1146,6 +1146,7 @@ void Projectile::Touch(Event *ev) // Bouncy Projectile if ((projFlags & P_BOUNCE_TOUCH)) { str snd; + int flags; if (level.time - fLastBounceTime < 0.1f) { fLastBounceTime = level.time; @@ -1157,49 +1158,60 @@ void Projectile::Touch(Event *ev) if (bouncesound_water.length()) { this->Sound(bouncesound_water, CHAN_BODY); } - } else { - if (bouncesound_metal.length()) { - snd = bouncesound_metal; - } else if (bouncesound_hard.length()) { - snd = bouncesound_hard; - } else { - snd = bouncesound; + + // + // Added in 2.30 + // + if (m_bDieInWater) { + PostEvent(EV_Remove, 0.5f); } - int flags = level.impact_trace.surfaceFlags; + return; + } - if (flags & SURF_MUD) { - if (bouncesound.length()) { - Sound(bouncesound, CHAN_BODY); - } - } else if (flags & SURF_ROCK) { - if (bouncesound_hard.length()) { - Sound(bouncesound_hard, CHAN_BODY); - } - } else if (flags & SURF_GRILL) { - if (bouncesound_metal.length()) { - Sound(bouncesound_metal, CHAN_BODY); - } - } else if (flags & SURF_WOOD) { - if (bouncesound_hard.length()) { - Sound(bouncesound_hard, CHAN_BODY); - } - } else if (flags & SURF_METAL) { - if (bouncesound_metal.length()) { - Sound(bouncesound_metal, CHAN_BODY); - } - } else if (flags & SURF_GLASS) { - if (bouncesound_hard.length()) { - Sound(bouncesound_hard, CHAN_BODY); - } - } else { - if (bouncesound.length()) { - Sound(bouncesound, CHAN_BODY); - } + if (bouncesound_metal.length()) { + snd = bouncesound_metal; + } else if (bouncesound_hard.length()) { + snd = bouncesound_hard; + } else { + snd = bouncesound; + } + + flags = level.impact_trace.surfaceFlags; + + if (flags & SURF_MUD) { + if (bouncesound.length()) { + Sound(bouncesound, CHAN_BODY); + } + } else if (flags & SURF_ROCK) { + if (bouncesound_hard.length()) { + Sound(bouncesound_hard, CHAN_BODY); + } + } else if (flags & SURF_GRILL) { + if (bouncesound_metal.length()) { + Sound(bouncesound_metal, CHAN_BODY); + } + } else if (flags & SURF_WOOD) { + if (bouncesound_hard.length()) { + Sound(bouncesound_hard, CHAN_BODY); + } + } else if (flags & SURF_METAL) { + if (bouncesound_metal.length()) { + Sound(bouncesound_metal, CHAN_BODY); + } + } else if (flags & SURF_GLASS) { + if (bouncesound_hard.length()) { + Sound(bouncesound_hard, CHAN_BODY); + } + } else { + if (bouncesound.length()) { + Sound(bouncesound, CHAN_BODY); } } BroadcastAIEvent(AI_EVENT_WEAPON_IMPACT); + fLastBounceTime = level.time; + return; } From e08b2fe382106be0e098e66cc38f0ed9f5be727c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 20:10:30 +0200 Subject: [PATCH 0425/2040] Added cg_target_game --- code/cgame/cg_local.h | 1 + code/cgame/cg_main.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 500e259c..b75a2131 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -431,6 +431,7 @@ extern "C" { extern cgs_t cgs; extern cg_t cg; extern clientGameImport_t cgi; + extern target_game_e cg_target_game; extern int cg_protocol; extern centity_t cg_entities[MAX_GENTITIES]; extern markPoly_t *cg_markPolys; diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 4a59a432..fe29dfcb 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -35,12 +35,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA clientGameImport_t cgi; static clientGameExport_t cge; -cvar_t *paused; -cvar_t *developer; -cg_t cg; -cgs_t cgs; -int cg_protocol; -centity_t cg_entities[MAX_GENTITIES]; +cvar_t *paused; +cvar_t *developer; +cg_t cg; +cgs_t cgs; +target_game_e cg_target_game = TG_INVALID; +int cg_protocol; +centity_t cg_entities[MAX_GENTITIES]; cvar_t *cg_animSpeed; cvar_t *cg_debugAnim; @@ -634,6 +635,8 @@ void CG_Init(clientGameImport_t *imported, int serverMessageNum, int serverComma cgi = *imported; cg_protocol = cgi.Cvar_Get("com_protocol", "", 0)->integer; + cg_target_game = (target_game_e)cgi.Cvar_Get("com_target_game", "0", 0)->integer; + CG_InitCGMessageAPI(&cge); CG_InitScoresAPI(&cge); From 8a28ad0c36e76ed6746772a8122d97feb0827df9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 9 Jun 2024 20:16:14 +0200 Subject: [PATCH 0426/2040] Fixed explosion effects on protocol below 2.0 --- code/cgame/cg_parsemsg.cpp | 77 +++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/code/cgame/cg_parsemsg.cpp b/code/cgame/cg_parsemsg.cpp index f9ff0397..5b261792 100644 --- a/code/cgame/cg_parsemsg.cpp +++ b/code/cgame/cg_parsemsg.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -1031,22 +1031,33 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) return; } - switch (iType) { - case 13: - iBaseEffect = SFX_EXP_GREN_BASE; - break; - case 14: - iBaseEffect = SFX_EXP_BAZOOKA_BASE; - break; - case 15: - iBaseEffect = SFX_EXP_HEAVYSHELL_BASE; - break; - case 16: - iBaseEffect = SFX_EXP_TANK_BASE; - break; - default: - iBaseEffect = SFX_EXP_GREN_BASE; - break; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + switch (iType) { + case 13: + iBaseEffect = SFX_EXP_GREN_BASE; + break; + case 14: + iBaseEffect = SFX_EXP_BAZOOKA_BASE; + break; + case 15: + iBaseEffect = SFX_EXP_HEAVYSHELL_BASE; + break; + case 16: + iBaseEffect = SFX_EXP_TANK_BASE; + break; + default: + iBaseEffect = SFX_EXP_GREN_BASE; + break; + } + } else { + switch (iType) { + case 13: + iBaseEffect = SFX_EXP_BAZOOKA_BASE; + break; + default: + iBaseEffect = SFX_EXP_GREN_BASE; + break; + } } CG_Trace( @@ -1074,14 +1085,18 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) break; case SFX_EXP_BAZOOKA_BASE: iSurfEffect = SFX_EXP_BAZOOKA_SNOW; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; case SFX_EXP_HEAVYSHELL_BASE: iSurfEffect = SFX_EXP_HEAVYSHELL_SNOW; break; default: iSurfEffect = SFX_EXP_GREN_SNOW; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; } fRadius = 0; @@ -1115,14 +1130,18 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) break; case SFX_EXP_BAZOOKA_BASE: iSurfEffect = SFX_EXP_BAZOOKA_DIRT; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; case SFX_EXP_HEAVYSHELL_BASE: iSurfEffect = SFX_EXP_HEAVYSHELL_DIRT; break; default: iSurfEffect = SFX_EXP_GREN_DIRT; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; } fRadius = 0; @@ -1144,7 +1163,9 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) break; default: iSurfEffect = SFX_EXP_GREN_GRASS; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; } fRadius = 0; @@ -1156,14 +1177,18 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) break; case SFX_EXP_BAZOOKA_BASE: iSurfEffect = SFX_EXP_BAZOOKA_STONE; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; case SFX_EXP_HEAVYSHELL_BASE: iSurfEffect = SFX_EXP_HEAVYSHELL_STONE; break; default: iSurfEffect = SFX_EXP_GREN_STONE; - iBaseEffect = -1; + if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + iBaseEffect = -1; + } break; } break; @@ -1211,7 +1236,9 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) ); } - sfxManager.MakeEffect_Normal(iBaseEffect, vEnd, trace.plane.normal); + if (iBaseEffect != -1) { + sfxManager.MakeEffect_Normal(iBaseEffect, vEnd, trace.plane.normal); + } } void CG_MakeVehicleEffect(vec3_t i_vStart, vec3_t i_vEnd, vec3_t i_vDir) From 4da5e26cdcc3f491db3d3266e56233734de12c61 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 13:59:10 +0200 Subject: [PATCH 0427/2040] Move CTRL macro to q_shared.h --- code/qcommon/q_shared.h | 3 +++ code/sdl/sdl_input.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index c053806c..ff792ed9 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -1188,6 +1188,9 @@ typedef enum { //============================================= +// get the control character for the given key (moved from sdl_input.c) +#define CTRL(a) ((a)-'a'+1) + int Q_isprint( int c ); int Q_islower( int c ); int Q_isupper( int c ); diff --git a/code/sdl/sdl_input.c b/code/sdl/sdl_input.c index 33979c2d..db10b914 100644 --- a/code/sdl/sdl_input.c +++ b/code/sdl/sdl_input.c @@ -59,8 +59,6 @@ static int in_eventTime = 0; static SDL_Window *SDL_window = NULL; -#define CTRL(a) ((a)-'a'+1) - /* =============== IN_PrintKey From 9a35d34fc326c60434411470480a1d7e30e95baf Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:02:10 +0200 Subject: [PATCH 0428/2040] Implement UINotepad Also fix several original game bugs within, some cosmetical, some memory corrupting --- code/uilib/uinotepad.cpp | 746 ++++++++++++++++++++++++++++++--------- code/uilib/uinotepad.h | 4 +- 2 files changed, 587 insertions(+), 163 deletions(-) diff --git a/code/uilib/uinotepad.cpp b/code/uilib/uinotepad.cpp index 22abf163..0e375cb5 100644 --- a/code/uilib/uinotepad.cpp +++ b/code/uilib/uinotepad.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -22,245 +22,667 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "ui_local.h" -CLASS_DECLARATION( UIMultiLineEdit, UINotepadEdit, NULL ) -{ - { NULL, NULL } +Event EV_Notepad_SaveAs +( + "_notepad_saveas", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Save As..." +); + +Event EV_Notepad_Save +( + "_notepad_save", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Save" +); + +Event EV_Notepad_Open +( + "_notepad_open", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Open" +); + +Event EV_Notepad_OpenFile +( + "openfile", + EV_DEFAULT, + "s", + "nameOfFile", + "called to open a file in the notepad" +); + +Event EV_Notepad_Find +( + "_notepad_find", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Find" +); + +Event EV_Notepad_Goto +( + "_notepad_goto", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Go to line" +); + +Event EV_Notepad_Copy +( + "_notepad_copy", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Copy" +); + +Event EV_Notepad_Cut +( + "_notepad_cut", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Cut" +); + +Event EV_Notepad_Paste +( + "_notepad_paste", + EV_DEFAULT, + NULL, + NULL, + "Event sent when user selected Paste" +); + +Event W_Notepad_ChildSizeChanged +( + "_notepad_childsizechanged", + EV_DEFAULT, + NULL, + NULL, + "Signal that the child area of the floating window has changed" +); + +CLASS_DECLARATION(UIMultiLineEdit, UINotepadEdit, NULL) { + {&W_LeftMouseDown, &UINotepadEdit::MousePressed}, + {NULL, NULL } }; -bool UI_LoadNotepadFile( const char *filename ) +CLASS_DECLARATION(UIFloatingWindow, UINotepad, NULL) { + {&W_Notepad_ChildSizeChanged, &UINotepad::ChildSizeChanged}, + {&EV_Notepad_SaveAs, &UINotepad::SaveAs }, + {&EV_Notepad_Save, &UINotepad::Save }, + {&EV_Notepad_Open, &UINotepad::Open }, + {&EV_Notepad_OpenFile, &UINotepad::OpenFile }, + {&UIFloatingWindow::W_ClosePressed, &UINotepad::ClosePressed }, + {&EV_Notepad_Find, &UINotepad::OnFind }, + {&EV_Notepad_Goto, &UINotepad::OnGoto }, + {&EV_Notepad_Copy, &UINotepad::OnCopy }, + {&EV_Notepad_Paste, &UINotepad::OnPaste }, + {&EV_Notepad_Cut, &UINotepad::OnCut }, + {NULL, NULL } +}; + +#define CTRL_EVENT_COUNT 10 +static ctrlevent_s controlEvents[CTRL_EVENT_COUNT] = { + {'o', &EV_Notepad_Open }, + {'s', &EV_Notepad_Save }, + {'a', &EV_Notepad_SaveAs }, + {'w', &UIFloatingWindow::W_ClosePressed}, + {'f', &EV_Notepad_Find }, + {'g', &EV_Notepad_Goto }, + {'c', &EV_Notepad_Copy }, + {'x', &EV_Notepad_Cut }, + {'v', &EV_Notepad_Paste }, + {NULL, NULL }, +}; + +bool UI_LoadNotepadFile(const char *filename) { - return false; + UINotepad *uinp = new UINotepad(); + if (uinp->Create(NULL, UIRect2D(100.0f, 100.0f, 450.0f, 300.0f), filename)) { + uWinMan.ActivateControl(uinp); + return true; + } + + if (uinp) { + delete uinp; + } + + return false; } UINotepadEdit::UINotepadEdit() { - // FIXME: stub + m_notepad = NULL; } -void UINotepadEdit::CharEvent - ( - int ch - ) - +void UINotepadEdit::CharEvent(int ch) { - // FIXME: stub + if (!m_notepad->ProcessCharEvent(ch)) { + UIMultiLineEdit::CharEvent(ch); + } } -void UINotepadEdit::setNotepad - ( - UINotepad *notepad - ) - +void UINotepadEdit::setNotepad(UINotepad *notepad) { - // FIXME: stub + m_notepad = notepad; } -bool UINotepadEdit::GotoLine - ( - int line - ) - +bool UINotepadEdit::GotoLine(int line) { - // FIXME: stub - return false; + if (line < 1 || line - 1 >= m_lines.getCount()) { + return false; + } + + m_selection.begin.line = m_selection.end.line = line - 1; + m_selection.begin.column = 0; + m_selection.end.column = 999999; + BoundSelectionPoint(m_selection.end); + EnsureSelectionPointVisible(m_selection.end); + return true; } -bool UINotepadEdit::FindText - ( - const char *text, - int offsetFromSel - ) - +bool UINotepadEdit::FindText(const char *text, int offsetFromSel) { - // FIXME: stub - return false; + if (!text) { + return false; + } + + str lowersearch = text; + lowersearch.tolower(); + + selectionpoint_s *topsel, *botsel; + SortSelection(&topsel, &botsel); + + int foundat = -1; + bool searchfromtop = false; + + // This loop runs at most twice: + // - once for searchfromtop == false, + // - optionally for searchfromtop == true, + // but only if text couldn't be found between the cursor and the end of the file + while (true) { + int i = 0; + m_lines.IterateFromHead(); + for (; m_lines.IsCurrentValid(); i++, m_lines.IterateNext()) { + if (i < topsel->line && !searchfromtop) { + // skip lines before the cursor if not searching from the top + continue; + } + if (i > topsel->line && searchfromtop) { + // no need to continue if we've looped back to the cursor + return false; + } + + str findin = m_lines.getCurrent(); + findin.tolower(); + const char *where = findin.c_str(); + + // Added in OPM to avoid code repetition + bool searchLineFromCursor = i == topsel->line && !searchfromtop; + if (searchLineFromCursor) { + // Start searching on the current line, BUT ONLY from the cursor position. + // Offset it with the selection offset: + // the purpose of this is to prevent matching + // on a string that was just found and is still selected, + // by offsetting it + if (findin.length() <= topsel->column + offsetFromSel) { + // cursor is at the end of the line, nothing left to search in this one + continue; + } + + where = &where[topsel->column + offsetFromSel]; + } + + const char *found = strstr(where, lowersearch); + + if (found) { + // use the beginning of the line to calculate where the matched text is + foundat = found - where; + if (searchLineFromCursor) { + // take cursor pos. into account if a match is found on the same line as the cursor + foundat += topsel->column + offsetFromSel; + } + break; + } + } + + if (foundat == -1) { + // couldn't find text in current search iteration + if (!searchfromtop) { + // try searching from the beginning of the document + searchfromtop = true; + continue; + } + + // text not found + return false; + } else { + // jump to found text and select it + m_selection.begin.column = foundat; + m_selection.end.column = foundat + strlen(text); + m_selection.begin.line = m_selection.end.line = i; + EnsureSelectionPointVisible(m_selection.end); + return true; + } + } } -void UINotepadEdit::MousePressed - ( - Event *ev - ) - +void UINotepadEdit::MousePressed(Event *ev) { - // FIXME: stub + if (m_notepad->m_state != STATE_TIMED_MESSAGE) { + m_notepad->m_state = STATE_NONE; + } + + UIMultiLineEdit::MouseDown(ev); } -CLASS_DECLARATION( UIFloatingWindow, UINotepad, NULL ) -{ - { NULL, NULL } -}; - - UINotepad::UINotepad() { - // FIXME: stub + m_state = STATE_NONE; + m_edit = NULL; + m_menu = NULL; + m_status = NULL; } -void UINotepad::TimeMessage - ( - const char *message, - int howlong - ) - +UINotepad::~UINotepad() { - // FIXME: stub + for (int i = m_popups.NumObjects(); i > 0; i--) { + Container *inner = m_popups.ObjectAt(i); + for (int j = inner->NumObjects(); j > 0; j--) { + uipopup_describe *uipd = inner->ObjectAt(j); + inner->RemoveObjectAt(j); + // NOTE: `delete uipd` is intentionally missing here! + // Since uipds created for this class have data fields + // that contain pointers only to static Event objects, + // the fields don't need to be cleaned up as they weren't + // dynamically allocated in the first place. + // See UINotepad::Create for reference. + // However, FIXME: the uipds themselves should still + // get cleaned up, but that doesn't happen yet. + } + } } -bool UINotepad::OpenFile - ( - const char *filename - ) - +void UINotepad::TimeMessage(const char *message, int howlong) { - // FIXME: stub - return false; + m_state = STATE_TIMED_MESSAGE; + m_timedmessage.die = uid.time + howlong; + m_timedmessage.text = message; } -bool UINotepad::Create - ( - UIWidget *parent, - UIRect2D& rect, - const char *filename - ) - +bool UINotepad::OpenFile(const char *filename) { - // FIXME: stub - return false; + char *data = NULL; + if (!filename || FS_ReadFile(filename, (void **)&data) == -1) { + return false; + } + + setFileName(filename); + if (m_edit) { + m_edit->Empty(); + m_edit->setData(data); + } + + FS_FreeFile(data); + return true; } -void UINotepad::ChildSizeChanged - ( - Event *ev - ) - +bool UINotepad::Create(UIWidget *parent, UIRect2D& rect, const char *filename) { - // FIXME: stub + UIFloatingWindow::Create(parent, rect, "", UColor(0.15f, 0.196f, 0.278f), UHudColor); + + m_edit = new UINotepadEdit(); + m_edit->setNotepad(this); + + m_edit->InitFrame(getChildSpace(), 0.0f, 0.0f, 20.0f, 20.0f, 0, "verdana-12"); + m_edit->setBackgroundColor(UWhite, true); + m_edit->setForegroundColor(UBlack); + m_edit->setFont("verdana-14"); + + m_status = new UIStatusBar(WND_ALIGN_BOTTOM, 20.0f); + m_status->InitFrame(getChildSpace(), 0.0f, 0.0f, 20.0f, 20.0f, 0, "verdana-12"); + m_status->EnableSizeBox(this); + + m_menu = new UIPulldownMenu(); + m_menu->CreateAligned(getChildSpace(), this); + // Fixed in OPM: menu text was hard to read when notepad is active + //m_menu->setForegroundColor(UBlack); + m_menu->setForegroundColor(UHudColor); + + Container *pops = new Container(); + + uipopup_describe *uipd = new uipopup_describe("Open (Ctrl-O)", UIP_EVENT, &EV_Notepad_Open, NULL); + pops->AddObject(uipd); + uipd = new uipopup_describe("Save (Ctrl-S)", UIP_EVENT, &EV_Notepad_Save, NULL); + pops->AddObject(uipd); + uipd = new uipopup_describe("Save As...(Ctrl-A)", UIP_EVENT, &EV_Notepad_SaveAs, NULL); + pops->AddObject(uipd); + + uipd = new uipopup_describe(NULL, UIP_SEPARATOR, NULL, NULL); + pops->AddObject(uipd); + + uipd = new uipopup_describe("Close (Ctrl-W)", UIP_EVENT, &UIFloatingWindow::W_ClosePressed, NULL); + pops->AddObject(uipd); + + m_popups.AddObject(pops); + for (int i = 1; i <= pops->NumObjects(); i++) { + m_menu->AddUIPopupDescribe("File", pops->ObjectAt(i)); + } + + pops = new Container(); + uipd = new uipopup_describe("Copy (Ctrl-C)", UIP_EVENT, &EV_Notepad_Copy, NULL); + pops->AddObject(uipd); + uipd = new uipopup_describe("Cut (Ctrl-X)", UIP_EVENT, &EV_Notepad_Cut, NULL); + pops->AddObject(uipd); + uipd = new uipopup_describe("Paste (Ctrl-V)", UIP_EVENT, &EV_Notepad_Paste, NULL); + pops->AddObject(uipd); + + uipd = new uipopup_describe(NULL, UIP_SEPARATOR, NULL, NULL); + pops->AddObject(uipd); + + uipd = new uipopup_describe("Find (Ctrl-F)", UIP_EVENT, &EV_Notepad_Find, NULL); + pops->AddObject(uipd); + uipd = new uipopup_describe("Go to line... (Ctrl-G)", UIP_EVENT, &EV_Notepad_Goto, NULL); + pops->AddObject(uipd); + + m_popups.AddObject(pops); + for (int i = 1; i <= pops->NumObjects(); i++) { + m_menu->AddUIPopupDescribe("Edit", pops->ObjectAt(i)); + } + + setFileName(""); + OpenFile(filename); + getChildSpace()->Connect(this, W_SizeChanged, W_Notepad_ChildSizeChanged); + getChildSpace()->SendSignal(W_SizeChanged); + getChildSpace()->AllowActivate(false); + return true; } -void UINotepad::SaveAs - ( - Event *ev - ) - +void UINotepad::ChildSizeChanged(Event *ev) { - // FIXME: stub + m_menu->Realign(); + UISize2D menuSize = m_menu->getSize(); + UISize2D childSpaceSize = getChildSpace()->getSize(); + + UIRect2D frame(0.0f, menuSize.height, childSpaceSize.width, childSpaceSize.height - 20.0f - menuSize.height); + + m_edit->setFrame(frame); } -void UINotepad::Save - ( - Event *ev - ) - +void UINotepad::SaveAs(Event *ev) { - // FIXME: stub + m_state = STATE_SAVE_AS; + m_textinput.text = ""; } -void UINotepad::Open - ( - Event *ev - ) - +void UINotepad::Save(Event *ev) { - // FIXME: stub + if (!m_filename.length()) { + SaveAs(NULL); + } + + str filecontents; + m_edit->getData(filecontents); + m_edit->setChanged(false); + + // FIXME: m_filename could be blank + FS_WriteTextFile(m_filename, filecontents, filecontents.length()); + + str result = "Saved " + m_filename; + TimeMessage(result, 3000); } -void UINotepad::OpenFile - ( - Event *ev - ) - +void UINotepad::Open(Event *ev) { - // FIXME: stub + PickFile(m_filename, this, EV_Notepad_OpenFile); } -void UINotepad::ClosePressed - ( - Event *ev - ) - +void UINotepad::OpenFile(Event *ev) { - // FIXME: stub + OpenFile(ev->GetString(1)); } -void UINotepad::OnFind - ( - Event *ev - ) - +void UINotepad::ClosePressed(Event *ev) { - // FIXME: stub + uWinMan.ActivateControl(this); + if (m_edit->IsChanged()) { + m_state = STATE_CONFIRMCLOSE; + m_textinput.text = "y"; + } else { + PostEvent(EV_Remove, 0.0f); + + // Fixed in OPM: + // in the original game, the control is not deactivated after removal, + // so the already heap-freed UINotepad instance still "reacts" to + // KeyEvents and CharEvents, creating a use-after-free scenario + // that causes crashes when debug heap is enabled + uWinMan.DeactivateCurrentControl(); + } } -void UINotepad::OnGoto - ( - Event *ev - ) - +void UINotepad::OnFind(Event *ev) { - // FIXME: stub + m_state = STATE_FIND_TEXT; + m_textinput.text = m_lastfind; } -void UINotepad::OnCopy - ( - Event *ev - ) - +void UINotepad::OnGoto(Event *ev) { - // FIXME: stub + m_state = STATE_GOTO_LINE; + m_textinput.text = ""; } -void UINotepad::OnPaste - ( - Event *ev - ) - +void UINotepad::OnCopy(Event *ev) { - // FIXME: stub + m_edit->CopySelection(); } -void UINotepad::OnCut - ( - Event *ev - ) - +void UINotepad::OnPaste(Event *ev) { - // FIXME: stub + m_edit->PasteSelection(); } -bool UINotepad::ProcessControlEvents - ( - int ch - ) - +void UINotepad::OnCut(Event *ev) { - // FIXME: stub - return false; + m_edit->CopySelection(); + m_edit->DeleteSelection(); } -bool UINotepad::ProcessCharEvent - ( - int ch - ) - +bool UINotepad::ProcessControlEvents(int ch) { - // FIXME: stub - return false; + if (ch < CTRL('a') || ch > CTRL('z')) { + // not a control character + return false; + } + + // Fixed in OPM: + // Original code didn't bounds-check controlEvents + for (int i = 0; i < CTRL_EVENT_COUNT; i++) { + ctrlevent_s *event = &controlEvents[i]; + if (!event->ev) { + // no event assigned + return false; + } + + if (ch == CTRL(event->ch)) { + // found it + PostEvent( + new Event(*event->ev), 0.0f + ); // create a new Event as it will be deleted by ProcessEvent in L_ProcessPendingEvents + return true; + } + } + + return false; } -void UINotepad::Draw - ( - void - ) - +bool UINotepad::ProcessCharEvent(int ch) { - // FIXME: stub + if (ProcessControlEvents(ch)) { + return true; + } + + if (m_state == STATE_NONE || m_state == STATE_TIMED_MESSAGE) { + return false; + } + + str text; + switch (ch) { + case '\b': // Backspace + m_textinput.text.CapLength(m_textinput.text.length() - 1); + break; + case K_ENTER: + switch (m_state) { + case STATE_GOTO_LINE: + { + if (!m_textinput.text.length()) { + m_state = STATE_NONE; + return true; + } + + int line = atoi(m_textinput.text); + if (m_edit->GotoLine(line)) { + m_state = STATE_NONE; + return true; + } + + text = "Line '" + m_textinput.text + "' doesn't exist."; + TimeMessage(text, 3000); + break; + } + case STATE_FIND_TEXT: + if (!m_textinput.text.length()) { + m_state = STATE_NONE; + return true; + } + + if (!m_edit->FindText(m_textinput.text, 1)) { + text = "Text: '" + m_textinput.text + "' could not be found."; + TimeMessage(text, 3000); + } + + m_lastfind = m_textinput.text; + return true; + case STATE_SAVE_AS: + m_state = STATE_NONE; + + if (!m_textinput.text.length()) { + return true; + } + + setFileName(m_textinput.text); + Save(NULL); + return true; + case STATE_CONFIRMCLOSE: + { + m_state = STATE_NONE; + + if (!m_textinput.text.length()) { + return true; + } + + char choice = tolower(m_textinput.text[0]); + if (choice != 'n' && choice != 'y') { + return true; + } + + if (choice == 'y') { + Save(NULL); + } + + // close window + PostEvent(new Event(EV_Remove), 0.0f); + + // Fixed in OPM: + // in the original game, the control is not deactivated after removal, + // so the already heap-freed UINotepad instance still "reacts" to + // KeyEvents and CharEvents, creating a use-after-free scenario, + // causing crashes when debug heap is enabled + uWinMan.DeactivateCurrentControl(); + + return true; + } + default: + m_state = STATE_NONE; + return true; + } + return true; + case K_ESCAPE: + case K_TAB: + m_state = STATE_NONE; + return true; + } + + if (!isprint(ch)) { + return true; + } + + if (m_state == STATE_CONFIRMCLOSE) { + m_textinput.text = ""; + } + + m_textinput.text += (char)ch; + return true; } -void UINotepad::setFileName - ( - const char *filename - ) - +void UINotepad::Draw(void) { - // FIXME: stub + UColor out = URed; + out.ScaleColor(0.5f); + out.ScaleAlpha(0.5f); + + m_status->setBackgroundColor(out, true); + m_status->setForegroundColor(UHudColor); + + str text; + switch (m_state) { + case STATE_GOTO_LINE: + text = "Goto line (tab cancels): " + m_textinput.text; + break; + case STATE_FIND_TEXT: + text = "Find text (tab cancels): " + m_textinput.text; + break; + case STATE_SAVE_AS: + text = "Save As (tab cancels): " + m_textinput.text; + break; + case STATE_CONFIRMCLOSE: + text = "Save " + m_filename + "? (yes/no/cancel) " + m_textinput.text; + break; + case STATE_TIMED_MESSAGE: + if (uid.time > m_timedmessage.die) { + m_state = STATE_NONE; + default: + m_status->setBackgroundColor(getBackgroundColor(), true); + m_status->setForegroundColor(getForegroundColor()); // Fixed in OPM + m_menu->setForegroundColor(getForegroundColor()); // Fixed in OPM + UIPoint2D selpoint = m_edit->getEndSelPoint(); + text = va("Line %d, column %d", (int)selpoint.y + 1, (int)selpoint.x + 1); + } else { + m_status->setBackgroundColor(getBackgroundColor(), true); + m_status->setForegroundColor(URed); + text = m_timedmessage.text; + } + break; + } + + m_status->setTitle(text); + UIFloatingWindow::Draw(); +} + +void UINotepad::setFileName(const char *filename) +{ + str text = str(filename) + " - Notepad"; + setTitle(text); + m_filename = filename; } diff --git a/code/uilib/uinotepad.h b/code/uilib/uinotepad.h index 7075130d..1d2c90e9 100644 --- a/code/uilib/uinotepad.h +++ b/code/uilib/uinotepad.h @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -59,6 +59,7 @@ typedef struct ctrlevent_s { } ctrlevent_t; class UINotepad : public UIFloatingWindow { + friend class UINotepadEdit; // UINotepadEdit needs m_state private: Container *> m_popups; @@ -80,6 +81,7 @@ protected: public: UINotepad(); + ~UINotepad(); bool OpenFile( const char *filename ); bool Create( UIWidget *parent, UIRect2D& rect, const char *filename ); From 3254b3f0447f2f9370a31b0a016cc3ce71e527b7 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:04:55 +0200 Subject: [PATCH 0429/2040] Send SE_CHAR events (CharEvent) for ENTER, TAB and ESCAPE keys So that UINotepad registers them as valid keypresses when typing --- code/sdl/sdl_input.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/sdl/sdl_input.c b/code/sdl/sdl_input.c index db10b914..829363de 100644 --- a/code/sdl/sdl_input.c +++ b/code/sdl/sdl_input.c @@ -1016,6 +1016,8 @@ static void IN_ProcessEvents( void ) if( key == K_BACKSPACE ) Com_QueueEvent( in_eventTime, SE_CHAR, CTRL('h'), 0, 0, NULL ); + else if (key == K_ENTER || key == K_TAB || key == K_ESCAPE) // mostly used by UINotepad + Com_QueueEvent( in_eventTime, SE_CHAR, key, 0, 0, NULL); else if( keys[K_CTRL].down && key >= 'a' && key <= 'z' ) Com_QueueEvent( in_eventTime, SE_CHAR, CTRL(key), 0, 0, NULL ); From c60c2c09e18ab1f27c3682b7854cbccbbf38005b Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:06:30 +0200 Subject: [PATCH 0430/2040] Fix incorrect TAB character width calculation and refactor logic --- code/uilib/uifont.cpp | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/code/uilib/uifont.cpp b/code/uilib/uifont.cpp index 4bfeee3b..89192f2b 100644 --- a/code/uilib/uifont.cpp +++ b/code/uilib/uifont.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -500,6 +500,7 @@ int UIFont::getCharWidth(unsigned short ch) { int index; int indirected; + float widthMul = 1.0f; // Added in OPM for easier readability if (!m_font) { return 0; @@ -507,6 +508,7 @@ int UIFont::getCharWidth(unsigned short ch) if (ch == '\t') { ch = ' '; + widthMul = 3.0f; } if (m_font->numPages) { @@ -526,11 +528,7 @@ int UIFont::getCharWidth(unsigned short ch) index = 0; } - if (ch == '\t') { - return m_font->sgl[index]->locations[indirected].size[0] * 256.0 * 3.0; - } else { - return m_font->sgl[index]->locations[indirected].size[0] * 256.0; - } + return m_font->sgl[index]->locations[indirected].size[0] * 256.0 * widthMul; } int UIFont::getHeight(const char *text, int maxlen, qboolean bVirtual) @@ -631,6 +629,7 @@ float UI_FontgetCharWidthf(fontheader_t *font, unsigned short uch) { int index; int indirected; + float widthMul = 1.0f; // Added in OPM for easier readability if (!font) { return 0.f; @@ -638,6 +637,7 @@ float UI_FontgetCharWidthf(fontheader_t *font, unsigned short uch) if (uch == '\t') { uch = ' '; + widthMul = 3.0f; } if (font->numPages) { @@ -657,11 +657,7 @@ float UI_FontgetCharWidthf(fontheader_t *font, unsigned short uch) index = 0; } - if (uch == '\t') { - return font->sgl[index]->locations[indirected].size[0] * 3.0; - } else { - return font->sgl[index]->locations[indirected].size[0]; - } + return font->sgl[index]->locations[indirected].size[0] * widthMul; } int UI_FontStringMaxWidth(fontheader_t *pFont, const char *pszString, int iMaxLen) @@ -674,13 +670,8 @@ int UI_FontStringMaxWidth(fontheader_t *pFont, const char *pszString, int iMaxLe return 0; } - i = 0; - for (;;) { - unsigned short uch = pszString[i++]; - - if (uch == 0 || (iMaxLen != -1 && i > iMaxLen)) { - break; - } + for (int i = 0; pszString[i] && (iMaxLen == -1 || i < iMaxLen); i++) { + unsigned short uch = pszString[i]; if (UI_FontDBCSIsLeadByte(pFont, uch)) { uch = (uch << 8) | pszString[i]; @@ -709,19 +700,13 @@ int UI_FontStringWidth(fontheader_t *pFont, const char *pszString, int iMaxLen) { float widths = 0.0; float maxwidths = 0.0; - int i; if (!pFont) { return 0; } - i = 0; - for (;;) { - unsigned short uch = pszString[i++]; - - if (uch == 0 || (iMaxLen != -1 && i > iMaxLen)) { - break; - } + for (int i = 0; pszString[i] && (iMaxLen == -1 || i < iMaxLen); i++) { + unsigned short uch = pszString[i]; if (UI_FontDBCSIsLeadByte(pFont, uch)) { uch = (uch << 8) | pszString[i]; From 849f1ee7d1456e3f445a45b80a7e232c6660a59e Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:13:21 +0200 Subject: [PATCH 0431/2040] Fix several bugs in UIMultiLineEdit These are necessary so that UINotepad can actually be used for editing text --- code/uilib/uimledit.cpp | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/code/uilib/uimledit.cpp b/code/uilib/uimledit.cpp index 8bda5646..efc13c1e 100644 --- a/code/uilib/uimledit.cpp +++ b/code/uilib/uimledit.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -103,10 +103,10 @@ void UIMultiLineEdit::setData(const char *data) toadd = ""; } else if (*p == '\r') { continue; + } else { + s[0] = *p; + toadd += s; } - - s[0] = *p; - toadd += s; } m_lines.AddTail(toadd); @@ -146,7 +146,7 @@ void UIMultiLineEdit::FrameInitialized(void) m_vertscroll->InitFrameAlignRight(this, 0, 0); Connect(this, W_SizeChanged, W_SizeChanged); - AllowActivate(false); + AllowActivate(true); } void UIMultiLineEdit::SizeChanged(Event *ev) @@ -266,7 +266,13 @@ void UIMultiLineEdit::Draw(void) if (cur.length() != botsel->column) { m_font->setColor(m_foreground_color); - m_font->Print(botlen, aty, &cur[botsel->column], m_bVirtual, false); + + // Fixed in OPM: + // highlighting text made the rest of the text after the selection on the line disappear. + // Cause: the last two arguments were incorrectly passed in originally, + // always specifying maxlen as m_bVirtual (which is usually zero). + // m_font->Print(botlen, aty, &cur[botsel->column], m_bVirtual, false); + m_font->Print(botlen, aty, &cur[botsel->column], -1, m_bVirtual); } caret = botlen; @@ -438,10 +444,12 @@ qboolean UIMultiLineEdit::KeyEvent(int key, unsigned int time) case K_UPARROW: m_selection.end.line--; caret_moved = true; + key_rec = true; break; case K_DOWNARROW: m_selection.end.line++; caret_moved = true; + key_rec = true; break; case K_LEFTARROW: m_selection.end.column--; @@ -485,16 +493,21 @@ qboolean UIMultiLineEdit::KeyEvent(int key, unsigned int time) } break; case K_DEL: + // Fixed in OPM: + // DEL key needed to be pressed twice to delete a single character, + // as the first hit would only create an "internal" selection, + // but wouldn't actually delete the character after the cursor. + // The DeleteSelection() method should ALWAYS be called, + // not only when there's an active selection. if (IsSelectionEmpty()) { m_shiftForcedDown = true; KeyEvent(K_RIGHTARROW, 0); m_shiftForcedDown = false; } else if (uii.Sys_IsKeyDown(K_SHIFT)) { CopySelection(); - DeleteSelection(); - } else { - DeleteSelection(); } + + DeleteSelection(); break; case K_PGDN: if (m_selection.end.line == (m_vertscroll->getTopItem() + m_vertscroll->getPageHeight() - 1)) { @@ -584,6 +597,7 @@ void UIMultiLineEdit::DeleteSelection(void) line.CapLength(newlen); *botsel = *topsel; EnsureSelectionPointVisible(*topsel); + return; } else if (botsel->line - topsel->line > 1) { for (i = 0, m_lines.IterateFromHead(); m_lines.IsCurrentValid() && i < topsel->line; i++, m_lines.IterateNext()) { From a19c7afce0d86a99a31ad4a79114bf4cee201a09 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:15:06 +0200 Subject: [PATCH 0432/2040] Add placeholders for handling clipboard operations in UIMultiLineEdit Actual clipboard functionality will be added later --- code/uilib/uimledit.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/code/uilib/uimledit.cpp b/code/uilib/uimledit.cpp index efc13c1e..a3ac0823 100644 --- a/code/uilib/uimledit.cpp +++ b/code/uilib/uimledit.cpp @@ -708,6 +708,9 @@ void UIMultiLineEdit::CopySelection(void) line.CapLength(botsel->column); clipText += "\n" + line; } + + // FIXME: clipboard not implemented yet + uii.Sys_SetClipboard(clipText); } void UIMultiLineEdit::PasteSelection(void) @@ -715,7 +718,16 @@ void UIMultiLineEdit::PasteSelection(void) str sel; int i; - sel = uii.Sys_GetClipboard(); + // temporary variable added in OPM as str cannot handle NULL assignment + // will be removed when Sys_GetClipboard is properly implemented + const char *clipboardData = uii.Sys_GetClipboard(); + if (clipboardData == NULL) + { + // FIXME: clipboard not implemented yet + return; + } + + sel = clipboardData; DeleteSelection(); From edd2a9d8f60592b70403e36da7c10d8ce5eeec74 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:17:35 +0200 Subject: [PATCH 0433/2040] UIMultiLineEdit::Draw documentation --- code/uilib/uimledit.cpp | 45 +++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/code/uilib/uimledit.cpp b/code/uilib/uimledit.cpp index a3ac0823..668286ef 100644 --- a/code/uilib/uimledit.cpp +++ b/code/uilib/uimledit.cpp @@ -201,70 +201,86 @@ void UIMultiLineEdit::Draw(void) int caret = 0; if (i < topsel->line || i > botsel->line) { + // Print regular line without any selection or cursor present m_font->setColor(m_foreground_color); m_font->Print(0, aty, cur, -1, m_bVirtual); } else { + // Current line contains cursor and/or selected text float linewidth = m_font->getWidth(cur, -1); if (i > topsel->line && i < botsel->line) { - DrawBox(0, aty, linewidth, m_font->getHeight(m_bVirtual), selectionBG, 1.f); + // all text in current line is selected, it's part of a larger selection, + // print entire line with the selection highlight box around it + DrawBox(0.0f, aty, linewidth, m_font->getHeight(m_bVirtual), selectionBG, 1.f); m_font->setColor(selectionColor); m_font->Print(0, aty, Sys_LV_CL_ConvertString(cur), -1, m_bVirtual); } else if (i != topsel->line) { - if (i == botsel->line) { - int toplen = m_font->getWidth(cur, botsel->column); + // part of this line is selected, and selection continues/began above + if (i == botsel->line) { // sanity check, should always be true + int toplen = m_font->getWidth(cur, botsel->column); // X coord of highlighting end if (toplen) { + // selection contains text from the beginning of the line, + // print it with the selection highlight box around it m_font->setColor(selectionColor); DrawBox(0, aty, toplen, m_font->getHeight(m_bVirtual), selectionBG, 1.f); m_font->Print(0, aty, cur, botsel->column, m_bVirtual); } - if (toplen < linewidth) { + if (toplen < linewidth) { // is there still text on this line after the selection? m_font->setColor(m_foreground_color); m_font->Print(toplen, aty, &cur[botsel->column], -1, m_bVirtual); } if (botsel == &m_selection.end) { + // Place cursor at the end of the selection if it was started from above caret = toplen; } } } else if (i != botsel->line) { - int toplen = m_font->getWidth(cur, topsel->column); - if (topsel->column) { + // part of this line is selected, and selection continues/began below + int toplen = m_font->getWidth(cur, topsel->column); // X coord of highlighting start + if (topsel->column) { // is there any text on this line before the selection? m_font->setColor(m_foreground_color); m_font->Print(0, aty, cur, topsel->column, m_bVirtual); } - if (toplen < linewidth) { + if (toplen < linewidth) { // is there any selected text before the end of the line? + // print the selected text with the selection highlight box around it m_font->setColor(selectionColor); DrawBox(toplen, aty, linewidth - toplen, m_font->getHeight(m_bVirtual), selectionBG, 1.f); m_font->Print(toplen, aty, &cur[topsel->column], -1, m_bVirtual); } if (topsel == &m_selection.end) { + // Place cursor before the highlight box if selection was made from the bottom up caret = toplen; } } else { + // current line contains the cursor if (topsel->column == botsel->column) { + // no selection or highlighted text caret = m_font->getWidth(cur, topsel->column); m_font->setColor(m_foreground_color); m_font->Print(0, aty, Sys_LV_CL_ConvertString(cur), -1, m_bVirtual); } else { - int toplen = m_font->getWidth(cur, topsel->column); - int botlen = toplen + m_font->getWidth(&cur[topsel->column], botsel->column - topsel->column); + // selection starts and ends on this line + int toplen = m_font->getWidth(cur, topsel->column); // X coord of highlighting start + int botlen = toplen + m_font->getWidth(&cur[topsel->column], botsel->column - topsel->column); // X coord of selection end - if (toplen) { + if (toplen) { // is there any text on this line before the selection? m_font->setColor(m_foreground_color); m_font->Print(0, aty, cur, topsel->column, m_bVirtual); } - if (botlen != toplen) { + if (botlen != toplen) { // is the selection wider than 0 pixels? (sanity check, always true) + // print the selected text with the selection highlight box around it DrawBox(toplen, aty, botlen - toplen, m_font->getHeight(m_bVirtual), selectionBG, 1.f); m_font->setColor(selectionColor); m_font->Print(toplen, aty, &cur[topsel->column], botsel->column - topsel->column, m_bVirtual); } - if (cur.length() != botsel->column) { + if (cur.length() != botsel->column) { // is there still text on this line after the selection? + // print the leftover text m_font->setColor(m_foreground_color); // Fixed in OPM: @@ -275,8 +291,10 @@ void UIMultiLineEdit::Draw(void) m_font->Print(botlen, aty, &cur[botsel->column], -1, m_bVirtual); } + // Place the cursor at the end of the selection... caret = botlen; if (topsel == &m_selection.end) { + // ... except if selection was made from the bottom up caret = toplen; } } @@ -286,7 +304,8 @@ void UIMultiLineEdit::Draw(void) } } - if (m_selection.end.line == i && (uid.time % 750) > 374 && IsActive()) { + if (m_selection.end.line == i && (uid.time % 750) >= 375 && IsActive()) { + // draw cursor caret DrawBox(caret, aty, 2.f, m_font->getHeight(m_bVirtual), UBlack, 1.f); } From c84702b49094e06eb2e7c53812f8a8068c51831f Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:18:49 +0200 Subject: [PATCH 0434/2040] Fix file picker crash on AA --- code/client/cl_uimaprunner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/client/cl_uimaprunner.cpp b/code/client/cl_uimaprunner.cpp index 6a5cf205..40b0730d 100644 --- a/code/client/cl_uimaprunner.cpp +++ b/code/client/cl_uimaprunner.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2023-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -94,7 +94,7 @@ void PickFile(const char *name, Listener *obj, Event& event) currentpath = ""; } - picker->Setup("", currentpath, ".*"); + picker->Setup("", currentpath, ".*", ""); } CLASS_DECLARATION(FilePickerClass, ViewSpawnerClass, NULL) { From ac01ad67516685d68ff3894269440644f1968ff0 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:19:29 +0200 Subject: [PATCH 0435/2040] Take over va() memory safety fix from ioquake3 --- code/qcommon/q_shared.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 485f016b..7dd4afa7 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -1659,7 +1659,6 @@ va does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functions. -FIXME: make this buffer size safe someday ============ */ const char *va( const char *format, ... ) @@ -1673,7 +1672,7 @@ const char *va( const char *format, ... ) index++; va_start( argptr, format ); - vsprintf( buf, format, argptr ); + Q_vsnprintf( buf, sizeof(*string), format, argptr ); va_end( argptr ); return buf; From 907aa21ba8d1f059dd0c08a0fb61d71fdfa19d33 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:24:39 +0200 Subject: [PATCH 0436/2040] Fix UIPopupMenu crashes caused by dereferencing already freed instance --- code/uilib/uipopupmenu.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/code/uilib/uipopupmenu.cpp b/code/uilib/uipopupmenu.cpp index 4e37663d..59e378f4 100644 --- a/code/uilib/uipopupmenu.cpp +++ b/code/uilib/uipopupmenu.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015-2023 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -405,6 +405,11 @@ void UIPopupMenu::MouseReleased return; } + // NOTE: Dismiss() below can delete this entire instance! + // Save the m_listener pointer for later, as `this->m_listener` + // cannot be used after the instance was freed. + Listener* listener = m_listener; + if (m_autodismiss) { Dismiss(); @@ -413,10 +418,11 @@ void UIPopupMenu::MouseReleased switch (desc->type) { case UIP_EVENT: - ProcessEvent((Event*)desc->data); + // make sure it's passed in as an Event&, as ProcessEvent(Event*) would try to delete the static event! + listener->ProcessEvent(*(Event*)desc->data); break; case UIP_EVENT_STRING: - ProcessEvent(new Event((const char*)desc->data)); + listener->ProcessEvent(new Event((const char*)desc->data)); break; case UIP_CMD: case UIP_CVAR: @@ -466,7 +472,7 @@ void UIPopupMenu::Dismiss { m_parentMenu->Dismiss(); } - else + else if (this) { // this is the topmost menu, self-destruct delete this; From 52f43a3aa6e22490699af2f9e7f4e6b00f39e7bc Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:25:30 +0200 Subject: [PATCH 0437/2040] Document OPM fix for center-justified UINotepad statusbar --- code/uilib/uistatus.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/uilib/uistatus.cpp b/code/uilib/uistatus.cpp index 92dd1238..19d6d2a5 100644 --- a/code/uilib/uistatus.cpp +++ b/code/uilib/uistatus.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -161,7 +161,10 @@ UIStatusBar::UIStatusBar alignment_t align, float height ) - : UIStatusBar() + : UIStatusBar() // Fixed in OPM: + // original builds didn't call this ctor, + // so statusbar text got center-justified due to + // m_iFontAlignmentHorizontal defaulting to FONT_JUSTHORZ_CENTER (0) { AlignBar(align, height); From 6e454cdfb36d2ebb2e22656ae250f22350b46470 Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:26:38 +0200 Subject: [PATCH 0438/2040] Fix subtle bugs and refactor in UIWindowManager --- code/uilib/uiwinman.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/uilib/uiwinman.cpp b/code/uilib/uiwinman.cpp index d5d7377b..9e986d97 100644 --- a/code/uilib/uiwinman.cpp +++ b/code/uilib/uiwinman.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2015 the OpenMoHAA team +Copyright (C) 2015-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -525,7 +525,7 @@ qboolean UIWindowManager::KeyEvent(int key, unsigned int time) { UIWidget *selwidget = NULL; - if (key == K_TAB && (uii.Sys_IsKeyDown(K_CTRL) || uii.Sys_IsKeyDown(K_DEL))) { + if (key == K_TAB && uii.Sys_IsKeyDown(K_CTRL)) { UIWidget *wid; if (m_activeControl && m_activeControl != this) { @@ -540,13 +540,13 @@ qboolean UIWindowManager::KeyEvent(int key, unsigned int time) selwidget = getFirstChild(); } - for (wid = selwidget->getNextChild(selwidget); wid != NULL; wid = wid->getNextChild(wid)) { + for (wid = getNextChild(selwidget); wid != NULL; wid = getNextChild(wid)) { if (!(selwidget->m_flags & WF_ALWAYS_BOTTOM) && selwidget->CanActivate()) { ActivateControl(wid); return true; } } - for (wid = getFirstChild(); wid != selwidget && wid != NULL; wid = wid->getNextChild(wid)) { + for (wid = getFirstChild(); wid != selwidget && wid != NULL; wid = getNextChild(wid)) { if (!(selwidget->m_flags & WF_ALWAYS_BOTTOM) && selwidget->CanActivate()) { ActivateControl(wid); return true; @@ -555,7 +555,7 @@ qboolean UIWindowManager::KeyEvent(int key, unsigned int time) } else { if (m_bindactive) { m_bindactive->KeyEvent(key, time); - } else if (!m_activeControl || !m_activeControl->KeyEvent(key, time) && (key != K_UPARROW || key != K_DOWNARROW)) { + } else if (!(m_activeControl && m_activeControl->KeyEvent(key, time)) && (key == K_DOWNARROW || key == K_UPARROW)) { selwidget = m_activeControl; if (selwidget && selwidget != this) { for (selwidget = m_activeControl; selwidget != NULL; selwidget = selwidget->getParent()) { From fa5a97031d2a00ddbde077682923c7e6c9a501cf Mon Sep 17 00:00:00 2001 From: pryon Date: Mon, 10 Jun 2024 14:43:40 +0200 Subject: [PATCH 0439/2040] Fix assignment of a temporary to a non-const reference error on GCC --- code/uilib/uinotepad.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/uilib/uinotepad.cpp b/code/uilib/uinotepad.cpp index 0e375cb5..556b6b6f 100644 --- a/code/uilib/uinotepad.cpp +++ b/code/uilib/uinotepad.cpp @@ -149,7 +149,8 @@ static ctrlevent_s controlEvents[CTRL_EVENT_COUNT] = { bool UI_LoadNotepadFile(const char *filename) { UINotepad *uinp = new UINotepad(); - if (uinp->Create(NULL, UIRect2D(100.0f, 100.0f, 450.0f, 300.0f), filename)) { + UIRect2D rect = UIRect2D(100.0f, 100.0f, 450.0f, 300.0f); + if (uinp->Create(NULL, rect, filename)) { uWinMan.ActivateControl(uinp); return true; } From e550d244dfee23c9dca2f0d863a634c1330bd041 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:05:39 +0200 Subject: [PATCH 0440/2040] Reimplemented skelChannelList_s::LocalChannel --- code/skeletor/skeletor_utilities.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/skeletor/skeletor_utilities.cpp b/code/skeletor/skeletor_utilities.cpp index 75f28a8c..78b2006c 100644 --- a/code/skeletor/skeletor_utilities.cpp +++ b/code/skeletor/skeletor_utilities.cpp @@ -80,16 +80,20 @@ int skelChannelList_s::GlobalChannel(int localchannel) const int skelChannelList_s::LocalChannel(int channel) const { - return m_chanLocalFromGlobal[channel]; + return GetLocalFromGlobal(channel); } int skelChannelList_s::GetLocalFromGlobal(int globalChannel) const { - if (m_chanLocalFromGlobal && globalChannel < m_numLocalFromGlobal) { - return m_chanLocalFromGlobal[globalChannel]; - } else { + if (!m_chanLocalFromGlobal) { return -1; } + + if (globalChannel >= m_numLocalFromGlobal) { + return -1; + } + + return m_chanLocalFromGlobal[globalChannel]; } int skelChannelList_s::NumChannels(void) const From abefdd772cd03719969ab1d7394b35293cfe360c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:06:25 +0200 Subject: [PATCH 0441/2040] DecodeFrameValue should only return a float value --- code/skeletor/skeletor.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 40febcfd..be9ef4ec 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -1047,7 +1047,7 @@ int skeletor_c::GetMorphWeightFrame(int index, float time, int *data) return GetMorphWeightFrame(data); } -float *DecodeFrameValue(skanChannelHdr *channelFrames, int desiredFrameNum) +float DecodeFrameValue(skanChannelHdr *channelFrames, int desiredFrameNum) { skanGameFrame *foundFrame; size_t frameSize; @@ -1069,7 +1069,7 @@ float *DecodeFrameValue(skanChannelHdr *channelFrames, int desiredFrameNum) foundFrame = (skanGameFrame *)((byte *)channelFrames->ary_frames + foundFrame->nPrevFrameIndex * frameSize); } - return foundFrame->pChannelData; + return foundFrame->pChannelData[0]; } int skeletor_c::GetMorphWeightFrame(int *data) @@ -1079,7 +1079,7 @@ int skeletor_c::GetMorphWeightFrame(int *data) int blendNum; float weight; int modelChannelNum; - float *channelData; + float channelData; numTargets = m_morphTargetList.NumChannels(); @@ -1096,12 +1096,11 @@ int skeletor_c::GetMorphWeightFrame(int *data) if (weight > 0.001) { for (modelChannelNum = 0; modelChannelNum < numTargets; modelChannelNum++) { animChannelNum = m_morphTargetList.GlobalChannel(modelChannelNum); - animChannelNum = blendInfo.pAnimationData->channelList.GetLocalFromGlobal(animChannelNum); + animChannelNum = blendInfo.pAnimationData->channelList.LocalChannel(animChannelNum); if (animChannelNum >= 0) { - channelData = - DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame); - data[modelChannelNum] += (int)(channelData[0] * weight); + channelData = DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame); + data[modelChannelNum] += (int)(channelData * weight); } } } @@ -1114,12 +1113,11 @@ int skeletor_c::GetMorphWeightFrame(int *data) if (weight > 0.001) { for (modelChannelNum = 0; modelChannelNum < numTargets; modelChannelNum++) { animChannelNum = m_morphTargetList.GlobalChannel(modelChannelNum); - animChannelNum = blendInfo.pAnimationData->channelList.GetLocalFromGlobal(animChannelNum); + animChannelNum = blendInfo.pAnimationData->channelList.LocalChannel(animChannelNum); if (animChannelNum >= 0) { - channelData = - DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame); - data[modelChannelNum] += (int)(channelData[0] * weight); + channelData = DecodeFrameValue(&blendInfo.pAnimationData->ary_channels[animChannelNum], blendInfo.frame); + data[modelChannelNum] += (int)(channelData * weight); } } } From c16f2029b10093ab187d06b826065a3ccd832fef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:06:35 +0200 Subject: [PATCH 0442/2040] Implemented skeletor_c::ChannelNames() --- code/skeletor/skeletor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index be9ef4ec..33745932 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -29,6 +29,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define EPSILON 0.000000000001f +ChannelNameTable* skeletor_c::ChannelNames() +{ + return m_channelNames; +} + int skelAnimDataGameHeader_s::GetFrameNums( float timeSeconds, float timeTolerance, int *beforeFrame, int *afterFrame, float *beforeWeight, float *afterWeight ) From ebb3173322060d94b71f4923e84457f27a5de848 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:06:47 +0200 Subject: [PATCH 0443/2040] Added skeletorMorphCache_t as an alias to int --- code/tiki/tiki_shared.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index dc6de490..57318d05 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -425,3 +425,5 @@ typedef struct { size_t size; int numuses; } skelcache_t; + +typedef int skeletorMorphCache_t; From 445814b14485d245ecbe133cda267c621c7bef24 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:15:10 +0200 Subject: [PATCH 0444/2040] Fixed skeletor_c::ChannelNames return value --- code/skeletor/skeletor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 33745932..ad4e5c9a 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ChannelNameTable* skeletor_c::ChannelNames() { - return m_channelNames; + return &m_channelNames; } int skelAnimDataGameHeader_s::GetFrameNums( From 79b0e6998d293409b67de9b6e31260b66db405ef Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 23:40:34 +0200 Subject: [PATCH 0445/2040] Fixed implementations --- code/skeletor/bonetable.cpp | 6 +++--- code/skeletor/skeletor_utilities.cpp | 20 ++++++++------------ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/code/skeletor/bonetable.cpp b/code/skeletor/bonetable.cpp index 46a86723..22a919f6 100644 --- a/code/skeletor/bonetable.cpp +++ b/code/skeletor/bonetable.cpp @@ -348,9 +348,9 @@ int ChannelNameTable::RegisterChannel(const char *name) const char *ChannelNameTable::FindNameFromLookup(int index) { - if (index < m_iNumChannels) { - return m_Channels[index].name; - } else { + if (index >= m_iNumChannels) { return NULL; } + + return m_Channels[index].name; } diff --git a/code/skeletor/skeletor_utilities.cpp b/code/skeletor/skeletor_utilities.cpp index 78b2006c..a580ceb7 100644 --- a/code/skeletor/skeletor_utilities.cpp +++ b/code/skeletor/skeletor_utilities.cpp @@ -182,24 +182,20 @@ qboolean skelChannelList_s::HasChannel(ChannelNameTable *nameTable, const char * { short int iGlobalChannel = nameTable->FindNameLookup(channelName); - if (iGlobalChannel >= 0) { - if (m_chanLocalFromGlobal && iGlobalChannel < m_numLocalFromGlobal) { - return (unsigned int)~m_chanLocalFromGlobal[iGlobalChannel] >> 31; - } else { - return qtrue; - } - } else { - return qfalse; - } + return iGlobalChannel >= 0 && LocalChannel(iGlobalChannel) >= 0; } const char *skelChannelList_s::ChannelName(ChannelNameTable *nameTable, int localChannelNum) const { - if (localChannelNum >= 0 && localChannelNum < m_numChannels) { - return nameTable->FindName(m_chanGlobalFromLocal[localChannelNum]); - } else { + if (localChannelNum >= this->m_numChannels || localChannelNum < 0) { return NULL; } + + if (m_chanGlobalFromLocal[localChannelNum] < 0) { + return 0; + } + + return nameTable->FindName(m_chanGlobalFromLocal[localChannelNum]); } void Skel_ExtractFilePath(const char *path, char *dest) From 6b6e5291ddf5d5a1399202cdd105b76cac556276 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 23:40:50 +0200 Subject: [PATCH 0446/2040] Fixed `EYES_up` length --- code/skeletor/skeletor_model_files.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor_model_files.cpp b/code/skeletor/skeletor_model_files.cpp index a7b6d543..4cbc6fed 100644 --- a/code/skeletor/skeletor_model_files.cpp +++ b/code/skeletor/skeletor_model_files.cpp @@ -209,7 +209,7 @@ void skeletor_c::LoadMorphTargetNames(skelHeaderGame_t *modelHeader) m_targetLookLeft = morphTargetIndex; } else if (!strncmp(newTargetName, "EYES_right", 10)) { m_targetLookRight = morphTargetIndex; - } else if (!strncmp(newTargetName, "EYES_up", 70)) { + } else if (!strncmp(newTargetName, "EYES_up", 7)) { m_targetLookUp = morphTargetIndex; } else if (!strncmp(newTargetName, "EYES_down", 9)) { m_targetLookDown = morphTargetIndex; From 531340627d3f2501ce92c32b7539b735eef27b9b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 10 Jun 2024 23:53:42 +0200 Subject: [PATCH 0447/2040] Call LocalChannel() instead --- code/skeletor/skeletor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index ad4e5c9a..6d3920aa 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -1252,5 +1252,5 @@ int dtiki_s::GetBoneNumFromName(const char *name) return -1; } - return m_boneList.GetLocalFromGlobal(iGlobalChannel); + return m_boneList.LocalChannel(iGlobalChannel); } From dd85118a9c3b32f30e046ea4fb9c547f75b80b4d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:01:41 +0200 Subject: [PATCH 0448/2040] Don't pack channels when reading encoded frames from mohsh and above (they're already packed in the animation file) --- code/skeletor/skeletor_loadanimation.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index c1740af0..611407ff 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -527,7 +527,7 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pChannel = &enAnim->ary_channels[i]; name = enAnim->channelList.ChannelName(&skeletor_c::m_channelNames, i); - type = GetChannelTypeFromName(name); + type = GetBoneChannelType(name); frameCnt = MSG_ReadShort(msg); switch (type) { @@ -704,8 +704,6 @@ skelAnimDataGameHeader_t *skeletor_c::LoadProcessedAnimEx(const char *path, void enAnim->channelList.AddChannel(m_channelNames.RegisterChannel(MSG_ReadString(&msg))); } - enAnim->channelList.PackChannels(); - newFrame = (skelAnimGameFrame_t *)Skel_Alloc(enAnim->numFrames * sizeof(skelAnimGameFrame_t)); enAnim->m_frame = newFrame; From 4d231fbc50a3bd0a1d5e9faf52b37014362c928e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:05:28 +0200 Subject: [PATCH 0449/2040] Call `LocalChannel` instead of `GetLocalFromGlobal` --- code/renderer/tr_model.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index f478554e..c8cd21e9 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -1243,14 +1243,14 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { channelNum = skelmodel->pBones[weight->boneIndex].channel; } - boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + boneNum = tiki->m_boneList.LocalChannel(channelNum); bone = &bones[boneNum]; SkelVertGetNormal(newVerts, bone, normal); for (weightNum = 0; weightNum < newVerts->numWeights; weightNum++) { channelNum = skelmodel->pBones[weight->boneIndex].channel; - boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + boneNum = tiki->m_boneList.LocalChannel(channelNum); bone = &bones[boneNum]; if (!weightNum) { @@ -1349,14 +1349,14 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) { weight = (skelWeight_t*)((byte*)newVerts + sizeof(skeletorVertex_t) + sizeof(skeletorMorph_t) * newVerts->numMorphs); channelNum = skelmodel->pBones[weight->boneIndex].channel; - boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + boneNum = tiki->m_boneList.LocalChannel(channelNum); bone = &bones[boneNum]; SkelVertGetNormal(newVerts, bone, normal); for (weightNum = 0; weightNum < newVerts->numWeights; weightNum++) { channelNum = skelmodel->pBones[weight->boneIndex].channel; - boneNum = tiki->m_boneList.GetLocalFromGlobal(channelNum); + boneNum = tiki->m_boneList.LocalChannel(channelNum); bone = &bones[boneNum]; SkelWeightGetXyz(weight, bone, out); From fb15f0f2b33c33f96d0c535c01113d08378dcc9c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:06:31 +0200 Subject: [PATCH 0450/2040] Fixed a tiny mistake that prevented morphs from working correctly Actors now have a working dynamic facial expression (moving eyes/mouth/brown...) --- code/skeletor/skeletor_model_files.cpp | 2 +- code/tiki/tiki_skel.cpp | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/code/skeletor/skeletor_model_files.cpp b/code/skeletor/skeletor_model_files.cpp index 4cbc6fed..db5a359a 100644 --- a/code/skeletor/skeletor_model_files.cpp +++ b/code/skeletor/skeletor_model_files.cpp @@ -217,6 +217,6 @@ void skeletor_c::LoadMorphTargetNames(skelHeaderGame_t *modelHeader) m_targetBlink = morphTargetIndex; } - newTargetName += strlen(newTargetName + 1); + newTargetName += strlen(newTargetName) + 1; } } diff --git a/code/tiki/tiki_skel.cpp b/code/tiki/tiki_skel.cpp index b267117e..17e649b4 100644 --- a/code/tiki/tiki_skel.cpp +++ b/code/tiki/tiki_skel.cpp @@ -439,14 +439,12 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) } if (nBoxBytes) { - const int ofsBoxes = LongNoSwapPtr(&pHeader->ofsBoxes); - - if (ofsBoxes <= 0 || (nBoxBytes + ofsBoxes) >= length) { + if (pHeader->ofsBoxes <= 0 || (nBoxBytes + pHeader->ofsBoxes) > length) { Com_Printf("^~^~^ Box data is corrupted for '%s'\n", cache->path); - pSkel->numMorphTargets = 0; - pSkel->pMorphTargets = NULL; + pSkel->numBoxes = 0; + pSkel->pBoxes = NULL; } else { - memcpy(pSkel->pBoxes, ((byte *)pHeader + ofsBoxes), nBoxBytes); + memcpy(pSkel->pBoxes, ((byte *)pHeader + pHeader->ofsBoxes), nBoxBytes); } } else { pSkel->numBoxes = 0; @@ -460,14 +458,12 @@ void TIKI_CacheFileSkel(skelHeader_t *pHeader, skelcache_t *cache, int length) } if (nMorphBytes) { - const int ofsMorphTargets = LongNoSwapPtr(&pHeader->ofsBoxes); - - if (ofsMorphTargets <= 0 || (nMorphBytes + ofsMorphTargets) >= length) { + if (pHeader->ofsMorphTargets <= 0 || (nMorphBytes + pHeader->ofsMorphTargets) > length) { Com_Printf("^~^~^ Morph targets data is corrupted for '%s'\n", cache->path); pSkel->numMorphTargets = 0; pSkel->pMorphTargets = NULL; } else { - memcpy(pSkel->pMorphTargets, ((byte *)pHeader + ofsMorphTargets), nMorphBytes); + memcpy(pSkel->pMorphTargets, ((byte *)pHeader + pHeader->ofsMorphTargets), nMorphBytes); } } else { pSkel->numMorphTargets = 0; From dfb2cb6bbf3477e5e093254332204d26987ed48c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:19:15 +0200 Subject: [PATCH 0451/2040] Fixed buffer overrun --- code/skeletor/skeletor_loadanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index 611407ff..ed019ebd 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -392,7 +392,7 @@ void WriteEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) MSG_WriteShort(msg, pChannel->nFramesInChannel); for (j = 0; j < pChannel->nFramesInChannel; j++) { - vec3_t channelData; + vec4_t channelData; pFrame = &pChannel->ary_frames[i]; MSG_WriteShort(msg, pFrame->nFrameNum); From 874b034698b54c1032f7f011714675ff223d4432 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:24:01 +0200 Subject: [PATCH 0452/2040] Corrected some compilation warnings --- code/gamespy/sv_gqueryreporting.c | 2 +- code/server/sv_client.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/gamespy/sv_gqueryreporting.c b/code/gamespy/sv_gqueryreporting.c index 4828db27..f0559f0e 100644 --- a/code/gamespy/sv_gqueryreporting.c +++ b/code/gamespy/sv_gqueryreporting.c @@ -306,7 +306,7 @@ static void send_final(qr_t qrec, struct sockaddr *sender, char *outbuf, char *v return; } - strcpy(encrypted_val, validation); + strcpy((char*)encrypted_val, validation); gs_encrypt((uchar *)qrec->secret_key, (int)strlen(qrec->secret_key), encrypted_val, keylen); gs_encode(encrypted_val, keylen, encoded_val); diff --git a/code/server/sv_client.c b/code/server/sv_client.c index e262ca9c..beacfbaa 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -1519,7 +1519,7 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) { // Since 2.0, displays chat messages // NOTE: this should be handled by fgame, not server // - Com_Printf("%s (%ld): %s", cl->name, cl - svs.clients, s); + Com_Printf("%s (%zu): %s", cl->name, (size_t)(cl - svs.clients), s); } if (clientOK) { From ee5faedaf9c70a3f4b94e3c97d9330321eb6f587 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:25:38 +0200 Subject: [PATCH 0453/2040] Removed the value of LittleSwap/BigSwap on little-endian/big-endian --- code/qcommon/q_platform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index d7fcce1e..32e8f31f 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -430,7 +430,7 @@ void SwapValue(void* dest, size_t size); #define BigFloat #define BigShortPtr(x) ShortNoSwapPtr(&x) #define BigLongPtr(x) LongNoSwapPtr(&x) -#define BigSwap(x, size) x +#define BigSwap(x, size) #elif defined( Q3_LITTLE_ENDIAN ) @@ -444,7 +444,7 @@ void SwapValue(void* dest, size_t size); #define LittleShortPtr(x) ShortNoSwapPtr(&x) #define LittleLongPtr(x) LongNoSwapPtr(&x) #define LittleFloatPtr(x) FloatNoSwapPtr(&x) -#define LittleSwap(x, size) x +#define LittleSwap(x, size) #define BigShort(x) ShortSwap(x) #define BigUnsignedShort(x) UnsignedShortSwap(x) From a26e5b74c29d7216ac77d3b7d7f8d3e9893fa92f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:05:09 +0200 Subject: [PATCH 0454/2040] Use `armhf` and `armel` suffix to distinguish between ARM variants --- TargetArch.cmake | 8 ++++++-- code/qcommon/q_platform.h | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/TargetArch.cmake b/TargetArch.cmake index d51cc015..6d1d8dd8 100644 --- a/TargetArch.cmake +++ b/TargetArch.cmake @@ -23,10 +23,14 @@ set(archdetect_c_code " # error cmake_ARCH alpha #elif defined __sparc__ # error cmake_ARCH sparc -#elif defined __arm__ || defined (_M_ARM) -# error cmake_ARCH arm #elif defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64) # error cmake_ARCH arm64 +#elif defined __arm__ || defined (_M_ARM) +# if defined(__ARM_PCS_VFP) && (__ARM_PCS_VFP) +# error cmake_ARCH armhf +# else +# error cmake_ARCH armel +# endif #elif defined __cris__ # error cmake_ARCH cris #elif defined __hppa__ diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 32e8f31f..bc4960c5 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -213,10 +213,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # define ARCH_STRING "alpha" #elif defined __sparc__ # define ARCH_STRING "sparc" -#elif defined __arm__ -# define ARCH_STRING "arm" -#elif defined(__aarch64__) || defined(__ARM64__) +#elif defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64) # define ARCH_STRING "arm64" +#elif defined __arm__ || defined (_M_ARM) +# if defined(__ARM_PCS_VFP) && (__ARM_PCS_VFP) +# define ARCH_STRING "armhf" +# else +# define ARCH_STRING "armel" +# endif #elif defined __cris__ # define ARCH_STRING "cris" #elif defined __hppa__ From 42c20ac008691efb88f4e05b3f71df27e2184237 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:35:18 +0200 Subject: [PATCH 0455/2040] Portal sky mustn't cause entity surface to be r-eadded This fixes an issue where an entity would get re-added with a really lower LOD. Fixes #307 --- code/renderer/tr_main.c | 48 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 800ff499..96a7445f 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -1047,7 +1047,7 @@ qboolean SurfIsOffscreen(const srfSurfaceFace_t* surface, shader_t* shader, int } } - if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 ) + if ( ( dot = DotProduct( normal, surface->plane.normal ) ) >= 0 ) { numTriangles--; } @@ -1485,6 +1485,27 @@ void R_AddEntitySurfaces (void) { continue; } + if (tr.viewParms.isPortalSky) { + // Expecting a sky entity in a sky portal + if (!(ent->e.renderfx & RF_SKYENTITY)) { + continue; + } + } else { + if (ent->e.renderfx & RF_SKYENTITY) { + continue; + } + } + + if (tr.viewParms.isPortal) { + if (!(ent->e.renderfx & (RF_WRAP_FRAMES | RF_SHADOW_PLANE))) { + continue; + } + } else { + if (ent->e.renderfx & RF_SHADOW_PLANE) { + continue; + } + } + // simple generated models, like sprites and beams, are not culled switch ( ent->e.reType ) { case RT_PORTALSURFACE: @@ -1552,25 +1573,24 @@ void R_AddSpriteSurfaces() { sprite = &tr.refdef.sprites[tr.currentSpriteNum]; - if (tr.viewParms.isPortalSky) - { - if ((sprite->renderfx & RF_SKYENTITY) == 0) { + if (tr.viewParms.isPortalSky) { + if (!(sprite->renderfx & RF_SKYENTITY)) { continue; } - } - else if ((sprite->renderfx & RF_SKYENTITY) != 0) - { - continue; - } + } else { + if (sprite->renderfx & RF_SKYENTITY) { + continue; + } + } - if (tr.viewParms.isPortal) - { + if (tr.viewParms.isPortal) { if (!(sprite->renderfx & (RF_SHADOW_PLANE | RF_WRAP_FRAMES))) { continue; } - } - else if (sprite->renderfx & RF_SHADOW_PLANE) { - continue; + } else { + if (sprite->renderfx & RF_SHADOW_PLANE) { + continue; + } } tr.currentEntityNum = ENTITYNUM_WORLD; From ca4b1ebdeea1649691f3c8a5fb567ee7e7e7a45d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:37:45 +0200 Subject: [PATCH 0456/2040] Don't render terrain when `refdef.render_terrain` is set to false --- code/renderer/tr_world.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/code/renderer/tr_world.c b/code/renderer/tr_world.c index 68b6bf36..36c4f5d8 100644 --- a/code/renderer/tr_world.c +++ b/code/renderer/tr_world.c @@ -58,6 +58,10 @@ static qboolean R_CullGrid( srfGridMesh_t *cv ) { return qtrue; } + if (!tr.refdef.render_terrain) { + return qtrue; + } + if ( tr.currentEntityNum != ENTITYNUM_WORLD ) { sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius ); } else { @@ -559,7 +563,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) } } - if (r_drawterrain->integer) + if (r_drawterrain->integer && tr.refdef.render_terrain && !tr.viewParms.isPortalSky) { int i; @@ -791,7 +795,7 @@ void R_AddWorldSurfaces (void) { tr.currentEntityNum = ENTITYNUM_WORLD; tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; - if (r_drawterrain->integer) { + if (r_drawterrain->integer && tr.refdef.render_terrain && !tr.viewParms.isPortalSky) { R_TerrainPrepareFrame(); } @@ -808,7 +812,7 @@ void R_AddWorldSurfaces (void) { R_TransformDlights(tr.refdef.num_dlights, tr.refdef.dlights, &tr.viewParms.world); R_RecursiveWorldNode(tr.world->nodes, tr.viewParms.fog.extrafrustums ? 31 : 15, (1 << tr.refdef.num_dlights) - 1); - if (r_drawterrain->integer) { + if (r_drawterrain->integer && tr.refdef.render_terrain && !tr.viewParms.isPortalSky) { R_AddTerrainSurfaces(); } if (r_drawstaticmodels->integer) { From a74b966b7c075abc8eea374eb93418d38423f026 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:44:02 +0200 Subject: [PATCH 0457/2040] Update fog when changing whether or not the terrain must be rendered --- code/fgame/worldspawn.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/worldspawn.cpp b/code/fgame/worldspawn.cpp index 14fe1548..b91f32eb 100644 --- a/code/fgame/worldspawn.cpp +++ b/code/fgame/worldspawn.cpp @@ -920,6 +920,7 @@ void World::GetRenderTerrain(Event *ev) void World::SetRenderTerrain(Event *ev) { render_terrain = ev->GetInteger(1); + UpdateFog(); } void World::GetSkyboxSpeed(Event *ev) From de02c868a27f3206688a2e474207f397028b704f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:46:50 +0200 Subject: [PATCH 0458/2040] Fixed bullet tracers being incorrect This should fix almost immobile bullet tracers on t1l1 --- code/fgame/weaputils.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index 4e036956..d611e81c 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -2524,8 +2524,12 @@ float BulletAttack( if (tracerspeed == 1.f) { gi.MSG_WriteBits(0, 1); } else { + int speed; + + speed = tracerspeed * (1 << 9); + gi.MSG_WriteBits(1, 1); - gi.MSG_WriteBits(Q_clamp(tracerspeed, 1, 1023), 10); + gi.MSG_WriteBits(Q_clamp(speed, 1, 1023), 10); } } @@ -2611,8 +2615,12 @@ void FakeBulletAttack( if (tracerspeed == 1.f) { gi.MSG_WriteBits(0, 1); } else { + int speed; + + speed = tracerspeed * (1 << 9); + gi.MSG_WriteBits(1, 1); - gi.MSG_WriteBits(Q_clamp(tracerspeed, 1, 1023), 10); + gi.MSG_WriteBits(Q_clamp(speed, 1, 1023), 10); } } From 332a63503172c167d5ea8ca2cc6e5585fda1a55e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:25:02 +0200 Subject: [PATCH 0459/2040] Use MAX_GLOBAL_FROM_LOCAL --- code/tiki/tiki_shared.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index 57318d05..1834c5b5 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -146,7 +146,7 @@ typedef struct skelChannelList_s { short int m_numChannels; short int m_numLocalFromGlobal; short int *m_chanLocalFromGlobal; - short int m_chanGlobalFromLocal[200]; + short int m_chanGlobalFromLocal[MAX_GLOBAL_FROM_LOCAL]; } skelChannelList_c; #endif From 546ded324e0b9680c63875a40362e39149068e99 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:25:45 +0200 Subject: [PATCH 0460/2040] Made ChannelNames() method public --- code/skeletor/skeletor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor.h b/code/skeletor/skeletor.h index a6cf90e8..3f7e23e6 100644 --- a/code/skeletor/skeletor.h +++ b/code/skeletor/skeletor.h @@ -130,10 +130,10 @@ public: void SetPose(const frameInfo_t *frameInfo, const int *contIndices, const vec4_t *contValues, float actionWeight); void SetEyeTargetPos(const float *pEyeTargetPos); int GetBoneParent(int boneIndex); + static class ChannelNameTable* ChannelNames(); private: void Init(); - static class ChannelNameTable *ChannelNames(); SkelMat4 *BoneTransformation(int, int *, float (*)[4]); }; From 1d50fa088aa9dc39a8c550997f62e2deb1a50c77 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:26:24 +0200 Subject: [PATCH 0461/2040] Don't dealloc if there is no frame in the channel --- code/skeletor/skeletor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 6d3920aa..0987e17a 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -261,15 +261,17 @@ void skelAnimDataGameHeader_s::DeallocAnimData(skelAnimDataGameHeader_t *data) { skanChannelHdr *pChannel; int i; + int channelType; - if (!data || data == (skelAnimDataGameHeader_t *)-476) { + if (!data) { return; } for (i = 0; i < data->nTotalChannels; i++) { pChannel = &data->ary_channels[i]; + channelType = GetBoneChannelType(data->channelList.ChannelName(skeletor_c::ChannelNames(), i)); - if (pChannel->ary_frames) { + if (channelType != 2) { Skel_Free(pChannel->ary_frames); } } From f8fa944054064b794a45b7ce0c418a50635cea92 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:26:51 +0200 Subject: [PATCH 0462/2040] Some refactoring, + implemented SetLocalFromGlobal() --- code/skeletor/skeletor_utilities.cpp | 42 ++++++++++++++++++---------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/code/skeletor/skeletor_utilities.cpp b/code/skeletor/skeletor_utilities.cpp index a580ceb7..d369aa51 100644 --- a/code/skeletor/skeletor_utilities.cpp +++ b/code/skeletor/skeletor_utilities.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -96,6 +96,12 @@ int skelChannelList_s::GetLocalFromGlobal(int globalChannel) const return m_chanLocalFromGlobal[globalChannel]; } + +void skelChannelList_s::SetLocalFromGlobal(int channel, int localchannel) +{ + m_chanLocalFromGlobal[channel] = localchannel; +} + int skelChannelList_s::NumChannels(void) const { return m_numChannels; @@ -117,26 +123,31 @@ void skelChannelList_s::ZeroChannels() void skelChannelList_s::PackChannels() { m_numLocalFromGlobal = MAX_SKELETOR_CHANNELS - 1; - - if (m_chanLocalFromGlobal[m_numLocalFromGlobal] == -1) { - do { - m_numLocalFromGlobal--; - } while (m_chanLocalFromGlobal[m_numLocalFromGlobal] == -1 && m_numLocalFromGlobal >= 0); + for (m_numLocalFromGlobal = MAX_SKELETOR_CHANNELS - 1; m_numLocalFromGlobal >= 0; m_numLocalFromGlobal--) { + if (m_chanLocalFromGlobal[m_numLocalFromGlobal] != -1) { + break; + } } if (m_numLocalFromGlobal < MAX_SKELETOR_CHANNELS) { m_numLocalFromGlobal++; } - if (m_numLocalFromGlobal <= 0) { + if (m_numLocalFromGlobal > 0) { + short *old_array = m_chanLocalFromGlobal; + int i; + + m_chanLocalFromGlobal = (short *)Skel_Alloc(m_numLocalFromGlobal * sizeof(m_chanLocalFromGlobal[0])); + + for (i = 0; i < m_numLocalFromGlobal; i++) { + m_chanLocalFromGlobal[i] = old_array[i]; + } + + Skel_Free(old_array); + } else { Skel_Free(m_chanLocalFromGlobal); m_chanLocalFromGlobal = NULL; m_numLocalFromGlobal = -1; - } else { - short *old_array = m_chanLocalFromGlobal; - m_chanLocalFromGlobal = (short *)Skel_Alloc(m_numLocalFromGlobal * sizeof(m_chanLocalFromGlobal[0])); - memcpy(m_chanLocalFromGlobal, old_array, m_numLocalFromGlobal * sizeof(m_chanLocalFromGlobal[0])); - Skel_Free(old_array); } } @@ -170,9 +181,10 @@ int skelChannelList_s::AddChannel(int newGlobalChannelNum) iLocalChannel = GetLocalFromGlobal(newGlobalChannelNum); if (iLocalChannel < 0) { - iLocalChannel = m_numChannels++; - m_chanGlobalFromLocal[iLocalChannel] = newGlobalChannelNum; - m_chanLocalFromGlobal[newGlobalChannelNum] = iLocalChannel; + iLocalChannel = m_numChannels++; + + m_chanGlobalFromLocal[iLocalChannel] = newGlobalChannelNum; + SetLocalFromGlobal(newGlobalChannelNum, iLocalChannel); } return iLocalChannel; From aeba0e0f6fae97926ae5801efe201e1333b9a763 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:26:59 +0200 Subject: [PATCH 0463/2040] Set the real limit of MAX_SKELETOR_CHANNELS --- code/skeletor/skeletor_name_lists.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor_name_lists.h b/code/skeletor/skeletor_name_lists.h index 56b5f251..75322bfd 100644 --- a/code/skeletor/skeletor_name_lists.h +++ b/code/skeletor/skeletor_name_lists.h @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #pragma once -#define MAX_SKELETOR_CHANNELS 16384 +#define MAX_SKELETOR_CHANNELS 2560 // Limit was 2048 before 2.30 #define MAX_CHANNEL_NAME 32 typedef struct ChannelName_s { From 02ef85e390e89730497d5666b96ac2c532f81162 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:28:49 +0200 Subject: [PATCH 0464/2040] Removed GetChannelTypeFromName(), was useless --- code/skeletor/bonetable.cpp | 42 ----------------------------- code/skeletor/skeletor_name_lists.h | 1 - 2 files changed, 43 deletions(-) diff --git a/code/skeletor/bonetable.cpp b/code/skeletor/bonetable.cpp index 22a919f6..4c1a19d0 100644 --- a/code/skeletor/bonetable.cpp +++ b/code/skeletor/bonetable.cpp @@ -273,48 +273,6 @@ int GetBoneChannelType(const char* name) return 3; } -int GetChannelTypeFromName(const char *name) -{ - int i; - size_t len; - - if (!name) { - return 2; - } - - for (i = 0; i < sizeof(bogusNameTable) / sizeof(bogusNameTable[0]); i++) { - if (!Q_stricmp(name, bogusNameTable[i])) { - return 2; - } - } - - if (strstr(name, "Bip0") && !strstr(name, "Bip01") && !strstr(name, "Footsteps")) { - return 2; - } - - len = strlen(name); - - if (len >= 4) { - if (!memcmp(name + len - 4, " rot", 5)) { - return 0; - } else if (!memcmp(name + len - 4, " pos", 5)) { - return 1; - } else if (len >= 6) { - if (!memcmp(name + len - 4, " rotFK", 7)) { - return 2; - } else { - return 3; - } - } else { - return 3; - } - } else { - return 3; - } - - return false; -} - int ChannelNameTable::RegisterChannel(const char *name) { int index; diff --git a/code/skeletor/skeletor_name_lists.h b/code/skeletor/skeletor_name_lists.h index 75322bfd..33008594 100644 --- a/code/skeletor/skeletor_name_lists.h +++ b/code/skeletor/skeletor_name_lists.h @@ -58,7 +58,6 @@ private: }; int GetBoneChannelType(const char* name); -int GetChannelTypeFromName(const char *name); #else From 72e315bce1ac91082631cb3b0f8a2e6cbf511da6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:04:33 +0200 Subject: [PATCH 0465/2040] Using an enum `channelType_e` rather than raw values for bone channel types --- code/skeletor/bonetable.cpp | 16 +++++------ .../skeletor/skeletor_animation_file_format.h | 2 +- code/skeletor/skeletor_loadanimation.cpp | 28 +++++++++---------- code/skeletor/skeletor_name_lists.h | 9 +++++- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/code/skeletor/bonetable.cpp b/code/skeletor/bonetable.cpp index 4c1a19d0..53c236b5 100644 --- a/code/skeletor/bonetable.cpp +++ b/code/skeletor/bonetable.cpp @@ -241,36 +241,36 @@ bool IsBogusChannelName(const char *name) return false; } -int GetBoneChannelType(const char* name) +channelType_t GetBoneChannelType(const char* name) { size_t len; if (!name) { - return 2; + return CHANNEL_NONE; } if (IsBogusChannelName(name)) { - return 2; + return CHANNEL_NONE; } len = strlen(name); if (len < 4) { - return 3; + return CHANNEL_VALUE; } if (!strcmp(name + len - 4, " rot")) { - return 0; + return CHANNEL_ROTATION; } if (!strcmp(name + len - 4, " pos")) { - return 1; + return CHANNEL_POSITION; } if (len >= 6 && !strcmp(name + len - 6, " rotFK")) { - return 2; + return CHANNEL_NONE; } - return 3; + return CHANNEL_VALUE; } int ChannelNameTable::RegisterChannel(const char *name) diff --git a/code/skeletor/skeletor_animation_file_format.h b/code/skeletor/skeletor_animation_file_format.h index 0b953174..5a679f50 100644 --- a/code/skeletor/skeletor_animation_file_format.h +++ b/code/skeletor/skeletor_animation_file_format.h @@ -79,7 +79,7 @@ typedef struct skelAnimDataGameHeader_s skelAnimDataGameHeader_t; typedef struct skelAnimDataGameHeader_s { int flags; - int nBytesUsed; + size_t nBytesUsed; bool bHasDelta; bool bHasMorph; bool bHasUpper; diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index ed019ebd..ab0c3b31 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -71,7 +71,7 @@ skelAnimDataGameHeader_t *EncodeFrames( skanGameFrame *pFrame; size_t frameSize; int indexLastFrameAdded; - int channelType; + channelType_t channelType; pChannel = enAnim->ary_channels; endFrameCap = enAnim->numFrames - 2; @@ -82,7 +82,7 @@ skelAnimDataGameHeader_t *EncodeFrames( channelType = GetBoneChannelType(enAnim->channelList.ChannelName(channelNames, i)); switch (channelType) { - case 0: + case CHANNEL_ROTATION: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); frameCnt = 0; for (j = 0; j < enAnim->numFrames; j++) { @@ -125,7 +125,7 @@ skelAnimDataGameHeader_t *EncodeFrames( pCurrFrame++; } break; - case 1: + case CHANNEL_POSITION: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); frameCnt = 0; for (j = 0; j < enAnim->numFrames; j++) { @@ -167,11 +167,11 @@ skelAnimDataGameHeader_t *EncodeFrames( pCurrFrame++; } break; - case 2: + case CHANNEL_NONE: pChannel->ary_frames = NULL; pChannel->nFramesInChannel = 0; break; - case 3: + case CHANNEL_VALUE: default: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float)); frameCnt = 0; @@ -433,7 +433,7 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) size_t frameSize; int frameCnt; int i, j; - int channelType; + channelType_t channelType; vec4_t channelData; for (i = 0; i < enAnim->nTotalChannels; i++) { @@ -443,7 +443,7 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) frameCnt = MSG_ReadShort(msg); switch (channelType) { - case 0: + case CHANNEL_ROTATION: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); @@ -462,7 +462,7 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->pChannelData[3] = LittleFloat(channelData[3]); } break; - case 1: + case CHANNEL_POSITION: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); @@ -480,7 +480,7 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->pChannelData[2] = LittleFloat(channelData[2]); } break; - case 2: + case CHANNEL_NONE: pChannel->ary_frames = NULL; pChannel->nFramesInChannel = 0; @@ -490,7 +490,7 @@ void ReadEncodedFrames(msg_t *msg, skelAnimDataGameHeader_t *enAnim) MSG_ReadData(msg, channelData, sizeof(vec4_t)); } break; - case 3: + case CHANNEL_VALUE: default: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float)); @@ -521,7 +521,7 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) int frameCnt; int i, j; const char *name; - int type; + channelType_t type; for (i = 0; i < enAnim->nTotalChannels; i++) { pChannel = &enAnim->ary_channels[i]; @@ -534,7 +534,7 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) // // 4 channels (Quat) // - case 0: + case CHANNEL_ROTATION: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec4_t)); pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); pChannel->ary_frames = pFrame; @@ -553,7 +553,7 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) // // 3 channels (Position) // - case 1: + case CHANNEL_POSITION: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(vec3_t)); pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); pChannel->ary_frames = pFrame; @@ -571,7 +571,7 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) // // 1 channel (frame) // - case 3: + case CHANNEL_VALUE: frameSize = (sizeof(skanGameFrame) - sizeof(skanGameFrame::pChannelData) + sizeof(float) * 1); pFrame = (skanGameFrame *)Skel_Alloc(frameSize * frameCnt); pChannel->ary_frames = pFrame; diff --git a/code/skeletor/skeletor_name_lists.h b/code/skeletor/skeletor_name_lists.h index 33008594..71d2fdd7 100644 --- a/code/skeletor/skeletor_name_lists.h +++ b/code/skeletor/skeletor_name_lists.h @@ -57,7 +57,14 @@ private: void SetChannelName(ChannelName_t *channel, const char *newName); }; -int GetBoneChannelType(const char* name); +typedef enum channelType_e { + CHANNEL_ROTATION, + CHANNEL_POSITION, + CHANNEL_NONE, + CHANNEL_VALUE +} channelType_t; + +channelType_t GetBoneChannelType(const char* name); #else From de874874e4acd9357b55b53934c58ab6d71e8eda Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:10:28 +0200 Subject: [PATCH 0466/2040] Use an enum for setup case rather than raw values --- code/tiki/tiki_parse.cpp | 87 ++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 34 deletions(-) diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index f4300ec9..87500c9f 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -28,6 +28,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../skeletor/skeletor.h" #include +typedef enum tiki_setupcase_e { + SETUP_END_MESSAGE = -1, + SETUP_LOAD_SCALE, + SETUP_LOD_SCALE, + SETUP_LOD_BIAS, + SETUP_SKELMODEL, + SETUP_LOAD_ORIGIN, + SETUP_LIGHT_OFFSET, + SETUP_RADIUS, + SETUP_SURFACE, + SETUP_FLAGS, + SETUP_DAMAGE, + SETUP_SHADER, + SETUP_CASE_KEY, + SETUP_CASE_VALUE, + SETUP_BEGIN_CASE, + SETUP_BEGIN_CASE_BODY, + SETUP_END_CASE +} tiki_setupcase_t; + /* =============== TIKI_FileExtension @@ -523,7 +543,7 @@ WriteScale */ static void WriteScale(dloaddef_t *ld, float scale) { - MSG_WriteByte(ld->modelBuf, 0); + MSG_WriteByte(ld->modelBuf, SETUP_LOAD_SCALE); MSG_WriteFloat(ld->modelBuf, scale); } @@ -534,7 +554,7 @@ WriteLoadScale */ static void WriteLoadScale(dloaddef_t *ld, float lod_scale) { - MSG_WriteByte(ld->modelBuf, 1); + MSG_WriteByte(ld->modelBuf, SETUP_LOD_SCALE); MSG_WriteFloat(ld->modelBuf, lod_scale); } @@ -545,7 +565,7 @@ WriteLodBias */ static void WriteLodBias(dloaddef_t *ld, float lod_bias) { - MSG_WriteByte(ld->modelBuf, 2); + MSG_WriteByte(ld->modelBuf, SETUP_LOD_BIAS); MSG_WriteFloat(ld->modelBuf, lod_bias); } @@ -556,7 +576,7 @@ WriteSkelmodel */ void WriteSkelmodel(dloaddef_t *ld, const char *name) { - MSG_WriteByte(ld->modelBuf, 3); + MSG_WriteByte(ld->modelBuf, SETUP_SKELMODEL); MSG_WriteString(ld->modelBuf, name); Q_strncpyz(ld->idleSkel, name, sizeof(ld->idleSkel)); @@ -570,7 +590,7 @@ WriteOrigin */ static void WriteOrigin(dloaddef_t *ld, float origin_x, float origin_y, float origin_z) { - MSG_WriteByte(ld->modelBuf, 4); + MSG_WriteByte(ld->modelBuf, SETUP_LOAD_ORIGIN); MSG_WriteFloat(ld->modelBuf, origin_x); MSG_WriteFloat(ld->modelBuf, origin_y); MSG_WriteFloat(ld->modelBuf, origin_z); @@ -583,7 +603,7 @@ WriteLightOffset */ static void WriteLightOffset(dloaddef_t *ld, float light_offset_x, float light_offset_y, float light_offset_z) { - MSG_WriteByte(ld->modelBuf, 5); + MSG_WriteByte(ld->modelBuf, SETUP_LIGHT_OFFSET); MSG_WriteFloat(ld->modelBuf, light_offset_x); MSG_WriteFloat(ld->modelBuf, light_offset_y); MSG_WriteFloat(ld->modelBuf, light_offset_z); @@ -596,7 +616,7 @@ WriteRadius */ static void WriteRadius(dloaddef_t *ld, float radius) { - MSG_WriteByte(ld->modelBuf, 6); + MSG_WriteByte(ld->modelBuf, SETUP_RADIUS); MSG_WriteFloat(ld->modelBuf, radius); } @@ -607,7 +627,7 @@ WriteSurface */ static void WriteSurface(dloaddef_t *ld, const char *surface) { - MSG_WriteByte(ld->modelBuf, 7); + MSG_WriteByte(ld->modelBuf, SETUP_SURFACE); MSG_WriteString(ld->modelBuf, surface); } @@ -618,7 +638,7 @@ WriteFlags */ static void WriteFlags(dloaddef_t *ld, int flags) { - MSG_WriteByte(ld->modelBuf, 8); + MSG_WriteByte(ld->modelBuf, SETUP_FLAGS); MSG_WriteLong(ld->modelBuf, flags); } @@ -629,7 +649,7 @@ WriteDamage */ static void WriteDamage(dloaddef_t *ld, float damage) { - MSG_WriteByte(ld->modelBuf, 9); + MSG_WriteByte(ld->modelBuf, SETUP_DAMAGE); MSG_WriteFloat(ld->modelBuf, damage); } @@ -640,7 +660,7 @@ WriteShader */ static void WriteShader(dloaddef_t *ld, const char *shader) { - MSG_WriteByte(ld->modelBuf, 10); + MSG_WriteByte(ld->modelBuf, SETUP_SHADER); MSG_WriteString(ld->modelBuf, shader); } @@ -651,7 +671,7 @@ WriteBeginCase */ static void WriteBeginCase(dloaddef_t *ld) { - MSG_WriteByte(ld->modelBuf, 13); + MSG_WriteByte(ld->modelBuf, SETUP_BEGIN_CASE); } /* @@ -661,7 +681,7 @@ WriteCaseKey */ static void WriteCaseKey(dloaddef_t *ld, const char *key) { - MSG_WriteByte(ld->modelBuf, 11); + MSG_WriteByte(ld->modelBuf, SETUP_CASE_KEY); MSG_WriteString(ld->modelBuf, key); } @@ -672,7 +692,7 @@ WriteCaseValue */ static void WriteCaseValue(dloaddef_t *ld, const char *value) { - MSG_WriteByte(ld->modelBuf, 12); + MSG_WriteByte(ld->modelBuf, SETUP_CASE_VALUE); MSG_WriteString(ld->modelBuf, value); } @@ -683,7 +703,7 @@ WriteBeginCaseBody */ static void WriteBeginCaseBody(dloaddef_t *ld) { - MSG_WriteByte(ld->modelBuf, 14); + MSG_WriteByte(ld->modelBuf, SETUP_BEGIN_CASE_BODY); } /* @@ -693,7 +713,7 @@ WriteEndCase */ static void WriteEndCase(dloaddef_t *ld) { - MSG_WriteByte(ld->modelBuf, 15); + MSG_WriteByte(ld->modelBuf, SETUP_END_CASE); } /* @@ -727,14 +747,14 @@ qboolean TIKI_LoadSetupCaseHeader( const char *value; qboolean match = false; - while (c != 14) { + while (c != SETUP_BEGIN_CASE_BODY) { c = MSG_ReadByte(msg); switch (c) { - case 11: + case SETUP_CASE_KEY: value = MSG_ReadString(msg); key = value; break; - case 12: + case SETUP_CASE_VALUE: value = MSG_ReadString(msg); if (skip || match || !keyValues) { break; @@ -745,7 +765,6 @@ qboolean TIKI_LoadSetupCaseHeader( match = true; } break; - case 14: default: break; } @@ -788,28 +807,28 @@ qboolean TIKI_LoadSetupCase( switch (c) { default: break; - case 0: + case SETUP_LOAD_SCALE: load_scale = MSG_ReadFloat(msg); if (skip) { break; } tiki->load_scale = load_scale; break; - case 1: + case SETUP_LOD_SCALE: lod_scale = MSG_ReadFloat(msg); if (skip) { break; } tiki->lod_scale = lod_scale; break; - case 2: + case SETUP_LOD_BIAS: lod_bias = MSG_ReadFloat(msg); if (skip) { break; } tiki->lod_bias = lod_bias; break; - case 3: + case SETUP_SKELMODEL: name = MSG_ReadString(msg); if (skip) { break; @@ -830,7 +849,7 @@ qboolean TIKI_LoadSetupCase( tiki->num_surfaces += skelmodel->numSurfaces; tiki->numMeshes++; break; - case 4: + case SETUP_LOAD_ORIGIN: load_origin[0] = MSG_ReadFloat(msg); load_origin[1] = MSG_ReadFloat(msg); load_origin[2] = MSG_ReadFloat(msg); @@ -839,7 +858,7 @@ qboolean TIKI_LoadSetupCase( } VectorCopy(load_origin, tiki->load_origin); break; - case 5: + case SETUP_LIGHT_OFFSET: light_offset[0] = MSG_ReadFloat(msg); light_offset[1] = MSG_ReadFloat(msg); light_offset[2] = MSG_ReadFloat(msg); @@ -848,14 +867,14 @@ qboolean TIKI_LoadSetupCase( } VectorCopy(light_offset, tiki->load_origin); break; - case 6: + case SETUP_RADIUS: radius = MSG_ReadFloat(msg); if (skip) { break; } tiki->radius = radius; break; - case 7: + case SETUP_SURFACE: name = MSG_ReadString(msg); if (skip) { break; @@ -873,21 +892,21 @@ qboolean TIKI_LoadSetupCase( } strcpy(loadsurfaces[currentSurface].name, name); break; - case 8: + case SETUP_FLAGS: flags = MSG_ReadLong(msg); if (skip) { break; } loadsurfaces[currentSurface].flags |= flags; break; - case 9: + case SETUP_DAMAGE: damage_multiplier = MSG_ReadFloat(msg); if (skip) { break; } loadsurfaces[currentSurface].damage_multiplier = damage_multiplier; break; - case 10: + case SETUP_SHADER: name = MSG_ReadString(msg); if (skip) { break; @@ -909,13 +928,13 @@ qboolean TIKI_LoadSetupCase( ); loadsurfaces[currentSurface].numskins++; break; - case 13: + case SETUP_BEGIN_CASE: if (!TIKI_LoadSetupCaseHeader(tiki, filename, loadsurfaces, numSurfacesSetUp, msg, skip, keyValues)) { return false; } break; - case -1: - case 15: + case SETUP_END_MESSAGE: + case SETUP_END_CASE: return true; } } From 10e3192f856cc9520f3a8848f1cfd136d6bfeeb8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:24:01 +0200 Subject: [PATCH 0467/2040] Fixed MASK_PLAYERSOLID being wrong --- code/fgame/bg_public.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index dcdbc48a..af881c1e 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -610,9 +610,7 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX | CONTENTS_FENCE) #define MASK_SAFESOLID (CONTENTS_BODY | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX) #define MASK_USABLE (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BODY) -#define MASK_PLAYERSOLID \ - (CONTENTS_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_BODY | CONTENTS_TRIGGER | CONTENTS_FENCE | CONTENTS_UNKNOWN2 \ - | CONTENTS_NOBOTCLIP | CONTENTS_BBOX) +#define MASK_PLAYERSOLID (CONTENTS_TRIGGER | CONTENTS_BODY | CONTENTS_WEAPONCLIP | CONTENTS_FENCE | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX | CONTENTS_SOLID) #define MASK_GUNTARGET \ (CONTENTS_SOLID | CONTENTS_LADDER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_CLAYPIDGEON | CONTENTS_BBOX \ | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_UNKNOWN3 | CONTENTS_FENCE | CONTENTS_BODY | CONTENTS_CORPSE \ From fd3a36f162e84da9a5e3388910338e4792fd7b13 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:30:19 +0200 Subject: [PATCH 0468/2040] Fixed melee sometimes not making the hit sound --- code/fgame/weaputils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index d611e81c..fb737103 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -168,7 +168,7 @@ qboolean MeleeAttack( victim->Damage(attacker, attacker, damage, pos, dir, vec_zero, knockback, 0, means_of_death); - if (victim->edict->r.contents & CONTENTS_SOLID) { + if (!(victim->edict->r.contents & CONTENTS_CLAYPIDGEON)) { victim->Sound("pistol_hit"); } } From 84d702838d72f2d523b65ad16ee1e531cc691947 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:58:31 +0200 Subject: [PATCH 0469/2040] Implemented Player::MeasureLandmineDistances() This makes minedetector actually detect mines, especially on `e1l2` --- code/fgame/player_conditionals.cpp | 85 +++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/code/fgame/player_conditionals.cpp b/code/fgame/player_conditionals.cpp index 71dd43ad..4c2d5d93 100644 --- a/code/fgame/player_conditionals.cpp +++ b/code/fgame/player_conditionals.cpp @@ -433,7 +433,90 @@ qboolean Player::CondNearLandmine(Conditional& condition) void Player::MeasureLandmineDistances() { - // FIXME: unimplemented + Weapon* weapon; + float previousMineDist; + float maxrange; + int i; + + if (m_fMineCheckTime == level.time) { + return; + } + m_fMineCheckTime = level.time; + previousMineDist = m_fMineDist; + m_fMineDist = 1000; + + weapon = GetActiveWeapon(WEAPON_MAIN); + if (!weapon) { + weapon = GetActiveWeapon(WEAPON_OFFHAND); + } + + maxrange = 40; + if (weapon) { + maxrange = weapon->GetMaxRange(); + } + + for (i = 0; i < globals.max_entities; i++) { + TriggerLandmine* landmine; + Entity* ent; + vec3_t forward; + Vector delta; + float radius; + + ent = G_GetEntity(i); + if (!ent) { + continue; + } + + if (!ent->isSubclassOf(TriggerLandmine)) { + continue; + } + + landmine = static_cast(ent); + // This could be from an allied player + if (landmine->IsImmune(this)) { + continue; + } + + AngleVectorsLeft(angles, forward, NULL, NULL); + delta = landmine->origin - origin; + radius = delta.length(); + + if (radius < maxrange) { + ent->PostEvent(EV_Show, level.frametime); + } + + if (radius > m_fMineDist) { + continue; + } + + if (radius >= 40) { + float dot; + + delta.normalize(); + + dot = DotProduct(delta, forward); + if (dot > 0 && radius / Square(dot) < m_fMineDist) { + m_fMineDist = radius / Square(dot); + } + } else if (radius < m_fMineDist) { + m_fMineDist = radius; + } + } + + m_fMineDist /= maxrange; + + if (m_fMineDist > 3) { + StopLoopSound(); + return; + } + + if (floorf(previousMineDist * 20) != floorf(m_fMineDist * 20)) { + float pitch; + + pitch = 2.f - log(m_fMineDist + 1.0); + + LoopSound("minedetector_on", -1, -1, -1, pitch); + } } qboolean Player::CondIsAssistingEscape(Conditional& condition) From 85bf56ae03df0e4a0493cd7f6439846440f8ec1a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 14 Jun 2024 21:19:04 +0200 Subject: [PATCH 0470/2040] Call SetWeight() rather than setting it manually --- code/fgame/animate.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/fgame/animate.cpp b/code/fgame/animate.cpp index 56eef6c7..38483961 100644 --- a/code/fgame/animate.cpp +++ b/code/fgame/animate.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -508,9 +508,8 @@ void Animate::StopAnimating(int slot) edict->s.frameInfo[slot].index = 1; } - edict->s.frameInfo[slot].weight = 0.0f; - animFlags[slot] = ANIM_LOOP | ANIM_NODELTA | ANIM_NOEXIT | ANIM_PAUSED; + SetWeight(slot, 0); animtimes[slot] = 0.0f; SlotChanged(slot); From 91497d8fa7d58f1d3770347c5d3e9fde3aa4383a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 14 Jun 2024 21:20:15 +0200 Subject: [PATCH 0471/2040] Implements `Player::EventTestAnim()` --- code/fgame/player.h | 5 +++-- code/fgame/player_animation.cpp | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/code/fgame/player.h b/code/fgame/player.h index 5eebc593..a67ece67 100644 --- a/code/fgame/player.h +++ b/code/fgame/player.h @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -68,7 +68,8 @@ enum painDirection_t { }; typedef enum { - ANIMSLOT_PAIN = 4 + ANIMSLOT_PAIN = 4, + ANIMSLOT_TESTANIM = 7 } playerAnimSlot_t; typedef enum { diff --git a/code/fgame/player_animation.cpp b/code/fgame/player_animation.cpp index a8098fe1..5f9070e1 100644 --- a/code/fgame/player_animation.cpp +++ b/code/fgame/player_animation.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -515,5 +515,28 @@ void Player::PlayerAnimDelta(float *vDelta) void Player::EventTestAnim(Event *ev) { - // FIXME: unimplemented + str name; + float weight; + int animNum; + + weight = ev->GetFloat(1); + if (weight <= 0) { + SetWeight(ANIMSLOT_TESTANIM, 0); + StopAnimating(ANIMSLOT_TESTANIM); + return; + } + + if (ev->NumArgs() > 1) { + name = ev->GetString(1); + animNum = gi.Anim_NumForName(edict->tiki, name.c_str()); + if (animNum == -1) { + gi.Printf("Couldn't find anim '%s'\n", name.c_str()); + return; + } + + NewAnim(animNum, ANIMSLOT_TESTANIM, weight); + RestartAnimSlot(ANIMSLOT_TESTANIM); + } + + SetWeight(ANIMSLOT_TESTANIM, weight); } From 6b869c4c0d9e0849dd8eb8a88cf22378c41aac41 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 14 Jun 2024 21:26:44 +0200 Subject: [PATCH 0472/2040] Use an enumeration instead of raw values --- code/cgame/cg_parsemsg.cpp | 246 +++++++++++++++++++------------------ 1 file changed, 124 insertions(+), 122 deletions(-) diff --git a/code/cgame/cg_parsemsg.cpp b/code/cgame/cg_parsemsg.cpp index 5b261792..9d7ebfe6 100644 --- a/code/cgame/cg_parsemsg.cpp +++ b/code/cgame/cg_parsemsg.cpp @@ -859,14 +859,14 @@ void CG_AddBulletImpacts() } if (fImpSndDistRA < fImpSndDistLA) { - if (wall_impact_type[iImpSndIndexRA]) { + if (wall_impact_type[iImpSndIndexRA] != SFX_BHIT_PAPER_LITE) { if (wall_impact_large[iImpSndIndexRA]) { fVolume = 1.f; } else { fVolume = 0.75f; } - if (wall_impact_type[iImpSndIndexRA] == 2 || wall_impact_type[iImpSndIndexRA] == 3) { + if (wall_impact_type[iImpSndIndexRA] == SFX_BHIT_WOOD_LITE || wall_impact_type[iImpSndIndexRA] == SFX_BHIT_WOOD_HARD) { sSoundName = "snd_bh_metal"; } else { sSoundName = "snd_bh_wood"; @@ -897,7 +897,7 @@ void CG_AddBulletImpacts() fVolume = 0.75f; } - if (wall_impact_type[iImpSndIndexRB] == 2 || wall_impact_type[iImpSndIndexRB] == 3) { + if (wall_impact_type[iImpSndIndexRB] == SFX_BHIT_WOOD_LITE || wall_impact_type[iImpSndIndexRB] == SFX_BHIT_WOOD_HARD) { sSoundName = "snd_bh_metal"; } else { sSoundName = "snd_bh_wood"; @@ -923,14 +923,14 @@ void CG_AddBulletImpacts() } if (fImpSndDistLA > 9999.0f) { - if (wall_impact_type[0]) { + if (wall_impact_type[0] != SFX_BHIT_PAPER_LITE) { if (wall_impact_large[0]) { fVolume = 1.f; } else { fVolume = 0.75f; } - if (wall_impact_type[0] == 2 || wall_impact_type[0] == 3) { + if (wall_impact_type[0] == SFX_BHIT_WOOD_LITE || wall_impact_type[0] == SFX_BHIT_WOOD_HARD) { sSoundName = "snd_bh_metal"; } else { sSoundName = "snd_bh_wood"; @@ -945,14 +945,14 @@ void CG_AddBulletImpacts() } if (fImpSndDistLB < fImpSndDistLA) { - if (wall_impact_type[iImpSndIndexLB]) { + if (wall_impact_type[iImpSndIndexLB] != SFX_BHIT_PAPER_LITE) { if (wall_impact_large[iImpSndIndexLB]) { fVolume = 1.f; } else { fVolume = 0.75f; } - if (wall_impact_type[iImpSndIndexLB] == 2 || wall_impact_type[iImpSndIndexLB] == 3) { + if (wall_impact_type[iImpSndIndexLB] == SFX_BHIT_WOOD_LITE || wall_impact_type[iImpSndIndexLB] == SFX_BHIT_WOOD_HARD) { sSoundName = "snd_bh_metal"; } else { sSoundName = "snd_bh_wood"; @@ -1033,16 +1033,16 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) if (cg_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { switch (iType) { - case 13: + case CGM_EXPLOSION_EFFECT_1: iBaseEffect = SFX_EXP_GREN_BASE; break; - case 14: + case CGM_EXPLOSION_EFFECT_2: iBaseEffect = SFX_EXP_BAZOOKA_BASE; break; - case 15: + case CGM_EXPLOSION_EFFECT_3: iBaseEffect = SFX_EXP_HEAVYSHELL_BASE; break; - case 16: + case CGM_EXPLOSION_EFFECT_4: iBaseEffect = SFX_EXP_TANK_BASE; break; default: @@ -1051,7 +1051,7 @@ void CG_MakeExplosionEffect(const vec3_t vPos, int iType) } } else { switch (iType) { - case 13: + case CGM6_EXPLOSION_EFFECT_2: iBaseEffect = SFX_EXP_BAZOOKA_BASE; break; default: @@ -1274,10 +1274,10 @@ void CG_ParseCGMessage_ver_15() iType = cgi.MSG_ReadBits(6); switch (iType) { - case 1: - case 2: - case 5: - if (iType == 1) { + case CGM_BULLET_1: + case CGM_BULLET_2: + case CGM_BULLET_5: + if (iType == CGM_BULLET_1) { vTmp[0] = cgi.MSG_ReadCoord(); vTmp[1] = cgi.MSG_ReadCoord(); vTmp[2] = cgi.MSG_ReadCoord(); @@ -1286,7 +1286,7 @@ void CG_ParseCGMessage_ver_15() vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); - if (iType != 1) { + if (iType != CGM_BULLET_1) { vTmp[0] = vStart[0]; vTmp[1] = vStart[1]; vTmp[2] = vStart[2]; @@ -1306,18 +1306,18 @@ void CG_ParseCGMessage_ver_15() alpha = 1.0f; } - if (iType == 1) { - CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue, alpha); - } else if (iType == 2) { + if (iType == CGM_BULLET_1) { + CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue, alpha); + } else if (iType == CGM_BULLET_2) { CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue, alpha); } else { CG_MakeBubbleTrail(vStart, vEndArray[0], iLarge, alpha); } break; - case 3: - case 4: - if (iType == 3) { + case CGM_BULLET_3: + case CGM_BULLET_4: + if (iType == CGM_BULLET_3) { vTmp[0] = cgi.MSG_ReadCoord(); vTmp[1] = cgi.MSG_ReadCoord(); vTmp[2] = cgi.MSG_ReadCoord(); @@ -1351,12 +1351,12 @@ void CG_ParseCGMessage_ver_15() CG_MakeBulletTracer(vTmp, vStart, vEndArray, iCount, iLarge, iInfo, qtrue, alpha); } break; - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: + case CGM_BULLET_6: + case CGM_BULLET_7: + case CGM_BULLET_8: + case CGM_BULLET_9: + case CGM_BULLET_10: + case CGM_BULLET_11: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); @@ -1364,7 +1364,7 @@ void CG_ParseCGMessage_ver_15() iLarge = cgi.MSG_ReadBits(2); switch (iType) { - case 6: + case CGM_BULLET_6: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); @@ -1373,16 +1373,16 @@ void CG_ParseCGMessage_ver_15() wall_impact_count++; } break; - case 7: + case CGM_BULLET_7: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); wall_impact_large[wall_impact_count] = iLarge; - wall_impact_type[wall_impact_count] = 6; + wall_impact_type[wall_impact_count] = SFX_BHIT_STONE_LITE; wall_impact_count++; } break; - case 8: + case CGM_BULLET_8: if (flesh_impact_count < MAX_IMPACTS) { // negative VectorNegate(vEnd, vEnd); @@ -1392,7 +1392,7 @@ void CG_ParseCGMessage_ver_15() flesh_impact_count++; } break; - case 9: + case CGM_BULLET_9: if (flesh_impact_count < MAX_IMPACTS) { // negative VectorNegate(vEnd, vEnd); @@ -1402,21 +1402,21 @@ void CG_ParseCGMessage_ver_15() flesh_impact_count++; } break; - case 10: + case CGM_BULLET_10: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); wall_impact_large[wall_impact_count] = iLarge; - wall_impact_type[wall_impact_count] = 2; + wall_impact_type[wall_impact_count] = SFX_BHIT_WOOD_LITE; wall_impact_count++; } break; - case 11: + case CGM_BULLET_11: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); wall_impact_large[wall_impact_count] = iLarge; - wall_impact_type[wall_impact_count] = 4; + wall_impact_type[wall_impact_count] = SFX_BHIT_METAL_LITE; wall_impact_count++; } break; @@ -1425,7 +1425,7 @@ void CG_ParseCGMessage_ver_15() } break; - case 12: + case CGM_MELEE_IMPACT: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); @@ -1434,33 +1434,33 @@ void CG_ParseCGMessage_ver_15() vEnd[2] = cgi.MSG_ReadCoord(); CG_MeleeImpact(vStart, vEnd); break; - case 13: - case 14: - case 15: - case 16: + case CGM_EXPLOSION_EFFECT_1: + case CGM_EXPLOSION_EFFECT_2: + case CGM_EXPLOSION_EFFECT_3: + case CGM_EXPLOSION_EFFECT_4: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); CG_MakeExplosionEffect(vStart, iType); break; - case 18: - case 19: - case 20: - case 21: - case 22: - case 23: - case 24: - case 25: + case CGM_MAKE_EFFECT_1: + case CGM_MAKE_EFFECT_2: + case CGM_MAKE_EFFECT_3: + case CGM_MAKE_EFFECT_4: + case CGM_MAKE_EFFECT_5: + case CGM_MAKE_EFFECT_6: + case CGM_MAKE_EFFECT_7: + case CGM_MAKE_EFFECT_8: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); cgi.MSG_ReadDir(vEnd); - sfxManager.MakeEffect_Normal(iType + SFX_EXP_GREN_PUDDLE, vStart, vEnd); + sfxManager.MakeEffect_Normal(SFX_EXP_GREN_PUDDLE + iType, vStart, vEnd); break; - case 26: - case 27: + case CGM_MAKE_CRATE_DEBRIS: + case CGM_MAKE_WINDOW_DEBRIS: { str sEffect; char cTmp[8]; @@ -1473,7 +1473,7 @@ void CG_ParseCGMessage_ver_15() // get the integer as string snprintf(cTmp, sizeof(cTmp), "%d", iLarge); - if (iType == 26) { + if (iType == CGM_MAKE_CRATE_DEBRIS) { sEffect = "models/fx/crates/debris_"; } else { sEffect = "models/fx/windows/debris_"; @@ -1490,7 +1490,7 @@ void CG_ParseCGMessage_ver_15() } break; - case 28: + case CGM_BULLET_NO_BARREL_1: vTmp[0] = cgi.MSG_ReadCoord(); vTmp[1] = cgi.MSG_ReadCoord(); vTmp[2] = cgi.MSG_ReadCoord(); @@ -1501,6 +1501,7 @@ void CG_ParseCGMessage_ver_15() vEndArray[0][1] = cgi.MSG_ReadCoord(); vEndArray[0][2] = cgi.MSG_ReadCoord(); iLarge = cgi.MSG_ReadBits(2); + if (cgi.MSG_ReadBits(1)) { int iAlpha = cgi.MSG_ReadBits(10); alpha = (float)iAlpha / 512.0; @@ -1514,7 +1515,7 @@ void CG_ParseCGMessage_ver_15() CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue, alpha); break; - case 29: + case CGM_BULLET_NO_BARREL_2: memset(vTmp, 0, sizeof(vTmp)); vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); @@ -1523,6 +1524,7 @@ void CG_ParseCGMessage_ver_15() vEndArray[0][1] = cgi.MSG_ReadCoord(); vEndArray[0][2] = cgi.MSG_ReadCoord(); iLarge = cgi.MSG_ReadBits(1); + if (cgi.MSG_ReadBits(1)) { int iAlpha = cgi.MSG_ReadBits(10); alpha = (float)iAlpha / 512.0; @@ -1536,7 +1538,7 @@ void CG_ParseCGMessage_ver_15() CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue, alpha); break; - case 30: + case CGM_HUDDRAW_SHADER: iInfo = cgi.MSG_ReadByte(); strcpy(cgi.HudDrawElements[iInfo].shaderName, cgi.MSG_ReadString()); cgi.HudDrawElements[iInfo].string[0] = 0; @@ -1546,13 +1548,13 @@ void CG_ParseCGMessage_ver_15() CG_HudDrawShader(iInfo); break; - case 31: + case CGM_HUDDRAW_ALIGN: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].iHorizontalAlign = cgi.MSG_ReadBits(2); cgi.HudDrawElements[iInfo].iVerticalAlign = cgi.MSG_ReadBits(2); break; - case 32: + case CGM_HUDDRAW_RECT: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].iX = cgi.MSG_ReadShort(); cgi.HudDrawElements[iInfo].iY = cgi.MSG_ReadShort(); @@ -1560,30 +1562,30 @@ void CG_ParseCGMessage_ver_15() cgi.HudDrawElements[iInfo].iHeight = cgi.MSG_ReadShort(); break; - case 33: + case CGM_HUDDRAW_VIRTUALSIZE: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].bVirtualScreen = cgi.MSG_ReadBits(1); break; - case 34: + case CGM_HUDDRAW_COLOR: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].vColor[0] = cgi.MSG_ReadByte() / 255.0; cgi.HudDrawElements[iInfo].vColor[1] = cgi.MSG_ReadByte() / 255.0; cgi.HudDrawElements[iInfo].vColor[2] = cgi.MSG_ReadByte() / 255.0; break; - case 35: + case CGM_HUDDRAW_ALPHA: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].vColor[3] = cgi.MSG_ReadByte() / 255.0; break; - case 36: + case CGM_HUDDRAW_STRING: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].hShader = 0; strcpy(cgi.HudDrawElements[iInfo].string, cgi.MSG_ReadString()); break; - case 37: + case CGM_HUDDRAW_FONT: iInfo = cgi.MSG_ReadByte(); strcpy(cgi.HudDrawElements[iInfo].fontName, cgi.MSG_ReadString()); cgi.HudDrawElements[iInfo].hShader = 0; @@ -1592,14 +1594,14 @@ void CG_ParseCGMessage_ver_15() CG_HudDrawFont(iInfo); break; - case 38: - case 39: + case CGM_NOTIFY_KILL: + case CGM_NOTIFY_HIT: { int iOldEnt; iOldEnt = current_entity_number; current_entity_number = cg.snap->ps.clientNum; - if (iType == 36) { + if (iType == CGM_NOTIFY_HIT) { commandManager.PlaySound("dm_kill_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1); } else { commandManager.PlaySound("dm_hit_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1); @@ -1609,7 +1611,7 @@ void CG_ParseCGMessage_ver_15() } break; - case 40: + case CGM_VOICE_CHAT: { int iOldEnt; @@ -1635,7 +1637,7 @@ void CG_ParseCGMessage_ver_15() current_entity_number = iOldEnt; } break; - case 41: + case CGM_FENCEPOST: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); @@ -1674,10 +1676,10 @@ void CG_ParseCGMessage_ver_6() iType = cgi.MSG_ReadBits(6); switch (iType) { - case 1: - case 2: - case 5: - if (iType == 1) { + case CGM6_BULLET_1: + case CGM6_BULLET_2: + case CGM6_BULLET_5: + if (iType == CGM6_BULLET_1) { vTmp[0] = cgi.MSG_ReadCoord(); vTmp[1] = cgi.MSG_ReadCoord(); vTmp[2] = cgi.MSG_ReadCoord(); @@ -1686,7 +1688,7 @@ void CG_ParseCGMessage_ver_6() vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); - if (iType != 1) { + if (iType != CGM6_BULLET_1) { vTmp[0] = vStart[0]; vTmp[1] = vStart[1]; vTmp[2] = vStart[2]; @@ -1697,18 +1699,18 @@ void CG_ParseCGMessage_ver_6() vEndArray[0][2] = cgi.MSG_ReadCoord(); iLarge = cgi.MSG_ReadBits(1); - if (iType == 1) { + if (iType == CGM6_BULLET_1) { CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue); - } else if (iType == 2) { + } else if (iType == CGM6_BULLET_2) { CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue); } else { CG_MakeBubbleTrail(vStart, vEndArray[0], iLarge); } break; - case 3: - case 4: - if (iType == 3) { + case CGM6_BULLET_3: + case CGM6_BULLET_4: + if (iType == CGM6_BULLET_3) { vTmp[0] = cgi.MSG_ReadCoord(); vTmp[1] = cgi.MSG_ReadCoord(); vTmp[2] = cgi.MSG_ReadCoord(); @@ -1732,11 +1734,11 @@ void CG_ParseCGMessage_ver_6() CG_MakeBulletTracer(vTmp, vStart, vEndArray, iCount, iLarge, iInfo, qtrue); } break; - case 6: - case 7: - case 8: - case 9: - case 10: + case CGM6_BULLET_6: + case CGM6_BULLET_7: + case CGM6_BULLET_8: + case CGM6_BULLET_9: + case CGM6_BULLET_10: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); @@ -1744,16 +1746,16 @@ void CG_ParseCGMessage_ver_6() iLarge = cgi.MSG_ReadBits(1); switch (iType) { - case 6: + case CGM6_BULLET_6: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); wall_impact_large[wall_impact_count] = iLarge; - wall_impact_type[wall_impact_count] = 0; + wall_impact_type[wall_impact_count] = SFX_BHIT_PAPER_LITE; wall_impact_count++; } break; - case 7: + case CGM6_BULLET_7: if (flesh_impact_count < MAX_IMPACTS) { // negative VectorNegate(vEnd, vEnd); @@ -1763,7 +1765,7 @@ void CG_ParseCGMessage_ver_6() flesh_impact_count++; } break; - case 8: + case CGM6_BULLET_8: if (flesh_impact_count < MAX_IMPACTS) { // negative VectorNegate(vEnd, vEnd); @@ -1773,21 +1775,21 @@ void CG_ParseCGMessage_ver_6() flesh_impact_count++; } break; - case 9: + case CGM6_BULLET_9: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); wall_impact_large[wall_impact_count] = iLarge; - wall_impact_type[wall_impact_count] = (iLarge != 0) + 2; + wall_impact_type[wall_impact_count] = iLarge ? SFX_BHIT_WOOD_HARD : SFX_BHIT_WOOD_LITE; wall_impact_count++; } break; - case 10: + case CGM6_BULLET_10: if (wall_impact_count < MAX_IMPACTS) { VectorCopy(vStart, wall_impact_pos[wall_impact_count]); VectorCopy(vEnd, wall_impact_norm[wall_impact_count]); wall_impact_large[wall_impact_count] = iLarge; - wall_impact_type[wall_impact_count] = (iLarge != 0) + 4; + wall_impact_type[wall_impact_count] = iLarge ? SFX_BHIT_METAL_HARD : SFX_BHIT_METAL_LITE; wall_impact_count++; } break; @@ -1796,7 +1798,7 @@ void CG_ParseCGMessage_ver_6() } break; - case 11: + case CGM6_MELEE_IMPACT: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); @@ -1805,31 +1807,31 @@ void CG_ParseCGMessage_ver_6() vEnd[2] = cgi.MSG_ReadCoord(); CG_MeleeImpact(vStart, vEnd); break; - case 12: - case 13: + case CGM6_EXPLOSION_EFFECT_1: + case CGM6_EXPLOSION_EFFECT_2: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); CG_MakeExplosionEffect(vStart, iType); break; - case 15: - case 16: - case 17: - case 18: - case 19: - case 20: - case 21: - case 22: + case CGM6_MAKE_EFFECT_1: + case CGM6_MAKE_EFFECT_2: + case CGM6_MAKE_EFFECT_3: + case CGM6_MAKE_EFFECT_4: + case CGM6_MAKE_EFFECT_5: + case CGM6_MAKE_EFFECT_6: + case CGM6_MAKE_EFFECT_7: + case CGM6_MAKE_EFFECT_8: vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); vStart[2] = cgi.MSG_ReadCoord(); cgi.MSG_ReadDir(vEnd); - sfxManager.MakeEffect_Normal(iType + SFX_EXP_GREN_PUDDLE, vStart, vEnd); + sfxManager.MakeEffect_Normal(SFX_EXP_GREN_PUDDLE + iType, vStart, vEnd); break; - case 23: - case 24: + case CGM6_MAKE_CRATE_DEBRIS: + case CGM6_MAKE_WINDOW_DEBRIS: { str sEffect; char cTmp[8]; @@ -1842,7 +1844,7 @@ void CG_ParseCGMessage_ver_6() // get the integer as string snprintf(cTmp, sizeof(cTmp), "%d", iLarge); - if (iType == 23) { + if (iType == CGM6_MAKE_CRATE_DEBRIS) { sEffect = "models/fx/crates/debris_"; } else { sEffect = "models/fx/windows/debris_"; @@ -1859,7 +1861,7 @@ void CG_ParseCGMessage_ver_6() } break; - case 25: + case CGM6_BULLET_NO_BARREL_1: vTmp[0] = cgi.MSG_ReadCoord(); vTmp[1] = cgi.MSG_ReadCoord(); vTmp[2] = cgi.MSG_ReadCoord(); @@ -1874,7 +1876,7 @@ void CG_ParseCGMessage_ver_6() CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qtrue, qtrue); break; - case 26: + case CGM6_BULLET_NO_BARREL_2: memset(vTmp, 0, sizeof(vTmp)); vStart[0] = cgi.MSG_ReadCoord(); vStart[1] = cgi.MSG_ReadCoord(); @@ -1887,7 +1889,7 @@ void CG_ParseCGMessage_ver_6() CG_MakeBulletTracer(vTmp, vStart, vEndArray, 1, iLarge, qfalse, qtrue); break; - case 27: + case CGM6_HUDDRAW_SHADER: iInfo = cgi.MSG_ReadByte(); strcpy(cgi.HudDrawElements[iInfo].shaderName, cgi.MSG_ReadString()); cgi.HudDrawElements[iInfo].string[0] = 0; @@ -1897,13 +1899,13 @@ void CG_ParseCGMessage_ver_6() CG_HudDrawShader(iInfo); break; - case 28: + case CGM6_HUDDRAW_ALIGN: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].iHorizontalAlign = cgi.MSG_ReadBits(2); cgi.HudDrawElements[iInfo].iVerticalAlign = cgi.MSG_ReadBits(2); break; - case 29: + case CGM6_HUDDRAW_RECT: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].iX = cgi.MSG_ReadShort(); cgi.HudDrawElements[iInfo].iY = cgi.MSG_ReadShort(); @@ -1911,30 +1913,30 @@ void CG_ParseCGMessage_ver_6() cgi.HudDrawElements[iInfo].iHeight = cgi.MSG_ReadShort(); break; - case 30: + case CGM6_HUDDRAW_VIRTUALSIZE: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].bVirtualScreen = cgi.MSG_ReadBits(1); break; - case 31: + case CGM6_HUDDRAW_COLOR: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].vColor[0] = cgi.MSG_ReadByte() / 255.0; cgi.HudDrawElements[iInfo].vColor[1] = cgi.MSG_ReadByte() / 255.0; cgi.HudDrawElements[iInfo].vColor[2] = cgi.MSG_ReadByte() / 255.0; break; - case 32: + case CGM6_HUDDRAW_ALPHA: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].vColor[3] = cgi.MSG_ReadByte() / 255.0; break; - case 33: + case CGM6_HUDDRAW_STRING: iInfo = cgi.MSG_ReadByte(); cgi.HudDrawElements[iInfo].hShader = 0; strcpy(cgi.HudDrawElements[iInfo].string, cgi.MSG_ReadString()); break; - case 34: + case CGM6_HUDDRAW_FONT: iInfo = cgi.MSG_ReadByte(); strcpy(cgi.HudDrawElements[iInfo].fontName, cgi.MSG_ReadString()); cgi.HudDrawElements[iInfo].hShader = 0; @@ -1943,14 +1945,14 @@ void CG_ParseCGMessage_ver_6() CG_HudDrawFont(iInfo); break; - case 35: - case 36: + case CGM6_NOTIFY_KILL: + case CGM6_NOTIFY_HIT: { int iOldEnt; iOldEnt = current_entity_number; current_entity_number = cg.snap->ps.clientNum; - if (iType == 36) { + if (iType == CGM6_NOTIFY_HIT) { commandManager.PlaySound("dm_kill_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1); } else { commandManager.PlaySound("dm_hit_notify", NULL, CHAN_LOCAL, 2.0, -1, -1, 1); @@ -1960,7 +1962,7 @@ void CG_ParseCGMessage_ver_6() } break; - case 37: + case CGM6_VOICE_CHAT: { int iOldEnt; From 7ddee0100e11ff1c869731711fa3b303060697fe Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 14 Jun 2024 22:24:55 +0200 Subject: [PATCH 0473/2040] Implements CG_BodyFallSound() --- code/cgame/cg_specialfx.cpp | 146 +++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 4 deletions(-) diff --git a/code/cgame/cg_specialfx.cpp b/code/cgame/cg_specialfx.cpp index d1b1c970..76e9843c 100644 --- a/code/cgame/cg_specialfx.cpp +++ b/code/cgame/cg_specialfx.cpp @@ -1,6 +1,6 @@ /* =========================================================================== -Copyright (C) 2023 the OpenMoHAA team +Copyright (C) 2024 the OpenMoHAA team This file is part of OpenMoHAA source code. @@ -38,7 +38,8 @@ static vec3_t g_vLadderstepMaxs; ClientSpecialEffectsManager sfxManager; -Event EV_SFX_EffectDelay( +Event EV_SFX_EffectDelay +( "effectdelay", EV_DEFAULT, "iivvvvv", @@ -519,7 +520,7 @@ void ClientSpecialEffectsManager::ExecuteEffect( AxisCopy(axis, pCommand->emitter->tag_axis); pCommand->emitter->cgd.createTime = cg.time; commandManager.SetSpawnthing(pCommand->emitter); - + (commandManager.*pCommand->endfcn)(); } } @@ -937,7 +938,144 @@ void CG_LandingSound(centity_t *ent, refEntity_t *pREnt, float volume, int iEqui void CG_BodyFallSound(centity_t *ent, refEntity_t *pREnt, float volume) { - // FIXME: unimplemented + int contents; + int surftype; + int iEffectNum = -1; + vec3_t vStart, vEnd; + vec3_t midlegs; + str sSoundName; + trace_t trace; + + VectorCopy(ent->lerpOrigin, vStart); + vStart[2] += 8; + + VectorCopy(vStart, vEnd); + vEnd[2] -= 64; + + if (ent->currentState.eType == ET_PLAYER) { + CG_Trace( + &trace, + vStart, + g_vFootstepMins, + g_vFootstepMaxs, + vEnd, + ent->currentState.number, + MASK_PLAYERSOLID, + qtrue, + qtrue, + "Player Landing" + ); + } else { + CG_Trace( + &trace, + vStart, + g_vFootstepMins, + g_vFootstepMaxs, + vEnd, + ent->currentState.number, + MASK_MONSTERSOLID, + qfalse, + qfalse, + "Monster Landing" + ); + } + + if (trace.fraction == 1) { + return; + } + + sSoundName = "snd_bodyfall_"; + contents = CG_PointContents(trace.endpos, -1); + if (contents & MASK_WATER) { + // take our ground position and trace upwards + VectorCopy(trace.endpos, midlegs); + midlegs[2] += WATER_NO_SPLASH_HEIGHT; + contents = CG_PointContents(midlegs, -1); + if (contents & MASK_WATER) { + sSoundName += "wade"; + } else { + sSoundName += "puddle"; + iEffectNum = SFX_FOOT_PUDDLE; + } + } else { + surftype = trace.surfaceFlags & MASK_SURF_TYPE; + switch (surftype) { + case SURF_FOLIAGE: + sSoundName += "foliage"; + iEffectNum = SFX_FOOT_GRASS; + break; + case SURF_SNOW: + sSoundName += "snow"; + iEffectNum = SFX_FOOT_SNOW; + break; + case SURF_CARPET: + sSoundName += "carpet"; + iEffectNum = SFX_FOOT_LIGHT_DUST; + break; + case SURF_SAND: + sSoundName += "sand"; + iEffectNum = SFX_FOOT_SAND; + break; + case SURF_PUDDLE: + sSoundName += "puddle"; + iEffectNum = SFX_FOOT_PUDDLE; + break; + case SURF_GLASS: + sSoundName += "glass"; + iEffectNum = SFX_FOOT_LIGHT_DUST; + break; + case SURF_GRAVEL: + sSoundName += "gravel"; + iEffectNum = SFX_FOOT_HEAVY_DUST; + break; + case SURF_MUD: + sSoundName += "mud"; + iEffectNum = SFX_FOOT_MUD; + break; + case SURF_DIRT: + sSoundName += "dirt"; + iEffectNum = SFX_FOOT_DIRT; + break; + case SURF_GRILL: + sSoundName += "grill"; + iEffectNum = SFX_FOOT_LIGHT_DUST; + break; + case SURF_GRASS: + sSoundName += "grass"; + iEffectNum = SFX_FOOT_GRASS; + break; + case SURF_ROCK: + sSoundName += "stone"; + iEffectNum = SFX_FOOT_HEAVY_DUST; + break; + case SURF_PAPER: + sSoundName += "paper"; + iEffectNum = SFX_FOOT_LIGHT_DUST; + break; + case SURF_WOOD: + sSoundName += "wood"; + iEffectNum = SFX_FOOT_LIGHT_DUST; + break; + case SURF_METAL: + sSoundName += "metal"; + iEffectNum = SFX_FOOT_LIGHT_DUST; + break; + default: + sSoundName += "stone"; + iEffectNum = SFX_FOOT_HEAVY_DUST; + break; + } + } + + if (cg_debugFootsteps->integer) { + cgi.DPrintf("BodyFall: %s volume: %.2f effect = %i\n", sSoundName.c_str(), volume, iEffectNum); + } + + commandManager.PlaySound(sSoundName, trace.endpos, -1, volume, -1, -1, 1); + + if (iEffectNum != -1) { + sfxManager.MakeEffect_Angles(iEffectNum, trace.endpos, Vector(270, 0, 0)); + } } /* From 40e39776646eded73ccdc46a69a181e8072334ea Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 00:15:51 +0200 Subject: [PATCH 0474/2040] Continue using entities even when attached to a turret, in 1.11 and below for backwards compatibility! Fixes #140 where the MG42 objective in m1l1 would not trigger --- code/fgame/player.cpp | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 59e79c2f..b5e17d3f 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -3438,20 +3438,44 @@ void Player::DoUse(Event *ev) num = getUseableEntities(touch, MAX_GENTITIES, true); - for (i = 0; i < num; i++) { - hit = &g_entities[touch[i]]; + if (g_protocol >= protocol_e::PROTOCOL_MOHTA_MIN) { + // Fixed in 2.0 + // Since 2.0, the loop stops when the player + // uses a turret, this prevents the turret from being deleted + // after being attached to the player + // + for (i = 0; i < num; i++) { + hit = &g_entities[touch[i]]; - if (!hit->inuse) { - continue; + if (!hit->inuse) { + continue; + } + + Event* event = new Event(EV_Use); + event->AddListener(this); + + hit->entity->ProcessEvent(event); + + if (m_pVehicle || m_pTurret) { + break; + } } + } else { + // + // Backward compatibility + // It still allows 1.11 SP to work properly + // Such as in m1l1 when the player must man the mounted machine gun + for (i = 0; i < num; i++) { + hit = &g_entities[touch[i]]; - Event *event = new Event(EV_Use); - event->AddListener(this); + if (!hit->inuse) { + continue; + } - hit->entity->ProcessEvent(event); + Event* event = new Event(EV_Use); + event->AddListener(this); - if (m_pVehicle || m_pTurret) { - break; + hit->entity->ProcessEvent(event); } } From 2df8ed10d06d018b82566f847874ab60e09fa75b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 14:56:30 +0200 Subject: [PATCH 0475/2040] Improves timeout checking, properly show the timeout menu and shutdown the server --- code/client/cl_main.cpp | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 0e0dbd46..41e3d57f 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -2426,10 +2426,37 @@ void CL_CheckTimeout( void ) { && clc.state >= CA_CONNECTED && clc.state != CA_CINEMATIC && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) { if (++cl.timeoutcount > 5) { // timeoutcount saves debugger - Com_Printf ("\nServer connection timed out.\n"); - Cbuf_AddText( "pushmenu servertimeout\n" ); - CL_Disconnect(); - return; + const char* info; + const char* maxclients; + + info = &cl.gameState.stringData[cl.gameState.stringOffsets[CS_SERVERINFO]]; + maxclients = Info_ValueForKey(info, "maxclients"); + // + // Disconnect if the player isn't alone (single-player mode) + // + if (!maxclients || atoi(maxclients) != 1) { + qboolean bConsoleState; + + bConsoleState = UI_ConsoleIsOpen(); + + Com_Printf("\nServer connection timed out.\n"); + SV_Shutdown("\nServer connection timed out\n"); + + if (com_cl_running && com_cl_running->integer) { + CL_AbnormalDisconnect(); + CL_FlushMemory(); + CL_StartHunkUsers(qfalse); + } + + UI_ForceMenuOff(qtrue); + UI_PushMenu("servertimeout"); + + if (bConsoleState) { + UI_OpenConsole(); + } else { + UI_CloseConsole(); + } + } } } else { cl.timeoutcount = 0; From 141574a0d71ae976afbf52d49d067e0736f19776 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 16:22:21 +0200 Subject: [PATCH 0476/2040] Ignore mouse events when paused --- code/client/cl_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index 7f763b44..fc52a69f 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -432,7 +432,7 @@ void CL_MouseEvent( int dx, int dy, int time ) { if( cl.mousey > cls.glconfig.vidHeight ) cl.mousey = cls.glconfig.vidHeight; } - else + else if ( !paused->integer ) { cl.mouseDx[cl.mouseIndex] += dx; cl.mouseDy[cl.mouseIndex] += dy; @@ -999,7 +999,7 @@ void CL_SendCmd( void ) { } // don't send commands if paused - if ( com_sv_running->integer && paused->integer && paused->integer ) { + if ( com_sv_running->integer && paused->integer ) { return; } From cc716c3fa4577249d1d5b7b258dd02155ca92a45 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 16:22:34 +0200 Subject: [PATCH 0477/2040] Don't process loopsound yet when spawning --- code/fgame/entity.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 07f264a1..19159bfa 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -3221,6 +3221,15 @@ void Entity::LoopSound(Event *ev) return; } + if (level.spawning) { + // If the server is currently spawning + // repost the event as loopsound wouldn't work properly + // on the client + Event* newev = new Event(*ev); + PostEvent(newev, level.frametime); + return; + } + // Get parameters sound_name = ev->GetString(1); From d7a5eb5d2f720c670191927f951aa8b7aefba836 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 16:26:35 +0200 Subject: [PATCH 0478/2040] Use LEVEL_WIDE_MIN_DIST instead of 10000 constant --- code/server/sv_snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index f7503500..fed722de 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -643,7 +643,7 @@ static void SV_AddEntitiesVisibleFromPoint(const vec3_t origin, clientSnapshot_t continue; } - if ((ent->s.loopSound && ent->s.loopSoundMinDist == 10000) || ent->s.renderfx & RF_VIEWMODEL) { + if ((ent->s.loopSound && ent->s.loopSoundMinDist == LEVEL_WIDE_MIN_DIST) || ent->s.renderfx & RF_VIEWMODEL) { // loopsound entities should be sent regardless SV_AddEntToSnapshot(svEnt, ent, eNums, portalEnt, portalsky); continue; From bbb54ea36dec5eb9f85354e14bddc948bf2b2c8a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 16:33:02 +0200 Subject: [PATCH 0479/2040] Uses LoopSounds() parameters instead of just the alias --- code/fgame/entity.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 19159bfa..95fbb02e 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -3280,10 +3280,10 @@ void Entity::LoopSound(str sound_name, float volume, float min_dist, float max_d // Add the looping sound to the entity edict->s.loopSound = gi.soundindex(name, aliasstreamed); - edict->s.loopSoundVolume = aliasvolume; - edict->s.loopSoundMinDist = aliasmin_dist; - edict->s.loopSoundMaxDist = aliasmax_dist; - edict->s.loopSoundPitch = aliaspitch; + edict->s.loopSoundVolume = volume < 0 ? (aliasvolume) : (aliasvolume * volume); + edict->s.loopSoundMinDist = min_dist < 0 ? (aliasmin_dist) : (min_dist); + edict->s.loopSoundMaxDist = max_dist < 0 ? (aliasmax_dist) : (max_dist); + edict->s.loopSoundPitch = pitch < 0 ? (aliaspitch) : (aliaspitch * pitch); // Local sound will always be heard edict->s.loopSoundFlags = aliaschannel == CHAN_LOCAL; From f5aadbb788cf2e40f7294d6e8c4975df462a9370 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 15 Jun 2024 16:38:02 +0200 Subject: [PATCH 0480/2040] If the loopSound has no origin, make it local This should fix #309 --- code/client/new/snd_main_new.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index c6ba1b66..7fd517d6 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "../snd_local.h" +#include "../client.h" #if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW @@ -57,6 +58,13 @@ void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t s } // FIXME: unimplemented + + if (VectorCompare(origin, vec3_origin)) { + // Consider it to be a local sound, uses the player origin + S_AddLoopingSound(cl.snap.ps.clientNum, cl.snap.ps.origin, velocity, sfxHandle); + return; + } + S_AddLoopingSound(ENTITYNUM_WORLD, origin, velocity, sfxHandle); } From 46b3f4eb5e6fa16dbf51d7145a8d066eb051e074 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:14:26 +0200 Subject: [PATCH 0481/2040] Adds `differentMap` parameter for G_ClientConnect, it clears the selected DM weapon. On each map change, the player gets asked for the primary weapon like in 2.0 and above --- code/fgame/g_client.cpp | 12 ++++++++---- code/fgame/g_local.h | 2 +- code/fgame/g_public.h | 2 +- code/server/sv_client.c | 2 +- code/server/sv_init.c | 4 ++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/code/fgame/g_client.cpp b/code/fgame/g_client.cpp index a1020954..b7ffc894 100644 --- a/code/fgame/g_client.cpp +++ b/code/fgame/g_client.cpp @@ -855,7 +855,7 @@ to the server machine, but qfalse on map changes and tournement restarts. ============ */ -const char *G_ClientConnect(int clientNum, qboolean firstTime) +const char *G_ClientConnect(int clientNum, qboolean firstTime, qboolean differentMap) { char *ip, *port, *value; gclient_t *client; @@ -863,7 +863,7 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime) char userinfo[MAX_INFO_STRING]; gi.DPrintf("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\n"); - if (!g_gametype->integer) { + if (g_gametype->integer == GT_SINGLE_PLAYER) { return NULL; } @@ -879,6 +879,7 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime) port = Info_ValueForKey(userinfo, "port"); // FIXME: what is fucking wrong with G_FilterPacket... + // NOTE: IP banning is directly handled by the server //if ( G_FilterPacket( value ) ) { // return "Banned IP"; //} @@ -903,6 +904,9 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime) G_InitSessionData(client, userinfo); } else { G_ReadSessionData(client); + if (differentMap) { + client->pers.dm_primary[0] = 0; + } } Q_strncpyz(client->pers.ip, ip, sizeof(client->pers.ip)); @@ -922,7 +926,7 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime) #endif // don't do the "xxx connected" messages if they were caried over from previous level - if (firstTime && g_gametype->integer) { + if (firstTime && g_gametype->integer != GT_SINGLE_PLAYER) { if (dedicated->integer) { gi.Printf("%s is preparing for deployment\n", client->pers.netname); } @@ -971,7 +975,7 @@ void G_ClientBegin(gentity_t *ent, usercmd_t *cmd) } else { ent->client->pers.enterTime = level.svsFloatTime; - if (g_gametype->integer) { + if (g_gametype->integer != GT_SINGLE_PLAYER) { // send effect if in a multiplayer game if (dedicated->integer) { gi.Printf("%s has entered the battle\n", ent->client->pers.netname); diff --git a/code/fgame/g_local.h b/code/fgame/g_local.h index 73c8ad5a..1d2b21a2 100644 --- a/code/fgame/g_local.h +++ b/code/fgame/g_local.h @@ -423,7 +423,7 @@ void QDECL G_Error(errorParm_t type, const char *fmt, ...) __attribute__((noretu // g_client.c // void G_BotConnect(int clientNum, const char* userinfo); -const char *G_ClientConnect(int clientNum, qboolean firstTime); +const char *G_ClientConnect(int clientNum, qboolean firstTime, qboolean differentMap); void G_ClientUserinfoChanged(gentity_t *ent, const char *userinfo); void G_ClientDisconnect(gentity_t *ent); void G_ClientBegin(gentity_t *ent, usercmd_t *cmd); diff --git a/code/fgame/g_public.h b/code/fgame/g_public.h index 31a7b373..bf8dc73b 100644 --- a/code/fgame/g_public.h +++ b/code/fgame/g_public.h @@ -490,7 +490,7 @@ typedef struct gameExport_s { // return NULL if the client is allowed to connect, otherwise return // a text string with the reason for denial - const char *(*ClientConnect)(int clientNum, qboolean firstTime); + const char *(*ClientConnect)(int clientNum, qboolean firstTime, qboolean differentMap); void (*ClientBegin)(gentity_t *ent, usercmd_t *cmd); void (*ClientUserinfoChanged)(gentity_t *ent, const char *userinfo); diff --git a/code/server/sv_client.c b/code/server/sv_client.c index beacfbaa..a62031d3 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -496,7 +496,7 @@ gotnewcl: Q_strncpyz( newcl->userinfo, userinfo, sizeof( newcl->userinfo ) ); // get the game a chance to reject this connection or modify the userinfo - denied = ge->ClientConnect( clientNum, qtrue ); + denied = ge->ClientConnect( clientNum, qtrue, qfalse ); if ( denied ) { NET_OutOfBandPrint( NS_SERVER, from, "droperror\n%s\n", denied ); diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 3145e386..7af49781 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -805,7 +805,7 @@ void SV_SpawnServer( const char *server, qboolean loadgame, qboolean restart, qb || Cvar_VariableIntegerValue( "g_gametype" ) == 0 ) { // connect the client again - denied = ge->ClientConnect( i, qfalse ); + denied = ge->ClientConnect( i, qfalse, qtrue ); p = ge->errorMessage; if( p ) @@ -887,7 +887,7 @@ void SV_SpawnServer( const char *server, qboolean loadgame, qboolean restart, qb const char *denied; // connect the client again - denied = ge->ClientConnect( i, qfalse ); + denied = ge->ClientConnect( i, qfalse, qfalse ); p = ge->errorMessage; if( p ) From 15f2f6c79898a06a0111bf03e37d649c396bf709 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:16:14 +0200 Subject: [PATCH 0482/2040] Renamed g_session functions --- code/fgame/g_client.cpp | 6 +++--- code/fgame/g_local.h | 4 ++-- code/fgame/g_session.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/fgame/g_client.cpp b/code/fgame/g_client.cpp index b7ffc894..aa87f11b 100644 --- a/code/fgame/g_client.cpp +++ b/code/fgame/g_client.cpp @@ -827,7 +827,7 @@ void G_BotConnect(int clientNum, const char *userinfo) // read the session data memset(client, 0, sizeof(*client)); - G_InitSessionData(client, userinfo); + G_InitClientPersistant(client, userinfo); Q_strncpyz(client->pers.ip, "localhost", sizeof(client->pers.ip)); client->pers.port = 0; @@ -901,9 +901,9 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime, qboolean differen // read or initialize the session data if (firstTime) { memset(client, 0, sizeof(*client)); - G_InitSessionData(client, userinfo); + G_InitClientPersistant(client, userinfo); } else { - G_ReadSessionData(client); + G_ReadClientSessionData(client); if (differentMap) { client->pers.dm_primary[0] = 0; } diff --git a/code/fgame/g_local.h b/code/fgame/g_local.h index 1d2b21a2..90b2c965 100644 --- a/code/fgame/g_local.h +++ b/code/fgame/g_local.h @@ -455,8 +455,8 @@ void Svcmd_GameMem_f(void); // // g_session.c // -void G_ReadSessionData(gclient_t *client); -void G_InitSessionData(gclient_t *client, const char *userinfo); +void G_ReadClientSessionData(gclient_t *client); +void G_InitClientPersistant(gclient_t *client, const char *userinfo); void G_InitWorldSession(void); void G_WriteSessionData(void); diff --git a/code/fgame/g_session.cpp b/code/fgame/g_session.cpp index 7056c800..465e2405 100644 --- a/code/fgame/g_session.cpp +++ b/code/fgame/g_session.cpp @@ -58,7 +58,7 @@ G_ReadSessionData Called on a reconnect ================ */ -void G_ReadSessionData( gclient_t *client ) +void G_ReadClientSessionData( gclient_t *client ) { cvar_t *session; @@ -83,7 +83,7 @@ G_InitSessionData Called on a first-time connect ================ */ -void G_InitSessionData( gclient_t *client, const char *userinfo ) +void G_InitClientPersistant( gclient_t *client, const char *userinfo ) { G_WriteClientSessionData( client ); } From 5482b31c6634f3f40ffa95ae59c7b34d629e5d0a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:18:14 +0200 Subject: [PATCH 0483/2040] Reads the `sv_privatePassword` value --- code/fgame/g_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/g_client.cpp b/code/fgame/g_client.cpp index aa87f11b..09d7d2f7 100644 --- a/code/fgame/g_client.cpp +++ b/code/fgame/g_client.cpp @@ -890,7 +890,7 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime, qboolean differen if ((strcmp(ip, "localhost") != 0)) { // check for a password value = Info_ValueForKey(userinfo, "password"); - if (password->string[0] && Q_stricmp(password->string, "none") && strcmp(password->string, value) != 0) { + if (strcmp(sv_privatePassword->string, value) != 0 && *password->string && strcmp(password->string, value) != 0) { return "Invalid password"; } } From d1ecd4a3c8c01542a899b92536bf7f2805273259 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:19:11 +0200 Subject: [PATCH 0484/2040] Don't initialize client persistant data during autosave --- code/fgame/g_client.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/fgame/g_client.cpp b/code/fgame/g_client.cpp index 09d7d2f7..4df3f97e 100644 --- a/code/fgame/g_client.cpp +++ b/code/fgame/g_client.cpp @@ -901,7 +901,9 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime, qboolean differen // read or initialize the session data if (firstTime) { memset(client, 0, sizeof(*client)); - G_InitClientPersistant(client, userinfo); + if (!game.autosaved) { + G_InitClientPersistant(client, userinfo); + } } else { G_ReadClientSessionData(client); if (differentMap) { From a5691d777953e8c088732c639c46beac7d8c8ab4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:46:14 +0200 Subject: [PATCH 0485/2040] Allows clients to join a single-player game --- code/fgame/g_client.cpp | 8 +++++--- code/server/sv_client.c | 15 ++++++++++++--- code/server/sv_init.c | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/code/fgame/g_client.cpp b/code/fgame/g_client.cpp index 4df3f97e..50b0e8f5 100644 --- a/code/fgame/g_client.cpp +++ b/code/fgame/g_client.cpp @@ -863,9 +863,11 @@ const char *G_ClientConnect(int clientNum, qboolean firstTime, qboolean differen char userinfo[MAX_INFO_STRING]; gi.DPrintf("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\n"); - if (g_gametype->integer == GT_SINGLE_PLAYER) { - return NULL; - } + // Removed in OPM + // Accepts remote clients + //if (g_gametype->integer == GT_SINGLE_PLAYER) { + // return NULL; + //} ent = &g_entities[clientNum]; diff --git a/code/server/sv_client.c b/code/server/sv_client.c index a62031d3..a2868930 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -52,9 +52,11 @@ void SV_GetChallenge( netadr_t from ) { challenge_t *challenge; // ignore if we are in single player - if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) { - return; - } + // Removed in OPM + // Allow servers to accept players in a single-player game + //if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) { + // return; + //} challenge = FindChallenge(from, qtrue); @@ -759,6 +761,13 @@ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { // call the game begin function ge->ClientBegin( ( gentity_t * )ent, cmd ); + + // + // Added in OPM + // In a dedicated server, start the game when the first client enters the game + if (com_dedicated->integer) { + SV_ServerLoaded(); + } } /* diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 7af49781..0f474265 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -915,7 +915,7 @@ void SV_SpawnServer( const char *server, qboolean loadgame, qboolean restart, qb UI_LoadResource( "*143" ); - if( g_gametype->integer ) { + if( g_gametype->integer != GT_SINGLE_PLAYER ) { SV_ServerLoaded(); } } From 40492daecd867f282f4abb72354cc75126b61721 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 16 Jun 2024 23:20:30 +0200 Subject: [PATCH 0486/2040] Avoid creating a new sound index when there is no active client --- code/server/sv_snd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/server/sv_snd.c b/code/server/sv_snd.c index 8dab16dc..e51060f2 100644 --- a/code/server/sv_snd.c +++ b/code/server/sv_snd.c @@ -70,9 +70,17 @@ void SV_Sound( vec3_t *org, int entnum, int channel, const char *sound_name, flo { int i; - for (i = 0; i < sv_maxclients->integer; i++) + for (i = 0; i < svs.iNumClients; i++) { client_t* client = &svs.clients[i]; + if (client->state != CS_ACTIVE) { + continue; + } + + if (client->number_of_server_sounds >= MAX_SERVER_SOUNDS) { + continue; + } + SV_ClientSound(client, org, entnum, channel, SV_SoundIndex(sound_name, streamed), volume, mindist, pitch, maxdist, streamed); } } From a7df73073d4bf9bf0902710e9151b9954588e739 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 21 Jun 2024 20:54:09 +0200 Subject: [PATCH 0487/2040] Adds a condition to check if static model poly can be rendered --- code/renderer/tr_staticmodels.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/renderer/tr_staticmodels.cpp b/code/renderer/tr_staticmodels.cpp index 03ac0b85..6b8ca1e4 100644 --- a/code/renderer/tr_staticmodels.cpp +++ b/code/renderer/tr_staticmodels.cpp @@ -489,6 +489,10 @@ void RB_StaticMesh(staticSurface_t* staticSurf) { int baseIndex, baseVertex; short collapse[1000]; + if (!r_drawstaticmodelpoly->integer) { + return; + } + assert(backEnd.currentStaticModel); tiki = backEnd.currentStaticModel->tiki; surf = staticSurf->surface; From 64626a767c3b51c0b57b475ed9f62bc199f5b086 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 21 Jun 2024 21:48:55 +0200 Subject: [PATCH 0488/2040] Fixes entities not being rendered after number 1023 This fixes #310 where some static models would not be rendered, making it look like there are invisible walls. --- code/renderer/tr_local.h | 4 ++-- code/renderer/tr_main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index c2bfa15e..02d29a24 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1189,11 +1189,11 @@ the bits are allocated as follows: 2-6 : fog index 0-1 : dlightmap index */ -#define QSORT_SHADERNUM_SHIFT 21 // was 22, decreased in 2.0 +#define QSORT_SHADERNUM_SHIFT 21 // was 22, decreased in 2.30 #define QSORT_ENTITYNUM_SHIFT 8 #define QSORT_FOGNUM_SHIFT 2 #define QSORT_REFENTITYNUM_SHIFT 7 -#define QSORT_STATICMODEL_SHIFT 20 // was 21, decreased in 2.0 +#define QSORT_STATICMODEL_SHIFT 20 // was 21, decreased in 2.30 extern int gl_filter_min, gl_filter_max; diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 96a7445f..899581fd 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -1384,7 +1384,7 @@ R_DecomposeSort */ void R_DecomposeSort(unsigned int sort, int* entityNum, shader_t** shader, int* dlightMap, qboolean* bStaticModel) { *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; - *entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & 1023; + *entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & 4095; *dlightMap = sort & 15; *bStaticModel = sort & (1 << QSORT_STATICMODEL_SHIFT); } From 907ff36018d21075ed61913b55f7ae91193618cc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 21 Jun 2024 21:49:13 +0200 Subject: [PATCH 0489/2040] Fixes `r_showstaticbboxes` freezing the game --- code/renderer/tr_staticmodels.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/renderer/tr_staticmodels.cpp b/code/renderer/tr_staticmodels.cpp index 6b8ca1e4..97cc91c6 100644 --- a/code/renderer/tr_staticmodels.cpp +++ b/code/renderer/tr_staticmodels.cpp @@ -294,7 +294,7 @@ R_AddStaticModelSurfaces */ void R_AddStaticModelSurfaces(void) { cStaticModelUnpacked_t* SM; - int i, j; + int i, j, k; int ofsStaticData; int iRadiusCull; dtiki_t* tiki; @@ -418,10 +418,10 @@ void R_AddStaticModelSurfaces(void) { if (r_showstaticbboxes->integer) { vec3_t vMins, vMaxs; - for (i = 0; i < 3; i++) + for (k = 0; k < 3; k++) { - vMins[i] = tiki->a->mins[i] * tiki->load_scale * SM->scale; - vMaxs[i] = tiki->a->maxs[i] * tiki->load_scale * SM->scale; + vMins[k] = tiki->a->mins[k] * tiki->load_scale * SM->scale; + vMaxs[k] = tiki->a->maxs[k] * tiki->load_scale * SM->scale; } R_DebugRotatedBBox(SM->origin, SM->angles, vMins, vMaxs, 1.0, 0.0, 1.0, 0.75); From d9dc34f06d97be36da409a0ddadd1dd6f8f3aa5d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 21 Jun 2024 22:02:11 +0200 Subject: [PATCH 0490/2040] Checks for `AGEN_TIKI_DIST_FADE` and `AGEN_ONE_MINUS_TIKI_DIST_FADE` for static models --- code/renderer/tr_staticmodels.cpp | 36 ++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/code/renderer/tr_staticmodels.cpp b/code/renderer/tr_staticmodels.cpp index 97cc91c6..b1f2d57f 100644 --- a/code/renderer/tr_staticmodels.cpp +++ b/code/renderer/tr_staticmodels.cpp @@ -358,6 +358,8 @@ void R_AddStaticModelSurfaces(void) { skelSurfaceGame_t* surface; staticSurface_t* s_surface; shader_t* shader; + float fDist; + vec3_t vDelta; if (!skelmodel) { continue; @@ -383,20 +385,34 @@ void R_AddStaticModelSurfaces(void) { shader = tr.shaders[dsurf->hShader[0]]; - if (shader->numUnfoggedPasses == 1) + if (shader->numUnfoggedPasses == 1 && !r_nocull->integer) { - if (shader->unfoggedStages[0]->alphaGen == AGEN_DIST_FADE) - { + switch (shader->unfoggedStages[0]->alphaGen) { + case AGEN_DIST_FADE: if (R_DistanceCullPointAndRadius(shader->fDistNear + shader->fDistRange, tiki_worldorigin, SM->cull_radius) == CULL_OUT) { continue; } - } - else if (shader->unfoggedStages[0]->alphaGen == AGEN_ONE_MINUS_DIST_FADE) - { - if (R_DistanceCullPointAndRadius(shader->fDistNear, tiki_worldorigin, SM->cull_radius) == CULL_IN) { - continue; - } - } + break; + case AGEN_ONE_MINUS_DIST_FADE: + if (R_DistanceCullPointAndRadius(shader->fDistNear, tiki_worldorigin, SM->cull_radius) == CULL_IN) { + continue; + } + break; + case AGEN_TIKI_DIST_FADE: + fDist = (shader->fDistNear + shader->fDistRange); + VectorSubtract(tiki_worldorigin, tr.viewParms.ori.origin, vDelta); + if (VectorLengthSquared(vDelta) >= Square(fDist)) { + continue; + } + break; + case AGEN_ONE_MINUS_TIKI_DIST_FADE: + fDist = (shader->fDistNear + shader->fDistRange); + VectorSubtract(tiki_worldorigin, tr.viewParms.ori.origin, vDelta); + if (VectorLengthSquared(vDelta) <= Square(shader->fDistNear)) { + continue; + } + break; + } } SM->bRendered = qtrue; From 835c0b0d9a282c0b660337097ca82354278a8bac Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:28:58 +0200 Subject: [PATCH 0491/2040] Adds constants for LOD curve values --- code/tiki/tiki_shared.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/tiki/tiki_shared.h b/code/tiki/tiki_shared.h index 1834c5b5..39f8df0b 100644 --- a/code/tiki/tiki_shared.h +++ b/code/tiki/tiki_shared.h @@ -98,6 +98,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_TIKI_ALIASES 4095 #define MAX_GLOBAL_FROM_LOCAL 200 +#define MAX_LOD_CURVE_POINTS 5 +#define MAX_LOD_CURVE_CONSTS 4 + typedef struct AliasList_s AliasList_t; typedef struct AliasListNode_s AliasListNode_t; @@ -415,8 +418,8 @@ typedef struct { typedef struct lodControl_s { float minMetric; float maxMetric; - lodCurvePoint_t curve[5]; - lodCurvePointConstants_t consts[4]; + lodCurvePoint_t curve[MAX_LOD_CURVE_POINTS]; + lodCurvePointConstants_t consts[MAX_LOD_CURVE_CONSTS]; } lodControl_t; typedef struct { From f41e92de6e0548ac9bfb6f3b1694254cc8008412 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:34:00 +0200 Subject: [PATCH 0492/2040] Fixes possible memory corruption when generating a LOD curve --- code/tiki/tiki_skel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/tiki/tiki_skel.cpp b/code/tiki/tiki_skel.cpp index 17e649b4..24028e27 100644 --- a/code/tiki/tiki_skel.cpp +++ b/code/tiki/tiki_skel.cpp @@ -762,7 +762,7 @@ void GetLODFile(skelcache_t *cache) LOD->curve[3].val = (float)cache->skel->lodIndex[1]; LOD->curve[4].pos = 1.0f; - for (i = 9; cache->skel->lodIndex[i] > cache->skel->lodIndex[3]; i--) { + for (i = TIKI_SKEL_LOD_INDEXES; cache->skel->lodIndex[i] > cache->skel->lodIndex[3]; i--) { if (i <= 2) { break; } @@ -770,8 +770,8 @@ void GetLODFile(skelcache_t *cache) LOD->curve[4].val = (float)cache->skel->lodIndex[i]; - for (i = 8; i >= 0; i--) { - if (LOD->curve[i - 1].pos > LOD->curve[i].pos) { + for (i = 1; i < MAX_LOD_CURVE_POINTS - 1; i++) { + if (LOD->curve[i].pos < LOD->curve[i - 1].pos) { LOD->curve[i].val = LOD->curve[i - 1].pos; } } From 2a485a6b693a2de10d9a7c64c6339a9f8a95a5dd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:34:38 +0200 Subject: [PATCH 0493/2040] Fixes the endianness when loading LOD from file --- code/tiki/tiki_skel.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/code/tiki/tiki_skel.cpp b/code/tiki/tiki_skel.cpp index 24028e27..0f183dbe 100644 --- a/code/tiki/tiki_skel.cpp +++ b/code/tiki/tiki_skel.cpp @@ -748,6 +748,20 @@ void GetLODFile(skelcache_t *cache) LOD = (lodControl_t *)TIKI_Alloc(sizeof(lodControl_t)); memcpy(LOD, buf, length); TIKI_FreeFile(buf); + + LOD->minMetric = LittleFloat(LOD->minMetric); + LOD->maxMetric = LittleFloat(LOD->maxMetric); + + for (i = 0; i < MAX_LOD_CURVE_POINTS; i++) { + LOD->curve[i].pos = LittleFloat(LOD->curve[i].pos); + LOD->curve[i].val = LittleFloat(LOD->curve[i].val); + } + + for (i = 0; i < MAX_LOD_CURVE_CONSTS; i++) { + LOD->consts[i].base = LittleFloat(LOD->consts[i].base); + LOD->consts[i].scale = LittleFloat(LOD->consts[i].scale); + LOD->consts[i].cutoff = LittleFloat(LOD->consts[i].cutoff); + } } else { LOD = (lodControl_t *)TIKI_Alloc(sizeof(lodControl_t)); LOD->minMetric = 1.0f; From 11349f9ad5586a197b0d48c631ffb6a0e45da9aa Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:08:33 +0200 Subject: [PATCH 0494/2040] Fixes the source pos access for `ENUM_if_statement` (out of bounds index) --- code/script/scriptcompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index 928de100..a7acb868 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -1217,7 +1217,7 @@ __emit: case ENUM_if_statement: EmitValue(val.node[1]); - EmitVarToBool(val.node[4].sourcePosValue); + EmitVarToBool(val.node[3].sourcePosValue); EmitIfJump(val.node[2], val.node[3].sourcePosValue); break; From bef1b456e156d57306e1609aa03cc9025532aa28 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:10:36 +0200 Subject: [PATCH 0495/2040] Initialize all Ammo members --- code/fgame/ammo.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/code/fgame/ammo.cpp b/code/fgame/ammo.cpp index a6dc4869..de9b8c53 100644 --- a/code/fgame/ammo.cpp +++ b/code/fgame/ammo.cpp @@ -138,7 +138,9 @@ CLASS_DECLARATION(Class, Ammo, NULL) { }; Ammo::Ammo() - + : amount(0) + , maxamount(0) + , name_index(0) { if (LoadingSavegame) { // all data will be setup by the archive function @@ -150,7 +152,6 @@ Ammo::Ammo() } void Ammo::setAmount(int a) - { amount = a; @@ -160,38 +161,32 @@ void Ammo::setAmount(int a) } int Ammo::getAmount(void) - { return amount; } void Ammo::setMaxAmount(int a) - { maxamount = a; } int Ammo::getMaxAmount(void) - { return maxamount; } void Ammo::setName(str n) - { name = n; name_index = gi.itemindex(name) + CS_WEAPONS; } str Ammo::getName(void) - { return name; } int Ammo::getIndex(void) - { return name_index; } From e207715b5e2186eac826d8d7b0a5be8f97fd1af8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:12:29 +0200 Subject: [PATCH 0496/2040] Initialize `m_iLastTiresUpdate` --- code/fgame/vehicle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index b521598c..158ee1dd 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -1174,6 +1174,7 @@ Vehicle::Vehicle() m_sAnimationSet = ""; m_sSoundSet = ""; + m_iLastTiresUpdate = -1; for (i = 0; i < NUM_VEHICLE_TIRES; i++) { m_vTireEnd[i] = origin; m_bTireHit[i] = false; From 0b747bf1c5fb386705f7297fb32283c1b9a32e2c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:39:00 +0200 Subject: [PATCH 0497/2040] Use `memmove` rather than `strcpy` for removing key values --- code/qcommon/q_shared.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 7dd4afa7..91622016 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -1854,7 +1854,9 @@ void Info_RemoveKey( char *s, const char *key ) { if (!strcmp (key, pkey) ) { - strcpy (start, s); // remove this part + //strcpy (start, s); // remove this part + // Fixed in OPM + memmove(start, s, strlen(s)); return; } From e4d20c3fa1185e072bb45600ab62585b381d32b9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:39:08 +0200 Subject: [PATCH 0498/2040] Initialize explosion flash --- code/fgame/weaputils.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index fb737103..640104e5 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -1530,6 +1530,11 @@ Explosion::Explosion() return; } + flash_r = 0; + flash_g = 0; + flash_b = 0; + flash_a = 0; + flash_radius = 0; radius = 0; constant_damage = false; damage_every_frame = false; From cb208b9ad2645bd26cbccec9e993b86266de20dc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:39:26 +0200 Subject: [PATCH 0499/2040] Initialize the message buffer to avoid leaking private data --- code/server/sv_snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index fed722de..fb4f82d2 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -1076,7 +1076,7 @@ Also called by SV_FinalMessage ======================= */ void SV_SendClientSnapshot( client_t *client ) { - byte msg_buf[MAX_MSGLEN]; + byte msg_buf[MAX_MSGLEN]{ 0 }; msg_t msg; // build the snapshot From dfb6c37c9e6cab7714698e14354f68ef6747362f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:42:28 +0200 Subject: [PATCH 0500/2040] Don't copy the server name if it's from the same string address --- code/server/sv_init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 0f474265..0faebf3a 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -573,7 +573,11 @@ void SV_SpawnServer( const char *server, qboolean loadgame, qboolean restart, qb differentmap = qtrue; - strncpy( svs.rawServerName, server, sizeof( svs.rawServerName ) ); + if (svs.rawServerName != server) { + // Fixed in OPM + // Make sure to not copy from the same string... + strncpy( svs.rawServerName, server, sizeof( svs.rawServerName ) ); + } // check for a spawn position spawnpos = strchr( server, '$' ); From 5192d36f8127bc2b0707db835b247cc61a29a280 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:43:03 +0200 Subject: [PATCH 0501/2040] Fixes gametype incorrectly checked in `G_InitWorldSession` --- code/fgame/g_session.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/code/fgame/g_session.cpp b/code/fgame/g_session.cpp index 465e2405..bbd3a076 100644 --- a/code/fgame/g_session.cpp +++ b/code/fgame/g_session.cpp @@ -96,16 +96,13 @@ G_InitWorldSession ================== */ void G_InitWorldSession( void ) { - char s[MAX_STRING_CHARS]; - int gt; + int gt; - cvar_t *v = gi.Cvar_Get( "session", "", 0 ); - - gt = atoi( s ); + cvar_t *v = gi.Cvar_Get( "session", "-1", 0 ); // if the gametype changed since the last session, don't use any // client sessions - if ( g_gametype->integer != gt ) { + if ( g_gametype->integer != v->integer ) { G_Printf( "Gametype changed, clearing session data.\n" ); } } From 186d7a12e570614a3352e880b966fefd6b500976 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:51:20 +0200 Subject: [PATCH 0502/2040] typo --- code/server/sv_snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index fb4f82d2..fe190bca 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -1076,7 +1076,7 @@ Also called by SV_FinalMessage ======================= */ void SV_SendClientSnapshot( client_t *client ) { - byte msg_buf[MAX_MSGLEN]{ 0 }; + byte msg_buf[MAX_MSGLEN] = { 0 }; msg_t msg; // build the snapshot From 01d938b5ba8047dd8a82bf7403cfb9c66a050854 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:03:04 +0200 Subject: [PATCH 0503/2040] Fixes some variables being uninitialized --- code/fgame/actor.cpp | 5 +++++ code/fgame/sentient.cpp | 3 ++- code/server/sv_snapshot.c | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index f74215c2..61fd1a3a 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -2952,6 +2952,11 @@ Actor::Actor() } mVoiceType = -1; + + // + // Added in OPM + // + m_bSilent = false; } /* diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index 94305ef4..900e6da7 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -690,7 +690,8 @@ void Sentient::EventGiveDynItem(Event *ev) } Sentient::Sentient() - : m_bIsAnimal(false) + : mAccuracy(0.2f) + , m_bIsAnimal(false) { SentientList.AddObject((Sentient *)this); entflags |= ECF_SENTIENT; diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index fe190bca..7ac89133 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -1076,7 +1076,7 @@ Also called by SV_FinalMessage ======================= */ void SV_SendClientSnapshot( client_t *client ) { - byte msg_buf[MAX_MSGLEN] = { 0 }; + byte msg_buf[MAX_MSGLEN]; msg_t msg; // build the snapshot @@ -1088,6 +1088,7 @@ void SV_SendClientSnapshot( client_t *client ) { return; } + memset(msg_buf, 0, sizeof(msg_buf)); MSG_Init (&msg, msg_buf, sizeof(msg_buf)); msg.allowoverflow = qtrue; From 2f48ca6adb5c09ecf896b76b1695b220ae24efc3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:03:27 +0200 Subject: [PATCH 0504/2040] Adds assertion check to check if top stack is out of bounds --- code/script/scriptvm.cpp | 15 ++++++++++----- code/script/scriptvm.h | 9 +++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/code/script/scriptvm.cpp b/code/script/scriptvm.cpp index 168ce2a3..6b614acd 100644 --- a/code/script/scriptvm.cpp +++ b/code/script/scriptvm.cpp @@ -79,6 +79,7 @@ ScriptVMStack::ScriptVMStack() : localStack(nullptr) , stackBottom(nullptr) , pTop(nullptr) + , m_bMarkStack(false) {} ScriptVMStack::ScriptVMStack(size_t stackSize) @@ -157,11 +158,13 @@ ScriptVariable& ScriptVMStack::SetTop(ScriptVariable& newTop) ScriptVariable& ScriptVMStack::GetTop() const { + assert(m_bMarkStack || pTop < stackBottom); return *pTop; } ScriptVariable& ScriptVMStack::GetTop(size_t offset) const { + assert(m_bMarkStack || (pTop + offset) < stackBottom); return *(pTop + offset); } @@ -210,23 +213,27 @@ ScriptVariable& ScriptVMStack::PopAndGet(size_t offset) ScriptVariable& ScriptVMStack::Push() { + assert(!m_bMarkStack && (pTop + 1) < stackBottom); return *(pTop++); } ScriptVariable& ScriptVMStack::Push(size_t offset) { ScriptVariable& old = *pTop; + assert(!m_bMarkStack && (pTop + offset) < stackBottom); pTop += offset; return old; } ScriptVariable& ScriptVMStack::PushAndGet() { + assert(!m_bMarkStack && (pTop + 1) < stackBottom); return *++pTop; } ScriptVariable& ScriptVMStack::PushAndGet(size_t offset) { + assert(!m_bMarkStack && (pTop + offset) < stackBottom); pTop += offset; return *pTop; } @@ -305,7 +312,6 @@ ScriptVM::ScriptVM() m_pOldData = NULL; m_OldDataSize = 0; - m_bMarkStack = false; m_StackPos = NULL; } @@ -333,7 +339,6 @@ ScriptVM::ScriptVM(ScriptClass *scriptClass, unsigned char *pCodePos, ScriptThre m_pOldData = NULL; m_OldDataSize = 0; - m_bMarkStack = false; m_StackPos = NULL; m_ScriptClass->AddThread(this); @@ -1081,7 +1086,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) Director.cmdCount = 0; } - if (!m_bMarkStack) { + if (!m_VMStack.m_bMarkStack) { /* assert(pTop >= localStack && pTop < localStack + localStackSize); if (pTop < localStack) @@ -1549,7 +1554,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) case OP_MARK_STACK_POS: m_StackPos = &m_VMStack.GetTop(); - m_bMarkStack = true; + m_VMStack.m_bMarkStack = true; break; case OP_STORE_PARAM: @@ -1564,7 +1569,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) case OP_RESTORE_STACK_POS: m_VMStack.SetTop(*m_StackPos); - m_bMarkStack = false; + m_VMStack.m_bMarkStack = false; break; case OP_STORE_ARRAY: diff --git a/code/script/scriptvm.h b/code/script/scriptvm.h index 2d74153a..7f4b0e6c 100644 --- a/code/script/scriptvm.h +++ b/code/script/scriptvm.h @@ -123,7 +123,12 @@ private: /** The local stack size. */ ScriptVariable *stackBottom; /** Variable from the top stack of the local stack. */ - ScriptVariable *pTop; + ScriptVariable* pTop; + +public: + /** Whether or not the stack is marked. */ + /** changed by OP_MARK_STACK_POS and OP_RESTORE_STACK_POS */ + bool m_bMarkStack; }; class ScriptVM @@ -159,7 +164,7 @@ public: // parameters variables ScriptVariable *m_pOldData; // old fastEvent data, to cleanup int m_OldDataSize; - bool m_bMarkStack; // changed by OP_MARK_STACK_POS and OP_RESTORE_STACK_POS + //bool m_bMarkStack; // changed by OP_MARK_STACK_POS and OP_RESTORE_STACK_POS Event fastEvent; // parameter list, set when the VM is executed private: From 13197acb3ae09dc729bc8cc0fa5912c22971f20c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:17:58 +0200 Subject: [PATCH 0505/2040] Uses a `signed char` instead of a `char` for opcode stack offset. On some platforms like ARM, `char` is unsigned by default This fixes #311 where a memory corruption that occurred in ARM was caused because of insufficient ScriptVM stack size. The stack size was incorrectly calculated because the stack offset was using unsigned values instead of signed in ARM. --- code/script/scriptcompiler.cpp | 2 +- code/script/scriptcompiler.h | 2 +- code/script/scriptopcodes.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/script/scriptcompiler.cpp b/code/script/scriptcompiler.cpp index a7acb868..eef31697 100644 --- a/code/script/scriptcompiler.cpp +++ b/code/script/scriptcompiler.cpp @@ -77,7 +77,7 @@ unsigned char ScriptCompiler::PrevOpcode() return prev_opcodes[prev_opcode_pos].opcode; } -char ScriptCompiler::PrevVarStackOffset() +signed char ScriptCompiler::PrevVarStackOffset() { return prev_opcodes[prev_opcode_pos].VarStackOffset; } diff --git a/code/script/scriptcompiler.h b/code/script/scriptcompiler.h index 81e85be2..42203b01 100644 --- a/code/script/scriptcompiler.h +++ b/code/script/scriptcompiler.h @@ -77,7 +77,7 @@ public: void Reset(); unsigned char PrevOpcode(); - char PrevVarStackOffset(); + signed char PrevVarStackOffset(); void AbsorbPrevOpcode(); void ClearPrevOpcode(); void AccumulatePrevOpcode(int opcode, int iVarStackOffset); diff --git a/code/script/scriptopcodes.h b/code/script/scriptopcodes.h index 62ade8fd..ddddfb43 100644 --- a/code/script/scriptopcodes.h +++ b/code/script/scriptopcodes.h @@ -50,7 +50,7 @@ typedef struct { typedef struct { unsigned char opcode; - char VarStackOffset; + signed char VarStackOffset; } opcode_info_t; typedef enum { From 1f0f5764a8146e8115a22cc9597e244ff3692f2b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 22 Jun 2024 21:41:28 +0200 Subject: [PATCH 0506/2040] Added PathInfo() constructor initialization --- code/fgame/navigate.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/code/fgame/navigate.h b/code/fgame/navigate.h index 8d6934df..69c3af2e 100644 --- a/code/fgame/navigate.h +++ b/code/fgame/navigate.h @@ -103,9 +103,20 @@ public: vec2_t dir; public: + PathInfo(); + void Archive(Archiver& arc); }; + +inline PathInfo::PathInfo() + : bAccurate(false) + , point{ 0, 0, 0 } + , dist(0) + , dir{ 0, 0 } +{ +} + inline void PathInfo::Archive(Archiver& arc) { arc.ArchiveBool(&bAccurate); From 9407b64fe3726a136547af6b9cf40c077e161db1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 23 Jun 2024 00:18:22 +0200 Subject: [PATCH 0507/2040] Q_strncpyz: don't copy if the src is the same as the dest --- code/qcommon/q_shared.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 91622016..b9d679a0 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -1195,18 +1195,24 @@ Safe strncpy that ensures a trailing zero ============= */ void Q_strncpyz( char *dest, const char *src, size_t destsize ) { - if ( !dest ) { - Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" ); - } - if ( !src ) { - Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); - } - if ( destsize < 1 ) { - Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); - } + if ( !dest ) { + Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" ); + } - strncpy( dest, src, destsize-1 ); - dest[destsize-1] = 0; + if ( !src ) { + Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); + } + + if ( destsize < 1 ) { + Com_Error( ERR_FATAL, "Q_strncpyz: destsize < 1" ); + } + + if ( dest == src ) { + return; + } + + strncpy( dest, src, destsize - 1 ); + dest[ destsize - 1 ] = 0; } int Q_stricmpn( const char *s1, const char *s2, size_t n ) { From 9d654faa3ddcd1379cc772685690f9ae0ae629a7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 23 Jun 2024 00:24:20 +0200 Subject: [PATCH 0508/2040] As `m_BlockedPaths` is an array of `pathway_ref`, the proper `delete` call must be used --- code/fgame/entity.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 95fbb02e..547c3061 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -1847,8 +1847,8 @@ Entity::~Entity() } if (m_BlockedPaths) { - delete m_BlockedPaths; - m_BlockedPaths = 0; + delete[] m_BlockedPaths; + m_BlockedPaths = NULL; } level.FreeEdict(edict); @@ -5643,7 +5643,7 @@ void Entity::ConnectPaths(void) m_iNumBlockedPaths = 0; if (m_BlockedPaths) { - delete m_BlockedPaths; + delete[] m_BlockedPaths; m_BlockedPaths = NULL; } } From 0a6c745ffb35be67baa23c6f40e4c050be5df39d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:10:58 +0200 Subject: [PATCH 0509/2040] Use VectorNormalize() instead of VectorNormalize2() --- code/qcommon/cm_polylib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/cm_polylib.c b/code/qcommon/cm_polylib.c index 569b0299..5450c6df 100644 --- a/code/qcommon/cm_polylib.c +++ b/code/qcommon/cm_polylib.c @@ -236,7 +236,7 @@ winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist) v = DotProduct (vup, normal); VectorMA (vup, -v, normal, vup); - VectorNormalize2(vup, vup); + VectorNormalize(vup); VectorScale (normal, dist, org); From 303ed30a3813c1fbad188fb164fddbb384b6485d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:19:52 +0200 Subject: [PATCH 0510/2040] Don't remove the facet is there is no border planeCM_PlaneEqual --- code/qcommon/cm_patch.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/code/qcommon/cm_patch.c b/code/qcommon/cm_patch.c index 67175192..17b9e5de 100644 --- a/code/qcommon/cm_patch.c +++ b/code/qcommon/cm_patch.c @@ -766,10 +766,6 @@ static qboolean CM_ValidateFacet( facet_t *facet ) { Vector4Copy( planes[ facet->surfacePlane ].plane, plane ); w = BaseWindingForPlane( plane, plane[3] ); for ( j = 0 ; j < facet->numBorders && w ; j++ ) { - if ( facet->borderPlanes[j] == -1 ) { - FreeWinding( w ); - return qfalse; - } Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane ); if ( !facet->borderInward[j] ) { VectorSubtract( vec3_origin, plane, plane ); @@ -790,12 +786,6 @@ static qboolean CM_ValidateFacet( facet_t *facet ) { if ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) { return qfalse; // we must be missing a plane } - if ( bounds[0][j] >= MAX_MAP_BOUNDS ) { - return qfalse; - } - if ( bounds[1][j] <= -MAX_MAP_BOUNDS ) { - return qfalse; - } } return qtrue; // winding is fine } @@ -1314,7 +1304,7 @@ void CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollid } for ( j = 0 ; j < facet->numBorders ; j++ ) { k = facet->borderPlanes[j]; - if ( frontFacing[k] ^ facet->borderInward[j] ) { + if ( frontFacing[k] != facet->borderInward[j] ) { if ( intersection[k] > intersect ) { break; } From 563182c14c4510516b8354f7fe8bb3e8b1ce91f2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:25:23 +0200 Subject: [PATCH 0511/2040] Added FloatRoundedBitError() (currently unused) --- code/qcommon/q_math.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index 222b31e0..f81c121c 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -4136,4 +4136,24 @@ float PointToSegmentDistanceSquared(const vec3_t origin, const vec3_t a, const v } return VectorLengthSquared(final); -} \ No newline at end of file +} + +/* +================= +FloatRoundedBitError + +On x86 with FP87, some float operations may have results that are off by 1 bit. +This returns whether or not the operation lost 1 bit. +================= +*/ +qboolean FloatRoundedBitError() { + float a, b, c; + float value; + + a = 91.0000610; + b = 40.0000038; + c = 0.00005; + value = a * b + c; + + return value != 3640.00269f; +} From cda6225659d9c99da2be70e4cc52fa068dcf0e23 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:26:07 +0200 Subject: [PATCH 0512/2040] Adds a workaround against a bit that was lost on x86 with FP87. This fixes #312 where a rounding error caused facets to be removed due to windings points being outside of the epsilon --- code/qcommon/cm_polylib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/qcommon/cm_polylib.c b/code/qcommon/cm_polylib.c index 5450c6df..bed23de9 100644 --- a/code/qcommon/cm_polylib.c +++ b/code/qcommon/cm_polylib.c @@ -440,9 +440,9 @@ void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t eps dot = DotProduct (in->p[i], normal); dot -= dist; dists[i] = dot; - if (dot > epsilon) + if ((dot + 0.0005) > epsilon) sides[i] = SIDE_FRONT; - else if (dot < -epsilon) + else if ((dot - 0.0005) < -epsilon) sides[i] = SIDE_BACK; else { From d709dda87a50c4499d2c718404a967662bf83514 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:57:32 +0200 Subject: [PATCH 0513/2040] Use shader's distance range instead of the portal range --- code/renderer/tr_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 899581fd..968228b7 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -1059,7 +1059,7 @@ qboolean SurfIsOffscreen(const srfSurfaceFace_t* surface, shader_t* shader, int if (shader->fDistRange > 0.0) { - if (shortest > (tess.shader->portalRange * tess.shader->portalRange)) + if (shortest > Square(shader->fDistRange)) { return qtrue; } From 408c90134299c12343be77c87589a8c114b983ec Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:58:10 +0200 Subject: [PATCH 0514/2040] Fixes skyboxSpeed using an integer rather than a float This fixes #313 where the skybox would be misplaced --- code/fgame/worldspawn.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/worldspawn.cpp b/code/fgame/worldspawn.cpp index b91f32eb..07b68725 100644 --- a/code/fgame/worldspawn.cpp +++ b/code/fgame/worldspawn.cpp @@ -925,12 +925,12 @@ void World::SetRenderTerrain(Event *ev) void World::GetSkyboxSpeed(Event *ev) { - ev->AddInteger(skybox_speed); + ev->AddFloat(skybox_speed); } void World::SetSkyboxSpeed(Event *ev) { - skybox_speed = ev->GetInteger(1); + skybox_speed = ev->GetFloat(1); } void World::SetSkyAlpha(Event *ev) From 87baa69d7cb03d5953a972a267bfb651e851d900 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:20:33 +0200 Subject: [PATCH 0515/2040] Fixes incorrect lighting color normalization This fixes #314 where mark colors would have their values warped back to 0, making holes blue --- code/renderer/tr_light.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_light.c b/code/renderer/tr_light.c index 804f096d..2a8dd722 100644 --- a/code/renderer/tr_light.c +++ b/code/renderer/tr_light.c @@ -895,7 +895,7 @@ void R_GetLightingForDecal(vec3_t vLight, const vec3_t vFacing, const vec3_t vOr VectorScale(vLight, tr.overbrightMult, vLight); if (vLight[0] > 255.0 || vLight[1] > 255.0 || vLight[2] > 255.0) { - float scale = 255.0 / fmin(vLight[0], fmin(vLight[1], vLight[2])); + float scale = 255.0 / fmax(vLight[0], fmax(vLight[1], vLight[2])); VectorScale(vLight, scale, vLight); } } @@ -945,7 +945,7 @@ static int RB_GetEntityGridLighting() // normalize if (vLight[0] > 255.0 || vLight[1] > 255.0 || vLight[2] > 255.0) { - float scale = 255.0 / fmin(vLight[0], fmin(vLight[1], vLight[2])); + float scale = 255.0 / fmax(vLight[0], fmax(vLight[1], vLight[2])); VectorScale(vLight, scale, vLight); } From 7059f32eccdbdce9a482fb0a55cf6d37afd11c88 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 01:09:39 +0200 Subject: [PATCH 0516/2040] Don't timeout if the client hosts the game --- code/client/cl_main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 41e3d57f..f668bc43 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -2419,6 +2419,13 @@ CL_CheckTimeout ================== */ void CL_CheckTimeout( void ) { + if (com_sv_running->integer) { + // Added in OPM + // Timeout should not be possible if the client is hosting the game + // (like in single-player mode) + return; + } + // // check timeout // From 0d394a7e679be831900ce4c7372611334a452ab5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:15:00 +0200 Subject: [PATCH 0517/2040] Fixes strings printing on the same line --- code/client/cl_input.cpp | 6 +++--- code/server/sv_ccmds.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index fc52a69f..f3152d0d 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -577,9 +577,9 @@ void CL_MouseMove( usercmd_t *cmd ) { cmd->forwardmove = ClampChar(cmd->forwardmove - m_forward->value * my); if (!isfinite(cl.viewangles[PITCH]) || !isfinite(cl.viewangles[YAW])) { - Com_Printf("Invalid client viewangles encountered!\n"); - Com_Printf("cgameSensitivity: %f - mx: %f - my: %f - m_pitch: %f - m_yaw: %f", cgameSensitivity, mx, my, m_pitch->value, m_yaw->value); - Com_Printf("Resetting client viewangles"); + Com_DPrintf("Invalid client viewangles encountered (view pitch: %f, view yaw: %f)!\n", cl.viewangles[PITCH], cl.viewangles[YAW]); + Com_DPrintf("cgameSensitivity: %f | mx: %f | my: %f | m_pitch: %f | m_yaw: %f\n", cgameSensitivity, mx, my, m_pitch->value, m_yaw->value); + Com_DPrintf("Resetting client viewangles\n"); cl.viewangles[PITCH] = 0; cl.viewangles[YAW] = 0; } diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 9c6c479a..1e601533 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -2265,9 +2265,9 @@ void SV_SaveGame( const char *gamename, qboolean autosave ) Com_Printf( "Saving to %s", name ); if( autosave ) { - Com_DPrintf( " (autosave)...\n" ); + Com_Printf( " (autosave)...\n" ); } else { - Com_DPrintf( "...\n" ); + Com_Printf( "...\n" ); } strcpy( svs.gameName, name ); From f866dcbcfc016fa37d3ade17f686684d4ec15aae Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:10:37 +0200 Subject: [PATCH 0518/2040] Adds triggered music support This allows the main menu music to play, as well as single-player musics --- code/client/new/snd_main_new.cpp | 51 +++++++++++++++++++++++++++++++- code/client/new/snd_public_new.h | 4 +++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index 7fd517d6..0007453a 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -33,6 +33,10 @@ void S_Init2() // HACK: S_RegisterSound returns 0 when unsuccessful, or it returns the the sfx handle // But the first sfx handle is also 0... S_RegisterSound("sound/null.wav", qfalse); + + Cmd_AddCommand("tmstart", S_TriggeredMusic_Start); + Cmd_AddCommand("tmstartloop", S_TriggeredMusic_StartLoop); + Cmd_AddCommand("tmstop", S_TriggeredMusic_Stop); } /* @@ -439,8 +443,53 @@ void S_FadeSound(float fTime) // FIXME: unimplemented } +/* +============== +S_TriggeredMusic_Start +============== +*/ +void S_TriggeredMusic_Start() +{ + if (Cmd_Argc() != 2) { + Com_Printf("tmstart \n"); + return; + } + + S_StartBackgroundTrack(Cmd_Argv(1), ""); +} + +/* +============== +S_TriggeredMusic_StartLoop +============== +*/ +void S_TriggeredMusic_StartLoop() +{ + if (Cmd_Argc() != 2) { + Com_Printf("tmstartloop \n"); + return; + } + + S_StartBackgroundTrack(Cmd_Argv(1), Cmd_Argv(1)); +} + +/* +============== +S_TriggeredMusic_Stop +============== +*/ +void S_TriggeredMusic_Stop() +{ + S_StopBackgroundTrack(); +} + +/* +============== +S_TriggeredMusic_PlayIntroMusic +============== +*/ void S_TriggeredMusic_PlayIntroMusic() { - // FIXME: unimplemented + S_StartBackgroundTrack("sound/music/mus_MainTheme.mp3", ""); } void callbackServer(int entnum, int channel_number, const char* name) { diff --git a/code/client/new/snd_public_new.h b/code/client/new/snd_public_new.h index 0b298c01..1e7d32a2 100644 --- a/code/client/new/snd_public_new.h +++ b/code/client/new/snd_public_new.h @@ -64,6 +64,10 @@ qboolean MUSIC_PlaySong(const char* alias); void MUSIC_UpdateMusicVolumes(void); void MUSIC_CheckForStoppedSongs(void); +void S_TriggeredMusic_Start(); +void S_TriggeredMusic_StartLoop(); +void S_TriggeredMusic_Stop(); + void S_StopSound(int entnum, int channel); void S_StopAllSounds2(qboolean stop_music); float S_GetSoundTime(sfxHandle_t handle); From 2cd6b981f1988cf46d45f7b4e0594434fa04e5bd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:46:47 +0200 Subject: [PATCH 0519/2040] Puts the volume gain constant in a variable --- code/client/snd_openal_new.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 2a1ca925..c9e2007f 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -43,6 +43,8 @@ static bool s_bReverbChanged = false; static bool s_bFading = false; static float s_fFadeVolume = 1.f; +static constexpr float s_fVolumeGain = 1.f; // = 84.f; + cvar_t *s_milesdriver; cvar_t *s_openaldevice; cvar_t *s_reverb; @@ -380,9 +382,7 @@ S_OPENAL_InitChannel static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) { openal.channel[idx] = chan; - chan->vOrigin[2] = 0.0; - chan->vOrigin[1] = 0.0; - chan->vOrigin[0] = 0.0; + VectorClear(chan->vOrigin); chan->fVolume = 1.0; chan->fNewPitchMult = 0.0; chan->fMinDist = 0.0; @@ -1250,7 +1250,7 @@ static void S_OPENAL_Start2DSound( pChannel->iBaseRate = pChannel->sample_playback_rate(); pChannel->set_no_3d(); - fRealVolume = fRealVolume * 84.f; + fRealVolume = fRealVolume * s_fVolumeGain; pChannel->set_gain(fRealVolume); pChannel->play(); } else { @@ -1824,7 +1824,7 @@ static bool S_OPENAL_UpdateLoopSound( vec3_t vOrigin; int iPan; - pChannel->fVolume = fVolumeToPlay / 84.0; + pChannel->fVolume = fVolumeToPlay / s_fVolumeGain; fVolume = S_GetBaseVolume() * pChannel->fVolume; fMaxVolume = fVolume; @@ -2022,7 +2022,7 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) if (pLoopSound->bPlaying) { S_OPENAL_UpdateLoopSound( pLoopSound, - S_GetBaseVolume() * 84.0 * fTotalVolume, + S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, fMaxDistance, vListenerOrigin, @@ -2040,12 +2040,12 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { iChannel = S_OPENAL_Start2DLoopSound( - pLoopSound, fVolume, S_GetBaseVolume() * 84.0 * fTotalVolume, fMinDistance, vLoopOrigin + pLoopSound, fVolume, S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, vLoopOrigin ); } else { iChannel = S_OPENAL_Start3DLoopSound( pLoopSound, - S_GetBaseVolume() * 84.0 * fTotalVolume, + S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, fMaxDistance, vLoopOrigin, @@ -3670,7 +3670,7 @@ qboolean MUSIC_PlaySong(const char *alias) song_channel->fade_start_time = cls.realtime; } else { song_channel->fading = FADE_NONE; - song_channel->set_gain(S_GetBaseVolume() * (song->volume * s_ambientVolume->value) * 84.f); + song_channel->set_gain(S_GetBaseVolume() * (song->volume * s_ambientVolume->value) * s_fVolumeGain); } song_channel->play(); @@ -3703,7 +3703,7 @@ void MUSIC_UpdateMusicVolumes() openal.chan_song[i].set_gain( S_GetBaseVolume() * (music_songs[openal.chan_song[i].song_number].volume * s_ambientVolume->value) - * 84.0 * music_volume + * s_fVolumeGain * music_volume ); } } @@ -3720,10 +3720,10 @@ void MUSIC_UpdateMusicVolumes() / (openal.chan_song[i].fade_time * 1000.f) * max_volume; if (new_volume > max_volume) { - openal.chan_song[i].set_gain(S_GetBaseVolume() * (max_volume * 84.f * music_volume)); + openal.chan_song[i].set_gain(S_GetBaseVolume() * (max_volume * s_fVolumeGain * music_volume)); openal.chan_song[i].fading = FADE_NONE; } else { - openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * 84.f * music_volume)); + openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * s_fVolumeGain * music_volume)); } break; case fade_t::FADE_OUT: @@ -3732,7 +3732,7 @@ void MUSIC_UpdateMusicVolumes() / (openal.chan_song[i].fade_time * 1000.f) * max_volume; if (new_volume > 0) { - openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * 84.f * music_volume)); + openal.chan_song[i].set_gain(S_GetBaseVolume() * (new_volume * s_fVolumeGain * music_volume)); } else { MUSIC_StopChannel(i); } @@ -3746,7 +3746,7 @@ void MUSIC_UpdateMusicVolumes() s_musicVolume->modified = false; if (openal.chan_trig_music.is_playing() || openal.chan_trig_music.is_paused()) { openal.chan_trig_music.set_gain( - S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * 84.f + S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * s_fVolumeGain ); } } @@ -3826,7 +3826,7 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs } openal.chan_trig_music.fVolume = fVolume; - openal.chan_trig_music.set_gain(S_GetBaseVolume() * (fVolume * s_musicVolume->value) * 84.f); + openal.chan_trig_music.set_gain(S_GetBaseVolume() * (fVolume * s_musicVolume->value) * s_fVolumeGain); openal.chan_trig_music.set_sample_loop_count(iLoopCount); openal.chan_trig_music.set_sample_offset(iOffset); @@ -3910,7 +3910,7 @@ void S_TriggeredMusic_Unpause() openal.chan_trig_music.play(); } - openal.chan_trig_music.set_gain(S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * 84.f); + openal.chan_trig_music.set_gain(S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * s_fVolumeGain); } /* From 74ff3b920e18aa35943afa44cf0ff6fa527ab7ff Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:39:32 +0200 Subject: [PATCH 0520/2040] Fixes OpenAL 2D origin --- code/client/snd_openal_new.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index c9e2007f..1673afd8 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1038,8 +1038,7 @@ static int S_OPENAL_PickChannelBase(int iEntNum, int iEntChannel, int iFirstChan } if (!bStoppedChannel) { - i = iLastChannel; - while (++i <= 95) { + for(i = iLastChannel + 1; i < MAX_OPENAL_POSITION_CHANNELS; i++) { pChannel = openal.channel[i]; if (!pChannel || pChannel->is_free()) { continue; @@ -1215,17 +1214,19 @@ static void S_OPENAL_Start2DSound( pChannel->iEntNum = 0; if (vOrigin) { - pChannel->vOrigin[0] = -vOrigin[0]; - pChannel->vOrigin[1] = vOrigin[2]; - pChannel->vOrigin[2] = -vOrigin[1]; + //pChannel->vOrigin[0] = -vOrigin[0]; + //pChannel->vOrigin[1] = vOrigin[2]; + //pChannel->vOrigin[2] = -vOrigin[1]; + VectorCopy(vOrigin, pChannel->vOrigin); } } else { pChannel->iFlags &= ~CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = iRealEntNum; if (vOrigin) { - pChannel->vOrigin[0] = -vOrigin[0]; - pChannel->vOrigin[1] = vOrigin[2]; - pChannel->vOrigin[2] = -vOrigin[1]; + //pChannel->vOrigin[0] = -vOrigin[0]; + //pChannel->vOrigin[1] = vOrigin[2]; + //pChannel->vOrigin[2] = -vOrigin[1]; + VectorCopy(vOrigin, pChannel->vOrigin); bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; pChannel->iTime = cl.serverTime - 1; From ae13be0c37b1f89f8150b873e6895054f5840f2c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:39:47 +0200 Subject: [PATCH 0521/2040] Fixes OpenAL errors --- code/client/snd_openal_new.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 1673afd8..a04c9364 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2827,7 +2827,7 @@ openal_channel::set_sfx */ bool openal_channel::set_sfx(sfx_t *pSfx) { - ALfloat freq = 0; + ALint freq = 0; this->pSfx = pSfx; if (!pSfx->buffer || !qalIsBuffer(pSfx->buffer)) { @@ -2893,7 +2893,7 @@ bool openal_channel::set_sfx(sfx_t *pSfx) alDieIfError(); // Get the base frequency - qalGetBufferfv(pSfx->buffer, AL_FREQUENCY, &freq); + qalGetBufferi(pSfx->buffer, AL_FREQUENCY, &freq); alDieIfError(); iBaseRate = freq; @@ -3062,9 +3062,11 @@ void openal_channel::set_sample_loop_count(S32 count) alDieIfError(); } - for (S32 i = 0; i < count; i++) { - qalSourceQueueBuffers(source, 1, &buffer); - alDieIfError(); + if (buffer) { + for (S32 i = 0; i < count; i++) { + qalSourceQueueBuffers(source, 1, &buffer); + alDieIfError(); + } } } From 140242a761ebf6c28a2cfb9056966da505d4f886 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:00:15 +0200 Subject: [PATCH 0522/2040] Fixes MP3 files like dialog improperly working --- code/client/snd_openal_new.cpp | 68 ++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index a04c9364..3302fa7e 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -103,7 +103,8 @@ static void S_OPENAL_Pitch(); static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin); static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); -static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan); +static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx); +static ALuint S_OPENAL_Format(int width, int channels); # define alDieIfError() __alDieIfError(__FILE__, __LINE__) @@ -726,8 +727,55 @@ S_OPENAL_LoadMP3 */ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) { - return S_OPENAL_LoadMP3_Codec(_path, chan); + char path[MAX_QPATH]; + snd_info_t info; + ALuint format; + chan->stop(); + + qalSourcei(chan->source, AL_BUFFER, 0); + alDieIfError(); + + Q_strncpyz(path, _path, sizeof(path)); + path[MAX_QPATH - 1] = 0; + + FS_CorrectCase(path); + + // Try to load + chan->bufferdata = (ALubyte*)S_CodecLoad(path, &info); + if (!chan->bufferdata) { + return false; + } + + format = S_OPENAL_Format(info.width, info.channels); + + // Create a buffer + qalGenBuffers(1, &chan->buffer); + alDieIfError(); + + // Fill the buffer + if (info.size == 0) { + // We have no data to buffer, so buffer silence + byte dummyData[2] = {0}; + + qalBufferData(chan->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050); + } else { + qalBufferData(chan->buffer, format, chan->bufferdata, info.size, info.rate); + } + + alDieIfError(); + + // Free the memory + Hunk_FreeTempMemory(chan->bufferdata); + + qalSourcei(chan->source, AL_BUFFER, chan->buffer); + alDieIfError(); + + chan->set_no_3d(); + + return true; + +#if 0 char path[MAX_QPATH]; FILE *in; size_t len; @@ -789,6 +837,7 @@ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) chan->set_no_3d(); return true; +#endif } /* @@ -2836,7 +2885,7 @@ bool openal_channel::set_sfx(sfx_t *pSfx) alDieIfError(); //if (!_alutLoadMP3_LOKI(pSfx->buffer, pSfx->data, pSfx->length)) { - if (!S_OPENAL_LoadMP3_Codec(pSfx->name, this)) { + if (!S_OPENAL_LoadMP3_Codec(pSfx->name, pSfx)) { qalDeleteBuffers(1, &pSfx->buffer); alDieIfError(); @@ -3989,7 +4038,7 @@ static ALuint S_OPENAL_Format(int width, int channels) S_OPENAL_LoadMP3_Codec ============== */ -static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan) +static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx) { void *data; snd_info_t info; @@ -4004,7 +4053,7 @@ static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan) format = S_OPENAL_Format(info.width, info.channels); // Create a buffer - qalGenBuffers(1, &chan->buffer); + qalGenBuffers(1, &pSfx->buffer); alDieIfError(); // Fill the buffer @@ -4012,9 +4061,9 @@ static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan) // We have no data to buffer, so buffer silence byte dummyData[2] = {0}; - qalBufferData(chan->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050); + qalBufferData(pSfx->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050); } else { - qalBufferData(chan->buffer, format, data, info.size, info.rate); + qalBufferData(pSfx->buffer, format, data, info.size, info.rate); } alDieIfError(); @@ -4022,11 +4071,6 @@ static bool S_OPENAL_LoadMP3_Codec(const char *_path, openal_channel *chan) // Free the memory Hunk_FreeTempMemory(data); - qalSourcei(chan->source, AL_BUFFER, chan->buffer); - alDieIfError(); - - chan->set_no_3d(); - return true; } From edb1cb0ebee4a1591bf950647abd8aca1d95ebe5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:05:24 +0200 Subject: [PATCH 0523/2040] Renamed `SFX_FLAG_NO_DATA` to `SFX_FLAG_STREAMED` --- code/client/snd_local_new.h | 2 +- code/client/snd_mem_new.c | 4 ++-- code/client/snd_openal_new.cpp | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 707ecc1e..20358ddb 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -148,7 +148,7 @@ enum channel_flags_t { enum sfx_flags_t { SFX_FLAG_DEFAULT_SOUND = 1, SFX_FLAG_MP3 = 2, - SFX_FLAG_NO_DATA = 4, + SFX_FLAG_STREAMED = 4, SFX_FLAG_NO_OFFSET = 8, }; diff --git a/code/client/snd_mem_new.c b/code/client/snd_mem_new.c index 13dc44a2..2cd06435 100644 --- a/code/client/snd_mem_new.c +++ b/code/client/snd_mem_new.c @@ -478,7 +478,7 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo } } - if (!(sfx->iFlags & SFX_FLAG_NO_DATA) && realKhz < sfx->info.rate) { + if (!(sfx->iFlags & SFX_FLAG_STREAMED) && realKhz < sfx->info.rate) { byte* newdata; int newdatasize; @@ -499,7 +499,7 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo sfx->width = sfx->info.width; sfx->time_length = sfx->info.samples / sfx->info.rate * 1000.f; - if (sfx->iFlags & SFX_FLAG_NO_DATA) { + if (sfx->iFlags & SFX_FLAG_STREAMED) { Z_Free(sfx->data); sfx->data = NULL; } diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 3302fa7e..fabe7a92 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1205,7 +1205,7 @@ static void S_OPENAL_Start2DSound( iRealEntNum = iEntNum & ~S_FLAG_DO_CALLBACK; - if (pSfx->iFlags & SFX_FLAG_NO_DATA) { + if (pSfx->iFlags & SFX_FLAG_STREAMED) { iFreeChannel = S_OPENAL_PickChannel2DStreamed(iRealEntNum, iEntChannel); } else { iFreeChannel = S_OPENAL_PickChannel2D(iRealEntNum, iEntChannel); @@ -1214,7 +1214,7 @@ static void S_OPENAL_Start2DSound( if (iFreeChannel < 0) { Com_DPrintf( "Couldn't play %s sound '%s' for entity %i on channel %s\n", - (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "2Dstreamed" : "2D", + (pSfx->iFlags & SFX_FLAG_STREAMED) ? "2Dstreamed" : "2D", pSfx->name, iRealEntNum, S_ChannelNumToName(iEntChannel) @@ -1352,7 +1352,7 @@ void S_OPENAL_StartSound( bOnlyUpdate = false; pSfx = &s_knownSfx[sfxHandle]; if (bStreamed) { - pSfx->iFlags |= SFX_FLAG_NO_DATA; + pSfx->iFlags |= SFX_FLAG_STREAMED; } if (!S_OPENAL_ShouldPlay(pSfx)) { @@ -1360,7 +1360,7 @@ void S_OPENAL_StartSound( return; } - if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU + if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_STREAMED | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) { S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist); return; @@ -1370,7 +1370,7 @@ void S_OPENAL_StartSound( iEntNum &= ~S_FLAG_DO_CALLBACK; pSfxInfo = &sfx_infos[pSfx->sfx_info_index]; - if (pSfx->iFlags & SFX_FLAG_NO_DATA) { + if (pSfx->iFlags & SFX_FLAG_STREAMED) { Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name); return; } @@ -1379,7 +1379,7 @@ void S_OPENAL_StartSound( if (iChannel < 0) { Com_DPrintf( "Couldn't play %s sound '%s' for entity %i on channel %s\n", - (pSfx->iFlags & SFX_FLAG_NO_DATA) ? "3Dstreamed" : "3D", + (pSfx->iFlags & SFX_FLAG_STREAMED) ? "3Dstreamed" : "3D", pSfx->name, iEntNum, S_ChannelNumToName(iEntChannel) @@ -1719,7 +1719,7 @@ static int S_OPENAL_Start2DLoopSound( int iSoundOFfset; openal_channel *pChannel; - if (pLoopSound->pSfx->iFlags & SFX_FLAG_NO_DATA) { + if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { iChannel = S_OPENAL_PickChannel2DStreamed(0, 0); } else { iChannel = S_OPENAL_PickChannel2D(0, 0); @@ -1789,7 +1789,7 @@ static int S_OPENAL_Start3DLoopSound( int iSoundOffset; openal_channel *pChan3D; - if (pLoopSound->pSfx->iFlags & SFX_FLAG_NO_DATA) { + if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { return -1; } @@ -1869,7 +1869,7 @@ static bool S_OPENAL_UpdateLoopSound( pChannel->iStartTime = cl.serverTime; - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { vec3_t vOrigin; int iPan; @@ -2087,7 +2087,7 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name); } - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_NO_DATA | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { iChannel = S_OPENAL_Start2DLoopSound( pLoopSound, fVolume, S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, vLoopOrigin From eefe8ee2d1ba57f61bc3bad0dcf82e92ebe6d6d9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:17:04 +0200 Subject: [PATCH 0524/2040] Allow 3D / pan with streamed or MP3 sounds --- code/client/snd_openal_new.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index fabe7a92..d2f7aa6e 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1360,8 +1360,10 @@ void S_OPENAL_StartSound( return; } - if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_STREAMED | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU - || iEntChannel == CHAN_LOCAL) { + // Fixed in OPM + // 3D streamed or MP3 sound should be supported + if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET)) //|| pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + || iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) { S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist); return; } @@ -1370,10 +1372,12 @@ void S_OPENAL_StartSound( iEntNum &= ~S_FLAG_DO_CALLBACK; pSfxInfo = &sfx_infos[pSfx->sfx_info_index]; - if (pSfx->iFlags & SFX_FLAG_STREAMED) { - Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name); - return; - } + // Fixed in OPM + // 3D streamed sound should be supported + //if (pSfx->iFlags & SFX_FLAG_STREAMED) { + // Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name); + // return; + //} iChannel = S_OPENAL_PickChannel3D(iEntNum, iEntChannel); if (iChannel < 0) { @@ -1789,9 +1793,11 @@ static int S_OPENAL_Start3DLoopSound( int iSoundOffset; openal_channel *pChan3D; - if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { - return -1; - } + // Fixed in OPM + // 3D streamed sound should be supported + //if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { + // return -1; + //} iChannel = S_OPENAL_PickChannel3D(0, 0); if (iChannel < 0) { @@ -2107,7 +2113,7 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) continue; } - pLoopSound->bPlaying = 1; + pLoopSound->bPlaying = true; pLoopSound->iChannel = iChannel; if (pLoopSound->bCombine) { From 63445c4fc1e292f22e28099dd99c52a445033dce Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:20:22 +0200 Subject: [PATCH 0525/2040] Added a note to use the experimental openal-based sound system --- docs/compiling.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/compiling.md b/docs/compiling.md index 39faec5f..dd9c6f4f 100644 --- a/docs/compiling.md +++ b/docs/compiling.md @@ -11,6 +11,8 @@ The installation directory can be set to the MOHAA directory. By default, the build will produce both the client and dedicated server versions. The client can be omitted from the build by appending `-DBUILD_NO_CLIENT=1` to the CMake command-line arguments. Using this parameter will result in only the server portion being built. +The experimental OpenAL-based sound system can be used by appending `-DUSE_SOUND_NEW=1` to the CMake command-line arguments. + ## Compiling for Linux These are the tools required on Linux : From 5fc2425f3a0be1a40fbd4dcee702f7afb026ec32 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:52:04 +0200 Subject: [PATCH 0526/2040] Set the mindist/maxdist for 3D sounds --- code/client/snd_openal_new.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index d2f7aa6e..d641e456 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2775,10 +2775,17 @@ void openal_channel::set_3d() alDieIfError(); qalSourcei(source, AL_LOOPING, false); alDieIfError(); - qalSourcef(source, AL_ROLLOFF_FACTOR, 0.019f); + qalSourcef(source, AL_ROLLOFF_FACTOR, 0.5f); alDieIfError(); qalSourcef(source, AL_GAIN, S_GetBaseVolume()); alDieIfError(); + // + // Added in OPM + // + qalSourcef(source, AL_REFERENCE_DISTANCE, fMinDist); + alDieIfError(); + qalSourcef(source, AL_MAX_DISTANCE, fMaxDist); + alDieIfError(); } /* From 9615fafc1e31bf7629cfee14967671329b2b47a0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 19:03:21 +0200 Subject: [PATCH 0527/2040] Fixes incorrect usage of DotProduct result in an integer --- code/client/snd_openal_new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index d641e456..051ed0ba 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2340,7 +2340,7 @@ static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const ve { float lscale, rscale; vec3_t source_vec; - int pan; + float pan; VectorSubtract(origin, listener_origin, source_vec); VectorNormalize(source_vec); From a0d3333ebbbeadb6ca2438e7ccee8a3e42eee1ec Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 1 Jul 2024 19:39:51 +0200 Subject: [PATCH 0528/2040] Fixes chan->bufferdata not being set to NULL when released --- code/client/snd_openal_new.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 051ed0ba..e675e49e 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -767,6 +767,7 @@ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) // Free the memory Hunk_FreeTempMemory(chan->bufferdata); + chan->bufferdata = NULL; qalSourcei(chan->source, AL_BUFFER, chan->buffer); alDieIfError(); @@ -2782,10 +2783,14 @@ void openal_channel::set_3d() // // Added in OPM // - qalSourcef(source, AL_REFERENCE_DISTANCE, fMinDist); - alDieIfError(); - qalSourcef(source, AL_MAX_DISTANCE, fMaxDist); - alDieIfError(); + if (fMinDist > 0) { + qalSourcef(source, AL_REFERENCE_DISTANCE, fMinDist); + alDieIfError(); + } + if (fMaxDist > 0) { + qalSourcef(source, AL_MAX_DISTANCE, fMaxDist); + alDieIfError(); + } } /* From d6571820fe30062c7d2c0608b626fa6d2dca4615 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 18:46:27 +0200 Subject: [PATCH 0529/2040] Fixes g_pVert/g_pTris being freed even when they are NULL --- code/renderer/tr_terrain.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/renderer/tr_terrain.c b/code/renderer/tr_terrain.c index e870b85e..97bba6c3 100644 --- a/code/renderer/tr_terrain.c +++ b/code/renderer/tr_terrain.c @@ -1351,10 +1351,14 @@ void R_TerrainRestart_f(void) return; } - ri.Free(g_pVert); - g_pVert = NULL; - ri.Free(g_pTris); - g_pTris = NULL; + if (g_pVert) { + ri.Free(g_pVert); + g_pVert = NULL; + } + if (g_pTris) { + ri.Free(g_pTris); + g_pTris = NULL; + } R_PreTessellateTerrain(); } From dca9709b122a32741a1df9edc72d96692f1208c5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 18:48:02 +0200 Subject: [PATCH 0530/2040] Fixes `MASK_PLAYERSOLID` incorrectly using `CONTENTS_WEAPONCLIP` instead of `CONTENTS_PLAYERCLIP` for invisible player collision This fixes #317, fixes #319 and fixes #320 where the player would bypass clip/playerclip --- code/fgame/bg_public.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/bg_public.h b/code/fgame/bg_public.h index af881c1e..6bf408ae 100644 --- a/code/fgame/bg_public.h +++ b/code/fgame/bg_public.h @@ -610,7 +610,7 @@ movement on the server game. (CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX | CONTENTS_FENCE) #define MASK_SAFESOLID (CONTENTS_BODY | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX) #define MASK_USABLE (CONTENTS_SOLID | CONTENTS_BBOX | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_BODY) -#define MASK_PLAYERSOLID (CONTENTS_TRIGGER | CONTENTS_BODY | CONTENTS_WEAPONCLIP | CONTENTS_FENCE | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX | CONTENTS_SOLID) +#define MASK_PLAYERSOLID (CONTENTS_TRIGGER | CONTENTS_BODY | CONTENTS_PLAYERCLIP | CONTENTS_FENCE | CONTENTS_UNKNOWN2 | CONTENTS_NOBOTCLIP | CONTENTS_BBOX | CONTENTS_SOLID) #define MASK_GUNTARGET \ (CONTENTS_SOLID | CONTENTS_LADDER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_CLAYPIDGEON | CONTENTS_BBOX \ | CONTENTS_NOBOTCLIP | CONTENTS_UNKNOWN2 | CONTENTS_UNKNOWN3 | CONTENTS_FENCE | CONTENTS_BODY | CONTENTS_CORPSE \ From 14927df9fa0630223eb5f825eb868b1af5ca0e7a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 19:03:27 +0200 Subject: [PATCH 0531/2040] Moves `MAX_SUBTITLES` to `q_shared.h| --- code/client/cl_uiview3d.cpp | 2 -- code/qcommon/q_shared.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/client/cl_uiview3d.cpp b/code/client/cl_uiview3d.cpp index 71a127b6..51efab8f 100644 --- a/code/client/cl_uiview3d.cpp +++ b/code/client/cl_uiview3d.cpp @@ -30,8 +30,6 @@ CLASS_DECLARATION(UIWidget, View3D, NULL) { {NULL, NULL } }; -#define MAX_SUBTITLES 4 - cvar_t *subs[MAX_SUBTITLES]; cvar_t *teams[MAX_SUBTITLES]; float fadeTime[MAX_SUBTITLES]; diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index ff792ed9..accd20d1 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -1661,6 +1661,8 @@ typedef enum #define MAX_CONFIGSTRINGS 2736 #define MAX_HUDDRAW_ELEMENTS 256 +#define MAX_SUBTITLES 4 + // these are the only configstrings that the system reserves, all the // other ones are strictly for servergame to clientgame communication #define CS_SERVERINFO 0 // an info string with all the serverinfo cvars From 040f8db0ef84f004eab571d6d96f288e150cd275 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 19:10:48 +0200 Subject: [PATCH 0532/2040] Fixes wrong sound volume and pitch --- code/fgame/actor.cpp | 2 +- code/fgame/entity.cpp | 82 ++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 61fd1a3a..a1e213c0 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -6878,7 +6878,7 @@ bool Actor::SoundSayAnim(const_str name, byte bLevelSayAnim) edict->tiki->a->name ); - Sound(Director.GetString(name), 0, 0, 0, NULL, 0, 1, 1, -1); + Sound(Director.GetString(name), CHAN_AUTO, 0, 0, 0, NULL, 0, 1, 1, -1); return true; } diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 547c3061..57af734b 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -3615,6 +3615,11 @@ void Entity::Sound( static cvar_t *g_subtitle = NULL; static bool _tmp = false; int num; + int aliaschannel; + float aliasvolume; + float aliasmin_dist; + float aliasmax_dist; + float aliaspitch; if (!_tmp) { g_subtitle = gi.Cvar_Get("g_subtitle", "0", CVAR_ARCHIVE); @@ -3643,6 +3648,12 @@ void Entity::Sound( if (name != NULL) { if (ret) { + aliaschannel = ret->channel; + aliasvolume = G_Random() * ret->volumeMod + ret->volume; + aliaspitch = G_Random() * ret->pitchMod + ret->pitch; + aliasmin_dist = ret->dist; + aliasmax_dist = ret->maxDist; + if (channel < 0) { channel = ret->channel; } @@ -3659,51 +3670,72 @@ void Entity::Sound( } } - if (argstype == 0) { - volume = G_Random() * ret->volumeMod + ret->volume; - pitch = G_Random() * ret->pitchMod + ret->pitch; - min_dist = ret->dist; - max_dist = ret->maxDist; - } else if (argstype == 1) { + switch (argstype) { + case 0: + volume = aliasvolume; + pitch = aliaspitch; + min_dist = aliasmin_dist; + max_dist = aliasmax_dist; + channel = aliaschannel; + break; + case 1: if (volume >= 0.0f) { - volume = G_Random() * ret->volumeMod + volume; + volume = volume * aliasvolume; } else { - volume = G_Random() * ret->volumeMod + volume; + volume = aliasvolume; } if (pitch >= 0.0f) { - pitch = G_Random() * ret->pitchMod + pitch; + pitch = pitch * aliaspitch; } else { - pitch = G_Random() * ret->pitchMod + ret->pitch; - } - } else { - if (volume <= 0.0f) { - volume = G_Random() * ret->volumeMod + ret->volume; - } - - if (pitch >= 0.0f) { - pitch = G_Random() * ret->pitchMod + pitch; - } else { - pitch = G_Random() * ret->pitchMod + ret->pitch; + pitch = aliaspitch; } if (min_dist < 0.0f) { - min_dist = ret->dist; + min_dist = aliasmin_dist; } if (max_dist < 0.0f) { - max_dist = ret->maxDist; + max_dist = aliasmax_dist; } + + if (channel < 0) { + channel = aliaschannel; + } + break; + default: + if (volume < 0.0) { + volume = aliasvolume; + } + if (pitch < 0.0) { + pitch = aliaspitch; + } + if (min_dist < 0.0) { + min_dist = aliasmin_dist; + } + if (max_dist < 0.0) { + max_dist = aliasmax_dist; + } + if (channel < 0) { + channel = aliaschannel; + } + break; } - if (g_gametype->integer == GT_SINGLE_PLAYER && (!checkSubtitle || g_subtitle->integer) && ret->subtitle) { + if ((!checkSubtitle || g_subtitle->integer) && ret->subtitle) { Entity *p = G_GetEntity(0); - if (g_subtitle->integer == 2 || max_dist * max_dist > DistanceSquared(org, p->edict->s.origin)) { + if (g_subtitle->integer == 2 || Square(max_dist) > DistanceSquared(org, p->edict->s.origin)) { cvar_t *curSubtitle = gi.Cvar_Get("curSubtitle", "0", 0); + int curSub; gi.cvar_set(va("subtitle%d", curSubtitle->integer), va("%s", ret->subtitle)); - gi.cvar_set("curSubtitle", va("%d", curSubtitle->integer + 1)); + curSub = curSubtitle->integer + 1; + if (curSubtitle->integer + 1 < 0) { + curSub = curSubtitle->integer + MAX_SUBTITLES; + } + + gi.cvar_set("curSubtitle", va("%d", (curSubtitle->integer + 1) - MAX_SUBTITLES * (curSub >> 2))); } } From 02e2e92d361b29a053242fe5126f0ae480d7dc15 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 19:30:29 +0200 Subject: [PATCH 0533/2040] Uses linear sound distance model --- code/client/snd_openal_new.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index e675e49e..49d07659 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2780,6 +2780,8 @@ void openal_channel::set_3d() alDieIfError(); qalSourcef(source, AL_GAIN, S_GetBaseVolume()); alDieIfError(); + qalSourcef(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + alDieIfError(); // // Added in OPM // From d5f435ee90fb8ac6901e975fd2ac2d96b4f7c099 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:01:01 +0200 Subject: [PATCH 0534/2040] Makes loops work as they should --- code/client/snd_openal_new.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 49d07659..8cde8cea 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -3137,6 +3137,11 @@ void openal_channel::set_sample_loop_count(S32 count) alDieIfError(); } } + + if (count == 0) { + qalSourcei(source, AL_LOOPING, true); + alDieIfError(); + } } /* From 543c00037a3b0ab40d1bfeb5b6d2a76946a9d997 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:10:54 +0200 Subject: [PATCH 0535/2040] Implements sample playback rate --- code/client/snd_openal_new.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 8cde8cea..acfaccf5 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -3022,7 +3022,12 @@ void openal_channel::set_sample_pan(S32 pan) {} openal_channel::set_sample_playback_rate ============== */ -void openal_channel::set_sample_playback_rate(S32 rate) {} +void openal_channel::set_sample_playback_rate(S32 rate) { + // Fixed in OPM + // Set the pitch in OpenAL + qalSourcef(source, AL_PITCH, rate / (float)iBaseRate); + alDieIfError(); +} /* ============== @@ -3031,7 +3036,25 @@ openal_channel::sample_playback_rate */ S32 openal_channel::sample_playback_rate() { - return 22050; + float pitch = 1; + ALint freq = 0; + + // Fixed in OPM + // The sample rate varies according to the pitch + qalGetSourcef(source, AL_PITCH, &pitch); + alDieIfError(); + + if (buffer) { + qalGetBufferi(buffer, AL_FREQUENCY, &freq); + alDieIfError(); + } else if (pSfx) { + qalGetBufferi(pSfx->buffer, AL_FREQUENCY, &freq); + alDieIfError(); + } else { + freq = 22050; + } + + return freq * pitch; } /* From 5816391e9bda01476bdeb42557d42edddc73ae8b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:25:08 +0200 Subject: [PATCH 0536/2040] Fixes loopsound not properly working (not playing, or not being 3D) --- code/client/snd_openal_new.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index acfaccf5..a8c65c5a 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1559,12 +1559,13 @@ void S_OPENAL_AddLoopingSound( } pLoopSound = &openal.loop_sounds[iFreeLoopSound]; - pLoopSound->vOrigin[0] = -vOrigin[0]; - pLoopSound->vOrigin[1] = vOrigin[2]; - pLoopSound->vOrigin[2] = -vOrigin[1]; + //pLoopSound->vOrigin[0] = -vOrigin[0]; + //pLoopSound->vOrigin[1] = vOrigin[2]; + //pLoopSound->vOrigin[2] = -vOrigin[1]; //pLoopSound->vVelocity[0] = -vVelocity[0] / 52.49f / 500.f; //pLoopSound->vVelocity[1] = vVelocity[2] / 52.49f / 500.f; //pLoopSound->vVelocity[2] = -vVelocity[1] / 52.49f / 500.f; + VectorCopy(vOrigin, pLoopSound->vOrigin); VectorCopy(vVelocity, pLoopSound->vVelocity); pLoopSound->pSfx = pSfx; pLoopSound->bInUse = true; @@ -1823,8 +1824,8 @@ static int S_OPENAL_Start3DLoopSound( pLoopSound->vVelocity[0] / 52.49f, vLoopOrigin[1] / 52.49f, pLoopSound->vVelocity[2] / 52.49f ); */ - pChan3D->set_position(vLoopOrigin[0], pLoopSound->vVelocity[1], vLoopOrigin[2]); - pChan3D->set_velocity(pLoopSound->vVelocity[0], vLoopOrigin[1], pLoopSound->vVelocity[2]); + pChan3D->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]); + pChan3D->set_velocity(pLoopSound->vVelocity[0], pLoopSound->vVelocity[1], pLoopSound->vVelocity[2]); pChan3D->pSfx = pLoopSound->pSfx; pChan3D->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; pChan3D->iBaseRate = pChan3D->sample_playback_rate(); @@ -1876,7 +1877,7 @@ static bool S_OPENAL_UpdateLoopSound( pChannel->iStartTime = cl.serverTime; - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_STREAMED | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) // || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { vec3_t vOrigin; int iPan; @@ -1944,6 +1945,7 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) vec3_t alvec; qalGetListenerfv(AL_POSITION, alvec); + VectorCopy(alvec, vListenerOrigin); //VectorScale(alvec, 52.49f, vListenerOrigin); for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) { @@ -2094,7 +2096,7 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name); } - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET | SFX_FLAG_STREAMED | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) //|| pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { iChannel = S_OPENAL_Start2DLoopSound( pLoopSound, fVolume, S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, vLoopOrigin From 5317b8424fd28f25ece15785318fd6bedea65da9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 22:16:13 +0200 Subject: [PATCH 0537/2040] Prevents the player from walking This fixes #275 --- code/fgame/player.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index b5e17d3f..86b41dd3 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -4154,6 +4154,10 @@ void Player::VehicleMove(usercmd_t *ucmd) if (m_pVehicle->Drive(current_ucmd)) { client->ps.commandTime = ucmd->serverTime; + // Added in OPM + // The player can't walk while attached to a vehicle + client->ps.groundEntityNum = ENTITYNUM_NONE; + client->ps.walking = false; } else { ClientMove(ucmd); } @@ -4186,10 +4190,14 @@ void Player::TurretMove(usercmd_t *ucmd) client->ps.gravity = gravity * sv_gravity->value; - if (!m_pTurret->IsSubclassOfTurretGun() || !m_pTurret->UserAim(current_ucmd)) { - ClientMove(ucmd); - } else { + if (m_pTurret->IsSubclassOfTurretGun() && m_pTurret->UserAim(current_ucmd)) { client->ps.commandTime = ucmd->serverTime; + // Added in OPM + // The player can't walk while attached to a turret + client->ps.groundEntityNum = ENTITYNUM_NONE; + client->ps.walking = false; + } else { + ClientMove(ucmd); } } From 551fccb76140643ebdfcc1d6e03304b3e6192754 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 2 Jul 2024 22:47:41 +0200 Subject: [PATCH 0538/2040] Fixes wrong handle being compared for uniqueness This should fix invisible models (fixes #322) --- code/cgame/cg_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index fe29dfcb..57e855dc 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -253,13 +253,11 @@ CG_IsHandleUnique Check if the model handle is unique ================ */ -static qboolean CG_IsHandleUnique(int num) { - qhandle_t handle; +static qboolean CG_IsHandleUnique(qhandle_t handle) { int i; int numRef; numRef = 0; - handle = cgs.model_draw[num]; for (i = 0; i < MAX_MODELS; i++) { if (cgs.model_draw[i] == handle) { numRef++; From d56498e622da05ec4cc0af7ec78ba71dcf425ad3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:04:03 +0200 Subject: [PATCH 0539/2040] Adds CHANNEL_NONE case statement even if there is nothing to do --- code/skeletor/skeletor_loadanimation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index ab0c3b31..46f6a3d2 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -584,6 +584,9 @@ void ReadEncodedFramesEx(msg_t *msg, skelAnimDataGameHeader_t *enAnim) pFrame->pChannelData[0] = MSG_ReadFloat(msg); } break; + case CHANNEL_NONE: + // Nothing to do + break; } } } From eac8580f64dfa8691b19bebb1f3548b38d03b90e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:54:41 +0200 Subject: [PATCH 0540/2040] Add libmad 0.16.4 This new version introduces patches against crashes and exploits. CMake is also fully supported and platforms are properly detected so architecture specific optimizations are used. To use it, USE_SOUND_NEW must be non-zero when configuring the project --- code/client/CMakeLists.txt | 12 +- code/client/snd_codec_mp3.c | 6 +- code/libmad/.github/workflows/build.yml | 44 + code/libmad/.gitignore | 1 + code/libmad/CHANGES | 360 + code/libmad/CMakeLists.txt | 240 + code/libmad/COPYING | 340 + code/libmad/COPYRIGHT | 21 + code/libmad/CREDITS | 116 + code/libmad/D.dat | 607 ++ code/libmad/README.md | 178 + code/libmad/TODO | 69 + code/libmad/bit.c | 236 + code/libmad/decoder.c | 589 ++ code/libmad/fixed.c | 77 + code/libmad/frame.c | 510 ++ code/libmad/global.h | 58 + code/libmad/huffman.c | 3105 ++++++++ code/libmad/huffman.h | 66 + code/libmad/imdct_l_arm.S | 1000 +++ code/libmad/imdct_s.dat | 62 + code/libmad/layer12.c | 621 ++ code/libmad/layer12.h | 30 + code/libmad/layer3.c | 2779 +++++++ code/libmad/layer3.h | 29 + code/libmad/mad.h.in | 956 +++ code/libmad/minimad.c | 222 + code/libmad/packaging/mad.pc.in | 10 + code/libmad/packaging/madConfig.cmake.in | 5 + code/libmad/qc_table.dat | 77 + code/libmad/rq_table.dat | 8747 ++++++++++++++++++++++ code/libmad/sf_table.dat | 106 + code/libmad/stream.c | 156 + code/libmad/synth.c | 851 +++ code/libmad/timer.c | 481 ++ code/libmad/version.c | 87 + 36 files changed, 22850 insertions(+), 4 deletions(-) create mode 100644 code/libmad/.github/workflows/build.yml create mode 100644 code/libmad/.gitignore create mode 100644 code/libmad/CHANGES create mode 100644 code/libmad/CMakeLists.txt create mode 100644 code/libmad/COPYING create mode 100644 code/libmad/COPYRIGHT create mode 100644 code/libmad/CREDITS create mode 100644 code/libmad/D.dat create mode 100644 code/libmad/README.md create mode 100644 code/libmad/TODO create mode 100644 code/libmad/bit.c create mode 100644 code/libmad/decoder.c create mode 100644 code/libmad/fixed.c create mode 100644 code/libmad/frame.c create mode 100644 code/libmad/global.h create mode 100644 code/libmad/huffman.c create mode 100644 code/libmad/huffman.h create mode 100644 code/libmad/imdct_l_arm.S create mode 100644 code/libmad/imdct_s.dat create mode 100644 code/libmad/layer12.c create mode 100644 code/libmad/layer12.h create mode 100644 code/libmad/layer3.c create mode 100644 code/libmad/layer3.h create mode 100644 code/libmad/mad.h.in create mode 100644 code/libmad/minimad.c create mode 100644 code/libmad/packaging/mad.pc.in create mode 100644 code/libmad/packaging/madConfig.cmake.in create mode 100644 code/libmad/qc_table.dat create mode 100644 code/libmad/rq_table.dat create mode 100644 code/libmad/sf_table.dat create mode 100644 code/libmad/stream.c create mode 100644 code/libmad/synth.c create mode 100644 code/libmad/timer.c create mode 100644 code/libmad/version.c diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index c1761c24..77a5f515 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -34,6 +34,15 @@ if (USE_SOUND_NEW) list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.c$") file(GLOB_RECURSE SOURCES_CLIENT_SND "./snd_*_new.c*" "./snd_codec*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) + + set(OLD_VALUE ${BUILD_SHARED_LIBS}) + set(BUILD_SHARED_LIBS OFF) + add_subdirectory("../libmad" "./libmad") + set(BUILD_SHARED_LIBS ${OLD_VALUE}) + target_link_libraries(omohclient INTERFACE mad) +else() + add_subdirectory("../libmad-0.15.1b" "./libmad") + target_link_libraries(omohclient INTERFACE libmad) endif() if (USE_OPENAL) @@ -47,6 +56,3 @@ if (USE_OPENAL) endif() target_sources(omohclient INTERFACE ${SOURCES_CLIENT} ${SOURCES_UILIB}) - -add_subdirectory("../libmad-0.15.1b" "./libmad") -target_link_libraries(omohclient INTERFACE libmad) \ No newline at end of file diff --git a/code/client/snd_codec_mp3.c b/code/client/snd_codec_mp3.c index 80a02326..06d1f1c7 100644 --- a/code/client/snd_codec_mp3.c +++ b/code/client/snd_codec_mp3.c @@ -31,7 +31,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_codec.h" // includes for the MP3 codec -#include "../libmad-0.15.1b/synth.h" +#if USE_SOUND_NEW +# include "mad.h" +#else +# include "../libmad-0.15.1b/synth.h" +#endif #define MP3_SAMPLE_WIDTH 2 #define MP3_PCMSAMPLES_PERSLICE 32 diff --git a/code/libmad/.github/workflows/build.yml b/code/libmad/.github/workflows/build.yml new file mode 100644 index 00000000..ba50e409 --- /dev/null +++ b/code/libmad/.github/workflows/build.yml @@ -0,0 +1,44 @@ +name: build + +on: + push: + pull_request: + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - name: Ubuntu + os: ubuntu-latest + install_dir: ~/libmad + cmake_extras: -DCMAKE_BUILD_TYPE=RelWithDebInfo + - name: macOS + os: macos-latest + install_dir: ~/libmad + cmake_extras: -DCMAKE_BUILD_TYPE=RelWithDebInfo + - name: Windows + os: windows-latest + install_dir: C:\libmad + cmake_config: --config RelWithDebInfo + + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + steps: + - name: Check out Git repository + uses: actions/checkout@v2 + - name: Configure + run: cmake -DCMAKE_INSTALL_PREFIX=${{ matrix.install_dir }} ${{ matrix.cmake_extras }} -S . -B build + - name: Build + run: cmake --build build ${{ matrix.cmake_config }} + env: + CMAKE_BUILD_PARALLEL_LEVEL: 2 + - name: Install + run: cmake --install . ${{ matrix.cmake_config }} + working-directory: build + - name: Upload Build Artifact + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.name }} libmad build + path: ${{ matrix.install_dir }} diff --git a/code/libmad/.gitignore b/code/libmad/.gitignore new file mode 100644 index 00000000..378eac25 --- /dev/null +++ b/code/libmad/.gitignore @@ -0,0 +1 @@ +build diff --git a/code/libmad/CHANGES b/code/libmad/CHANGES new file mode 100644 index 00000000..45a94436 --- /dev/null +++ b/code/libmad/CHANGES @@ -0,0 +1,360 @@ + + libmad - MPEG audio decoder library + Copyright (C) 2000-2004 Underbit Technologies, Inc. + + $Id: CHANGES,v 1.14 2004/02/17 02:02:03 rob Exp $ + +=============================================================================== + +Verison 0.16.4 + * Fix compatibility with libmad 0.15.1b + +Version 0.16.3 + * Disable assembly optimizations for all 64 bit CPU architectures; they are + only for 32 and 16 bit architectures + * Fix CPU architecture detection for PowerPC + +Version 0.16.2 + * Fix building assembly file on ARM + * Fix pkgconfig file when CMAKE_INSTALL_{INCLUDE,LIB}DIR are absolute paths + +Version 0.16.1 + * Fix generation of mad.h broken by move to CMake + * Add CMake options for CPU architecture-specific optimizations + +Version 0.16.0 + * Add CMake build system + * Remove autotools build system + * Add pkgconfig and CMake config files + * Apply patches from Debian and Fedora + +Version 0.15.1 (beta) + + * Updated to autoconf 2.59, automake 1.8.2, libtool 1.5.2. + + * Replaced Layer III IMDCT routine with one based on a faster algorithm, + improving both speed and accuracy. + + * Improved portability of the Huffman table initialization. + + * Fixed a problem that could result in an assertion failure in layer3.c + due to an invalid Layer III free format bitrate. + + * Improved the robustness of Layer II bitrate/mode combinations, and added + a new MAD_ERROR_BADMODE error enum. The allowability of low-bitrate + stereo streams is influenced by the --enable-strict-iso option to + `configure'. + +Version 0.15.0 (beta) + + * Updated to autoconf 2.57, automake 1.7.5, libtool 1.4.3. + + * Added new mad_f_div() API routine. + + * Added a 64th entry to the Layer I/Layer II scalefactor table, for better + compatibility with existing streams. The --enable-strict-iso option to + `configure' can be used to disable use of this entry. + + * Modified the header decoding routine to allow the reserved emphasis + value, for better compatibility with existing streams. The + --enable-strict-iso option to `configure' can be used to restore the + previous behavior of reporting this value as an error. + + * Added new MAD_EMPHASIS_RESERVED enumeration constant. + + * Fixed a bug in the ARM version of mad_f_scale64() discovered by Andre + McCurdy. + + * Rewrote PowerPC assembly for minor gains. + + * Modified mad_timer_fraction() to avoid the possibility of division by + zero when 0 is passed as the second argument. + + * Fixed a non-fatal problem caused by attempting to designate ancillary + bits in Layer III after a decoding error. + + * Changed to build a shared library by default. + + * Changed to use native Cygwin build by default; give --host=mingw32 to + `configure' to use MinGW (and avoid a dependency on the Cygwin DLL). + +Version 0.14.2 (beta) + + * Changed Cygwin builds to use MinGW; resulting Win32 executables no + longer have a dependency on Cygwin DLLs. + + * Added a new mad_stream_errorstr() API function to libmad for retrieving + a string description of the current error condition. + +Version 0.14.1 (beta) + + * Updated config.guess and config.sub to latest upstream versions. + + * Enabled libtool versioning rather than release numbering. + + * Improved the documentation in minimad.c. + + * Several other small fixes. + +Version 0.14.0 (beta) + + * Added a 64-bit FPM negation operation to improve performance of subband + synthesis on some platforms. + + * Improved MSVC++ portability and added MSVC++ project files. + + * Added rounding to Layer III requantization for slightly better accuracy. + +Version 0.13.0 (beta) + + * Ancillary data is now properly extracted from Layer III streams. + + * Rewrote the Layer III joint stereo decoding routine to correct a major + MPEG-2 problem and a minor MPEG-1 problem decoding intensity stereo. + + * Eliminated the dependency on sign-extending right shifts for Layer I and + Layer II. + + * Renamed `private' field to `private_bits' for better C++ compatibility. + + * Gratuitously renamed `sfreq' field to `samplerate' and + MAD_ERROR_BADSAMPLEFREQ constant to MAD_ERROR_BADSAMPLERATE. + + * Added `samplerate' and `channels' fields to synth.pcm struct to allow + these to be different from the decoded frame, and for simpler access. + + * Added new mad_stream_options() and mad_decoder_options() API entries for + special runtime decoding options. + + * Added new MAD_OPTION_IGNORECRC and MAD_OPTION_HALFSAMPLERATE options. + + * Added new MAD_FLAG_FREEFORMAT indicator flag. + + * Fixed some bugs in the async decoder. + + * Added a new mad_timer_multiply() API routine. + + * Eliminated `+' from asm constraints under Intel for better compatibility + with some compilers. + + * Fixed a PIC-related problem in imdct_l_arm.S. + + * Eliminated a static variable to make libmad thread-safe. + +Version 0.12.5 (beta) + + * Modified Layer III requantization to occur during Huffman decoding for + significant performance gains. + + * Optimized short block IMDCT by eliminating redundant calculations. + + * Made several other Layer III performance improvements; added + ASO_INTERLEAVE1, ASO_INTERLEAVE2, and ASO_ZEROCHECK + architecture-specific options for best performance on various + architectures. + + * Optimized synthesis DCT to store result values as soon as they are + calculated. + +Version 0.12.4 (beta) + + * New PowerPC fixed-point assembly courtesy of David Blythe. + + * Reorganized fixed-point assembly routines for easier maintenance and + better performance. + + * Improved performance of subband synthesis through better indexing and + fewer local variables. + + * Added alias reduction for the lower two subbands of mixed short blocks, + per a report of ambiguity with ISO/IEC 11172-3 and for uniformity with + most other implementations. Also improved alias reduction performance + using multiply/accumulate. + + * Added --enable-strict-iso option to `configure' to override best + accepted practices such as the alias reduction for mixed short blocks. + + * Improved performance of Layer III IMDCT by using longer + multiply/accumulate runs where possible. + +Version 0.12.3 (beta) + + * Added MPEG 2.5 support. + + * Added preliminary support for parameterizing the binary point position + in the fixed-point representation. + + * Added multiply/accumulate optimization to the Layer III IMDCT for long + blocks. + + * Fixed a bug in the handling of Layer III mixed_block_flag. + + * Fixed a configure problem when multiple -O CFLAGS are present. + +Version 0.12.2 (beta) + + * Rearranged the synthesis polyphase filterbank memory vector for better + locality of reference, and rewrote mad_synth_frame() to accommodate, + resulting in improved performance. + + * Discovered a combination of compiler optimization flags that further + improve performance. + + * Changed some array references in layer3.c to pointer derefs. + +Version 0.12.1 (beta) + + * Resolved the intensity + MS joint stereo issue (a simple bug). + OPT_ISKLUGE is no longer considered to be a kluge. + + * Fixed another, hopefully last main_data memory bug. + + * Split part of struct mad_frame into struct mad_header for convenience + and size. + +Version 0.12.0 (alpha) + + * Changed the build environment to use automake and libtool. A libmad + shared library can now be built using the --enable-shared option to + `configure'. + + * Added another callback to MAD's high-level decoder API after the frame + header has been read but before the frame's audio data is decoded. + + * Streamlined header processing so that mad_frame_decode() can be called + with or without having already called mad_frame_header(). + + * Fixed some other header reading miscellany, including CRC handling and + free bitrate detection, and frame length verification with free + bitrates. + + * Fixed a problem with Layer III free bitrates > 320 kbps. The main_data + buffer size should now be large enough to handle any size frame, by + virtue of the maximum possible part2_3_length. + + * Further developed the async API; arbitrary messages can now be passed to + the subsidiary decoding process. + + * Streamlined timer.c and extended its interface. It now has support for + video frame/field lengths, including output support for drop-frame + encoding. + + * Replaced many constant integer preprocessor defines with enums. + +Version 0.11.4 (beta) + + * Fixed free format bitrate discovery. + + * Changed the timer implementation and extended its interface. + + * Integrated Nicolas Pitre's patch for pre-shifting at compile-time and + for better multiply/accumulate code output. + + * Applied Simon Burge's patch to imdct_l_arm.S for a.out compatibility. + + * Added -mtune=strongarm for all ARM targets. + +Version 0.11.3 (beta) + + * Added new --enable-speed and --enable-accuracy options for `configure' + to automatically select appropriate SSO/ASO options, et al. + + * Modified subband synthesis to use multiply/accumulate optimization (if + available) for better speed and/or accuracy. + + * Incorporated Andre McCurdy's changes for further rounding optimizations + in the rest of his code. + +Version 0.11.2 (beta) + + * Incorporated Nicolas Pitre's ARM assembly and parameterized scaling + changes. + + * Incorporated Andre McCurdy's ARM assembly optimization (used only if + --enable-aso is given to `configure' to enable architecture-specific + optimizations.) + + * Reduced FPM_INTEL assembly to two instructions. + + * Fixed accuracy problems with certain FPM modes in synth.c. + + * Improved the accuracy of FPM_APPROX. + + * Improved the accuracy of SSO. + + * Improved sync discovery by checking for a sync word in the following + frame. + + * Minor code clean-up. + + * Added experimental rules for generating a libmad.so shared library. + +Version 0.11.1 (beta) + + * Moved libmad code into a separate directory. + + * Changed SSO to be disabled by default, as output accuracy is deemed to + be more important than speed in the general case. + + * Fixed a bug in Layer III sanity checking that could cause a crash on + certain random data input. + + * Extended the Layer III requantization table from 8191 to 8206 as some + encoders are known to use these values, even though ISO/IEC 11172-3 + suggests the maximum should be 8191. + +Version 0.11.0 (beta) + + * Implemented MPEG-2 extension to Lower Sampling Frequencies. + + * Improved Layer III performance by avoiding IMDCT calculation when all + input samples are zero. + + * Significantly reduced size of Layer II tables. + +Version 0.10.3 (beta) + + * Improved SSO output quality. + + * Made portable to cygwin. + + * Localized memory references in III_huffdecode() for better performance. + +Version 0.10.2 (beta) + + * Rewrote Layer III long block 36-point IMDCT routine for better + performance. + + * Improved subband synthesis fixed-point games somewhat. + +Version 0.10.1 (beta) + + * Added a subband synthesis optimization (SSO) which involves modifying + the fixed-point multiplication method during windowing. This produces + subtle differences in the output but improves performance greatly. + + * Added I_STEREO and MS_STEREO flags to frame struct. + + * Eliminated privately-used CRCFAILED flag. + + * Fixed a bug where Layer III decoding could crash on some badly-formatted + (e.g. non-MPEG) bitstreams. + + * Miscellaneous code clean-up. + +Version 0.10.0 (beta) + + * Added SPARC fixed-point math support. + + * Revamped libmad API for better high- and low-level support. + + * Documented more of the code. + + * Changed sync semantics such that new stream buffers are assumed to be + sync-aligned. + + * Changed Layer III to dynamically allocate static memory so as not to + waste it (about 6.4K) when only decoding Layer I or Layer II. + +=============================================================================== + diff --git a/code/libmad/CMakeLists.txt b/code/libmad/CMakeLists.txt new file mode 100644 index 00000000..6524ce5d --- /dev/null +++ b/code/libmad/CMakeLists.txt @@ -0,0 +1,240 @@ +cmake_minimum_required(VERSION 3.1.0) +project(mad VERSION 0.16.4) + +option(BUILD_SHARED_LIBS "Build dynamic library" ON) + +# The library SOVERSION. This is set to 0 for backward compatibility. +# The general policy is that minor versions of the library (e.g., 0.16.1, +# 0.16.2) don't constitute a major ABI breakage. Major versions (e.g., 0.17, +# 0.18) do. +set(LIBRARY_SOVERSION 0) + +include(GNUInstallDirs) +include(CheckTypeSize) + +# +# Build +# + +add_library(mad + bit.c + decoder.c + fixed.c + frame.c + huffman.c + layer12.c + layer3.c + stream.c + synth.c + timer.c + version.c +) +target_include_directories(mad PUBLIC + $ + $ + $ +) + +if(WIN32 AND BUILD_SHARED_LIBS) + set_target_properties(mad PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + +set_target_properties(mad PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${LIBRARY_SOVERSION} +) + +# +# Compile definitions +# + +option(OPTIMIZE "Optimize for SPEED (default) or ACCURACY" SPEED) +if(OPTIMIZE STREQUAL "SPEED") + message(STATUS "Optimizing for speed over accuracy.") + target_compile_definitions(mad PRIVATE OPT_SPEED) +else() + message(STATUS "Optimizing for accuracy over speed.") + target_compile_definitions(mad PRIVATE OPT_ACCURACY) +endif() + +option(ASO "Enable CPU Architecture Specific Optimizations (x86, ARM, and MIPS only)" ON) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + message(STATUS "Using 64 bit fixed point math") + option(FPM_64BIT "64 bit fixed point math" ON) +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86" OR "i386") + message(STATUS "Using x86 fixed point math") + option (FPM_INTEL "x86 fixed point math" ON) + if(ASO) + target_compile_definitions(mad PRIVATE ASO_ZEROCHECK) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ".*(arm|ARM).*") + message(STATUS "Using ARM fixed point math") + option (FPM_ARM "ARM fixed point math" ON) + if(ASO) + enable_language(ASM) + target_compile_definitions(mad PRIVATE ASO_INTERLEAVE1 ASO_IMDCT) + target_sources(mad PRIVATE imdct_l_arm.S) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ".*(mips|MIPS).*") + message(STATUS "Using MIPS fixed point math") + option(FPM_MIPS "MIPS fixed point math" ON) + if(ASO) + target_compile_definitions(mad PRIVATE ASO_INTERLEAVE2 ASO_ZEROCHECK) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ".*(sparc|SPARC).*") + message(STATUS "Using SPARC fixed point math") + option(FPM_SPARC "SPARC fixed point math" ON) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ".(ppc|PPC|powerpc).*") + message(STATUS "Using PowerPC fixed point math") + option(FPM_PPC "PowerPC fixed point math" ON) +else() + message(WARNING "Target CPU architecture not detected. Fixed-point math will yield limited accuracy.") + option(FPM_DEFAULT "Generic fixed-point math" ON) +endif() + + +check_type_size(int SIZEOF_INT BUILTIN_TYPES_ONLY LANGUAGE C) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mad.h.in ${CMAKE_CURRENT_BINARY_DIR}/mad.h @ONLY) + +include(CheckIncludeFile) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +if(HAVE_SYS_TYPES_H) + target_compile_definitions(mad PRIVATE HAVE_SYS_TYPES_H) +endif() + +check_include_file(sys/wait.h HAVE_SYS_WAIT_H) +if(HAVE_SYS_WAIT_H) + target_compile_definitions(mad PRIVATE HAVE_SYS_WAIT_H) +endif() + +check_include_file(sys/mman.h HAVE_SYS_MMAN_H) +if(HAVE_SYS_MMAN_H) + target_compile_definitions(mad PRIVATE HAVE_SYS_MMAN_H) +endif() + +check_include_file(sys/stat.h HAVE_SYS_STAT_H) +if(HAVE_SYS_STAT_H) + target_compile_definitions(mad PRIVATE HAVE_SYS_STAT_H) +endif() + +check_include_file(unistd.h HAVE_UNISTD_H) +if(HAVE_UNISTD_H) + target_compile_definitions(mad PRIVATE HAVE_UNISTD_H) +endif() + +check_include_file(assert.h HAVE_ASSERT_H) +if(HAVE_ASSERT_H) + target_compile_definitions(mad PRIVATE HAVE_ASSERT_H) +endif() + +check_include_file(fcntl.h HAVE_FCNTL_H) +if(HAVE_FCNTL_H) + target_compile_definitions(mad PRIVATE HAVE_FCNTL_H) +endif() + +check_include_file(limits.h HAVE_LIMITS_H) +if(HAVE_LIMITS_H) + target_compile_definitions(mad PRIVATE HAVE_LIMITS_H) +endif() + +include(CheckFunctionExists) +check_function_exists(ftruncate HAVE_FTRUNCATE) +if(HAVE_FTRUNCATE) + target_compile_definitions(mad PRIVATE HAVE_FTRUNCATE) +endif() + +check_function_exists(pipe HAVE_PIPE) +if(HAVE_PIPE) + target_compile_definitions(mad PRIVATE HAVE_PIPE) +endif() + +check_function_exists(fork HAVE_FORK) +if(HAVE_FORK) + target_compile_definitions(mad PRIVATE HAVE_FORK) +endif() + +check_function_exists(waitpid HAVE_WAITPID) +if(HAVE_WAITPID) + target_compile_definitions(mad PRIVATE HAVE_WAITPID) +endif() + +option(MADD_ASM "Enable if your MIPS CPU supports a 2-operand MADD instruction." OFF) +if(MADD_ASM) + target_compile_definitions(mad PRIVATE HAVE_MADD_ASM) +endif() + +option(MADD16_ASM "Enable if your MIPS CPU supports a 2-operand MADD16 instruction." OFF) +if(MADD16_ASM) + target_compile_definitions(mad PRIVATE HAVE_MADD_ASM) +endif() + +# +# Example application +# + +include(CMakeDependentOption) +cmake_dependent_option(EXAMPLE "Build example executable" ON "HAVE_UNISTD_H;HAVE_SYS_STAT_H;HAVE_SYS_MMAN_H" OFF) +if(EXAMPLE) + add_executable(mad_example minimad.c) + target_link_libraries(mad_example PRIVATE mad) +endif() + +# +# Installation +# + +include(CMakePackageConfigHelpers) + +# Library files +install(TARGETS mad + EXPORT madTargets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +# Header files +install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/mad.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +# pkgconfig +if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + set(PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}") +else() + set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}") +endif() +if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") +else() + set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") +endif() +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/mad.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/packaging/mad.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/packaging/mad.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + +# CMake config +set(MAD_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/mad") +install( + EXPORT madTargets + FILE madTargets.cmake + NAMESPACE mad:: + DESTINATION "${MAD_INSTALL_CMAKEDIR}" +) +configure_package_config_file(packaging/madConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/packaging/madConfig.cmake" + INSTALL_DESTINATION "${MAD_INSTALL_CMAKEDIR}" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/packaging/madConfigVersion.cmake" + VERSION "${PROJECT_VERSION}" + COMPATIBILITY SameMajorVersion +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/packaging/madConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/packaging/madConfigVersion.cmake" + DESTINATION "${MAD_INSTALL_CMAKEDIR}" +) diff --git a/code/libmad/COPYING b/code/libmad/COPYING new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/code/libmad/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/code/libmad/COPYRIGHT b/code/libmad/COPYRIGHT new file mode 100644 index 00000000..ed91d2ba --- /dev/null +++ b/code/libmad/COPYRIGHT @@ -0,0 +1,21 @@ + + libmad - MPEG audio decoder library + Copyright (C) 2000-2004 Underbit Technologies, 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + If you would like to negotiate alternate licensing terms, you may do + so by contacting: Underbit Technologies, Inc. + diff --git a/code/libmad/CREDITS b/code/libmad/CREDITS new file mode 100644 index 00000000..72ec72ed --- /dev/null +++ b/code/libmad/CREDITS @@ -0,0 +1,116 @@ + + libmad - MPEG audio decoder library + Copyright (C) 2000-2004 Underbit Technologies, Inc. + + $Id: CREDITS,v 1.5 2004/02/17 02:02:03 rob Exp $ + +=============================================================================== + +AUTHOR + + Except where otherwise noted, all code was authored by: + + Robert Leslie + +CONTRIBUTORS + + Significant contributions have been incorporated with thanks to: + + Anonymous + 2002/03/15: frame.c + - Reported problem with use of reserved emphasis value. + 2003/08/31: layer12.c + - Suggested support for certain disallowed bitrate/mode + combinations. + + Niek Albers + 2003/04/21: layer3.c + - Reported runtime uninitialized use of `ptr' in designating + ancillary bits after a decoding error. + + Christian Biere + 2003/02/01: frame.c + - Reported assertion failure in layer3.c due to an + invalid/unsupported Layer III free format bitrate. + + David Blythe + 2001/01/30: fixed.h + - Provided initial PowerPC fixed-point assembly. + + Simon Burge + 2000/09/20: imdct_l_arm.S + - Suggested patch for a.out compatibility. + + Brian Cameron + 2003/07/02: huffman.c + - Suggested changes for improved portability. + + Joshua Haberman + 2001/08/10: decoder.c, huffman.c + - Suggested portability fixes. + + Timothy King + 2002/05/04: sf_table.dat, layer12.c + - Reported problem with use of (missing) scalefactor index 63. + + Felix von Leitner + 2003/01/21: fixed.h + - Suggested Intel scaling alternative for possible speedup. + + Andre McCurdy + 2000/08/10: imdct_l_arm.S + - ARM optimized assembly replacement for III_imdct_l(). + 2000/09/15: imdct_l_arm.S + - Applied Nicolas Pitre's rounding optimisation in all remaining + places. + 2001/02/10: layer3.c + - Inspiration for Huffman decoding and requantization rewrite, and + other miscellany. + 2001/03/24: imdct_l_arm.S + - Corrected PIC unsafe code. + 2002/02/16: fixed.h + - Discovered bug in ARM version of mad_f_scale64(). + + Haruhiko OGASAWARA + 2001/01/28: layer3.c + - Reported discrepancy in alias reduction for mixed short blocks. + + Brett Paterson + 2001/10/28: global.h + - Reported missing et al. under MS Embedded Visual C. + + Sean 'Shaleh' Perry + 2000/04/04: fixed.h + - Suggested use of size-dependent typedefs. + 2001/10/22: config.guess, config.sub + - Keep up to date for proper Debian packaging. + + Bertrand Petit + 2001/11/05: synth.h + - Suggested PCM channel enumeration constants. + 2001/11/05: stream.h + - Suggested MAD_ERROR_NONE enumeration constant. + 2001/11/05: stream.c + - Suggested mad_stream_errorstr() function. + + Nicolas Pitre + 2000/09/09: fixed.h + - Parameterized all scaling for correct use of all multiplication + methods within mad_synth_frame(). + - Rewrote the FPM_ARM version of mad_f_mul() so we have 64-bit + multiplication result, rounding and scaling with 3 instructions. + 2000/09/09: imdct_l_arm.S + - Optimized rounding + scaling operations. + 2000/09/17: synth.c + - Changed D[] run-time shifts to compile-time. + - Modified synthesis for better multiply/accumulate code output. + 2001/08/11: fixed.h, synth.c + - Suggested 64-bit FPM negation and negative term factorization + during synthesis. + 2001/08/11: fixed.h + - Suggested unrounded behavior for FPM_DEFAULT when OPT_SPEED. + 2001/11/19: fixed.c + - Suggested computation of any resampling ratio. + +=============================================================================== + diff --git a/code/libmad/D.dat b/code/libmad/D.dat new file mode 100644 index 00000000..4a7fa4fa --- /dev/null +++ b/code/libmad/D.dat @@ -0,0 +1,607 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: D.dat,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +/* + * These are the coefficients for the subband synthesis window. This is a + * reordered version of Table B.3 from ISO/IEC 11172-3. + * + * Every value is parameterized so that shift optimizations can be made at + * compile-time. For example, every value can be right-shifted 12 bits to + * minimize multiply instruction times without any loss of accuracy. + */ + + { PRESHIFT(0x00000000) /* 0.000000000 */, /* 0 */ + -PRESHIFT(0x0001d000) /* -0.000442505 */, + PRESHIFT(0x000d5000) /* 0.003250122 */, + -PRESHIFT(0x001cb000) /* -0.007003784 */, + PRESHIFT(0x007f5000) /* 0.031082153 */, + -PRESHIFT(0x01421000) /* -0.078628540 */, + PRESHIFT(0x019ae000) /* 0.100311279 */, + -PRESHIFT(0x09271000) /* -0.572036743 */, + PRESHIFT(0x1251e000) /* 1.144989014 */, + PRESHIFT(0x09271000) /* 0.572036743 */, + PRESHIFT(0x019ae000) /* 0.100311279 */, + PRESHIFT(0x01421000) /* 0.078628540 */, + PRESHIFT(0x007f5000) /* 0.031082153 */, + PRESHIFT(0x001cb000) /* 0.007003784 */, + PRESHIFT(0x000d5000) /* 0.003250122 */, + PRESHIFT(0x0001d000) /* 0.000442505 */, + + PRESHIFT(0x00000000) /* 0.000000000 */, + -PRESHIFT(0x0001d000) /* -0.000442505 */, + PRESHIFT(0x000d5000) /* 0.003250122 */, + -PRESHIFT(0x001cb000) /* -0.007003784 */, + PRESHIFT(0x007f5000) /* 0.031082153 */, + -PRESHIFT(0x01421000) /* -0.078628540 */, + PRESHIFT(0x019ae000) /* 0.100311279 */, + -PRESHIFT(0x09271000) /* -0.572036743 */, + PRESHIFT(0x1251e000) /* 1.144989014 */, + PRESHIFT(0x09271000) /* 0.572036743 */, + PRESHIFT(0x019ae000) /* 0.100311279 */, + PRESHIFT(0x01421000) /* 0.078628540 */, + PRESHIFT(0x007f5000) /* 0.031082153 */, + PRESHIFT(0x001cb000) /* 0.007003784 */, + PRESHIFT(0x000d5000) /* 0.003250122 */, + PRESHIFT(0x0001d000) /* 0.000442505 */ }, + + { -PRESHIFT(0x00001000) /* -0.000015259 */, /* 1 */ + -PRESHIFT(0x0001f000) /* -0.000473022 */, + PRESHIFT(0x000da000) /* 0.003326416 */, + -PRESHIFT(0x00207000) /* -0.007919312 */, + PRESHIFT(0x007d0000) /* 0.030517578 */, + -PRESHIFT(0x0158d000) /* -0.084182739 */, + PRESHIFT(0x01747000) /* 0.090927124 */, + -PRESHIFT(0x099a8000) /* -0.600219727 */, + PRESHIFT(0x124f0000) /* 1.144287109 */, + PRESHIFT(0x08b38000) /* 0.543823242 */, + PRESHIFT(0x01bde000) /* 0.108856201 */, + PRESHIFT(0x012b4000) /* 0.073059082 */, + PRESHIFT(0x0080f000) /* 0.031478882 */, + PRESHIFT(0x00191000) /* 0.006118774 */, + PRESHIFT(0x000d0000) /* 0.003173828 */, + PRESHIFT(0x0001a000) /* 0.000396729 */, + + -PRESHIFT(0x00001000) /* -0.000015259 */, + -PRESHIFT(0x0001f000) /* -0.000473022 */, + PRESHIFT(0x000da000) /* 0.003326416 */, + -PRESHIFT(0x00207000) /* -0.007919312 */, + PRESHIFT(0x007d0000) /* 0.030517578 */, + -PRESHIFT(0x0158d000) /* -0.084182739 */, + PRESHIFT(0x01747000) /* 0.090927124 */, + -PRESHIFT(0x099a8000) /* -0.600219727 */, + PRESHIFT(0x124f0000) /* 1.144287109 */, + PRESHIFT(0x08b38000) /* 0.543823242 */, + PRESHIFT(0x01bde000) /* 0.108856201 */, + PRESHIFT(0x012b4000) /* 0.073059082 */, + PRESHIFT(0x0080f000) /* 0.031478882 */, + PRESHIFT(0x00191000) /* 0.006118774 */, + PRESHIFT(0x000d0000) /* 0.003173828 */, + PRESHIFT(0x0001a000) /* 0.000396729 */ }, + + { -PRESHIFT(0x00001000) /* -0.000015259 */, /* 2 */ + -PRESHIFT(0x00023000) /* -0.000534058 */, + PRESHIFT(0x000de000) /* 0.003387451 */, + -PRESHIFT(0x00245000) /* -0.008865356 */, + PRESHIFT(0x007a0000) /* 0.029785156 */, + -PRESHIFT(0x016f7000) /* -0.089706421 */, + PRESHIFT(0x014a8000) /* 0.080688477 */, + -PRESHIFT(0x0a0d8000) /* -0.628295898 */, + PRESHIFT(0x12468000) /* 1.142211914 */, + PRESHIFT(0x083ff000) /* 0.515609741 */, + PRESHIFT(0x01dd8000) /* 0.116577148 */, + PRESHIFT(0x01149000) /* 0.067520142 */, + PRESHIFT(0x00820000) /* 0.031738281 */, + PRESHIFT(0x0015b000) /* 0.005294800 */, + PRESHIFT(0x000ca000) /* 0.003082275 */, + PRESHIFT(0x00018000) /* 0.000366211 */, + + -PRESHIFT(0x00001000) /* -0.000015259 */, + -PRESHIFT(0x00023000) /* -0.000534058 */, + PRESHIFT(0x000de000) /* 0.003387451 */, + -PRESHIFT(0x00245000) /* -0.008865356 */, + PRESHIFT(0x007a0000) /* 0.029785156 */, + -PRESHIFT(0x016f7000) /* -0.089706421 */, + PRESHIFT(0x014a8000) /* 0.080688477 */, + -PRESHIFT(0x0a0d8000) /* -0.628295898 */, + PRESHIFT(0x12468000) /* 1.142211914 */, + PRESHIFT(0x083ff000) /* 0.515609741 */, + PRESHIFT(0x01dd8000) /* 0.116577148 */, + PRESHIFT(0x01149000) /* 0.067520142 */, + PRESHIFT(0x00820000) /* 0.031738281 */, + PRESHIFT(0x0015b000) /* 0.005294800 */, + PRESHIFT(0x000ca000) /* 0.003082275 */, + PRESHIFT(0x00018000) /* 0.000366211 */ }, + + { -PRESHIFT(0x00001000) /* -0.000015259 */, /* 3 */ + -PRESHIFT(0x00026000) /* -0.000579834 */, + PRESHIFT(0x000e1000) /* 0.003433228 */, + -PRESHIFT(0x00285000) /* -0.009841919 */, + PRESHIFT(0x00765000) /* 0.028884888 */, + -PRESHIFT(0x0185d000) /* -0.095169067 */, + PRESHIFT(0x011d1000) /* 0.069595337 */, + -PRESHIFT(0x0a7fe000) /* -0.656219482 */, + PRESHIFT(0x12386000) /* 1.138763428 */, + PRESHIFT(0x07ccb000) /* 0.487472534 */, + PRESHIFT(0x01f9c000) /* 0.123474121 */, + PRESHIFT(0x00fdf000) /* 0.061996460 */, + PRESHIFT(0x00827000) /* 0.031845093 */, + PRESHIFT(0x00126000) /* 0.004486084 */, + PRESHIFT(0x000c4000) /* 0.002990723 */, + PRESHIFT(0x00015000) /* 0.000320435 */, + + -PRESHIFT(0x00001000) /* -0.000015259 */, + -PRESHIFT(0x00026000) /* -0.000579834 */, + PRESHIFT(0x000e1000) /* 0.003433228 */, + -PRESHIFT(0x00285000) /* -0.009841919 */, + PRESHIFT(0x00765000) /* 0.028884888 */, + -PRESHIFT(0x0185d000) /* -0.095169067 */, + PRESHIFT(0x011d1000) /* 0.069595337 */, + -PRESHIFT(0x0a7fe000) /* -0.656219482 */, + PRESHIFT(0x12386000) /* 1.138763428 */, + PRESHIFT(0x07ccb000) /* 0.487472534 */, + PRESHIFT(0x01f9c000) /* 0.123474121 */, + PRESHIFT(0x00fdf000) /* 0.061996460 */, + PRESHIFT(0x00827000) /* 0.031845093 */, + PRESHIFT(0x00126000) /* 0.004486084 */, + PRESHIFT(0x000c4000) /* 0.002990723 */, + PRESHIFT(0x00015000) /* 0.000320435 */ }, + + { -PRESHIFT(0x00001000) /* -0.000015259 */, /* 4 */ + -PRESHIFT(0x00029000) /* -0.000625610 */, + PRESHIFT(0x000e3000) /* 0.003463745 */, + -PRESHIFT(0x002c7000) /* -0.010848999 */, + PRESHIFT(0x0071e000) /* 0.027801514 */, + -PRESHIFT(0x019bd000) /* -0.100540161 */, + PRESHIFT(0x00ec0000) /* 0.057617187 */, + -PRESHIFT(0x0af15000) /* -0.683914185 */, + PRESHIFT(0x12249000) /* 1.133926392 */, + PRESHIFT(0x075a0000) /* 0.459472656 */, + PRESHIFT(0x0212c000) /* 0.129577637 */, + PRESHIFT(0x00e79000) /* 0.056533813 */, + PRESHIFT(0x00825000) /* 0.031814575 */, + PRESHIFT(0x000f4000) /* 0.003723145 */, + PRESHIFT(0x000be000) /* 0.002899170 */, + PRESHIFT(0x00013000) /* 0.000289917 */, + + -PRESHIFT(0x00001000) /* -0.000015259 */, + -PRESHIFT(0x00029000) /* -0.000625610 */, + PRESHIFT(0x000e3000) /* 0.003463745 */, + -PRESHIFT(0x002c7000) /* -0.010848999 */, + PRESHIFT(0x0071e000) /* 0.027801514 */, + -PRESHIFT(0x019bd000) /* -0.100540161 */, + PRESHIFT(0x00ec0000) /* 0.057617187 */, + -PRESHIFT(0x0af15000) /* -0.683914185 */, + PRESHIFT(0x12249000) /* 1.133926392 */, + PRESHIFT(0x075a0000) /* 0.459472656 */, + PRESHIFT(0x0212c000) /* 0.129577637 */, + PRESHIFT(0x00e79000) /* 0.056533813 */, + PRESHIFT(0x00825000) /* 0.031814575 */, + PRESHIFT(0x000f4000) /* 0.003723145 */, + PRESHIFT(0x000be000) /* 0.002899170 */, + PRESHIFT(0x00013000) /* 0.000289917 */ }, + + { -PRESHIFT(0x00001000) /* -0.000015259 */, /* 5 */ + -PRESHIFT(0x0002d000) /* -0.000686646 */, + PRESHIFT(0x000e4000) /* 0.003479004 */, + -PRESHIFT(0x0030b000) /* -0.011886597 */, + PRESHIFT(0x006cb000) /* 0.026535034 */, + -PRESHIFT(0x01b17000) /* -0.105819702 */, + PRESHIFT(0x00b77000) /* 0.044784546 */, + -PRESHIFT(0x0b619000) /* -0.711318970 */, + PRESHIFT(0x120b4000) /* 1.127746582 */, + PRESHIFT(0x06e81000) /* 0.431655884 */, + PRESHIFT(0x02288000) /* 0.134887695 */, + PRESHIFT(0x00d17000) /* 0.051132202 */, + PRESHIFT(0x0081b000) /* 0.031661987 */, + PRESHIFT(0x000c5000) /* 0.003005981 */, + PRESHIFT(0x000b7000) /* 0.002792358 */, + PRESHIFT(0x00011000) /* 0.000259399 */, + + -PRESHIFT(0x00001000) /* -0.000015259 */, + -PRESHIFT(0x0002d000) /* -0.000686646 */, + PRESHIFT(0x000e4000) /* 0.003479004 */, + -PRESHIFT(0x0030b000) /* -0.011886597 */, + PRESHIFT(0x006cb000) /* 0.026535034 */, + -PRESHIFT(0x01b17000) /* -0.105819702 */, + PRESHIFT(0x00b77000) /* 0.044784546 */, + -PRESHIFT(0x0b619000) /* -0.711318970 */, + PRESHIFT(0x120b4000) /* 1.127746582 */, + PRESHIFT(0x06e81000) /* 0.431655884 */, + PRESHIFT(0x02288000) /* 0.134887695 */, + PRESHIFT(0x00d17000) /* 0.051132202 */, + PRESHIFT(0x0081b000) /* 0.031661987 */, + PRESHIFT(0x000c5000) /* 0.003005981 */, + PRESHIFT(0x000b7000) /* 0.002792358 */, + PRESHIFT(0x00011000) /* 0.000259399 */ }, + + { -PRESHIFT(0x00001000) /* -0.000015259 */, /* 6 */ + -PRESHIFT(0x00031000) /* -0.000747681 */, + PRESHIFT(0x000e4000) /* 0.003479004 */, + -PRESHIFT(0x00350000) /* -0.012939453 */, + PRESHIFT(0x0066c000) /* 0.025085449 */, + -PRESHIFT(0x01c67000) /* -0.110946655 */, + PRESHIFT(0x007f5000) /* 0.031082153 */, + -PRESHIFT(0x0bd06000) /* -0.738372803 */, + PRESHIFT(0x11ec7000) /* 1.120223999 */, + PRESHIFT(0x06772000) /* 0.404083252 */, + PRESHIFT(0x023b3000) /* 0.139450073 */, + PRESHIFT(0x00bbc000) /* 0.045837402 */, + PRESHIFT(0x00809000) /* 0.031387329 */, + PRESHIFT(0x00099000) /* 0.002334595 */, + PRESHIFT(0x000b0000) /* 0.002685547 */, + PRESHIFT(0x00010000) /* 0.000244141 */, + + -PRESHIFT(0x00001000) /* -0.000015259 */, + -PRESHIFT(0x00031000) /* -0.000747681 */, + PRESHIFT(0x000e4000) /* 0.003479004 */, + -PRESHIFT(0x00350000) /* -0.012939453 */, + PRESHIFT(0x0066c000) /* 0.025085449 */, + -PRESHIFT(0x01c67000) /* -0.110946655 */, + PRESHIFT(0x007f5000) /* 0.031082153 */, + -PRESHIFT(0x0bd06000) /* -0.738372803 */, + PRESHIFT(0x11ec7000) /* 1.120223999 */, + PRESHIFT(0x06772000) /* 0.404083252 */, + PRESHIFT(0x023b3000) /* 0.139450073 */, + PRESHIFT(0x00bbc000) /* 0.045837402 */, + PRESHIFT(0x00809000) /* 0.031387329 */, + PRESHIFT(0x00099000) /* 0.002334595 */, + PRESHIFT(0x000b0000) /* 0.002685547 */, + PRESHIFT(0x00010000) /* 0.000244141 */ }, + + { -PRESHIFT(0x00002000) /* -0.000030518 */, /* 7 */ + -PRESHIFT(0x00035000) /* -0.000808716 */, + PRESHIFT(0x000e3000) /* 0.003463745 */, + -PRESHIFT(0x00397000) /* -0.014022827 */, + PRESHIFT(0x005ff000) /* 0.023422241 */, + -PRESHIFT(0x01dad000) /* -0.115921021 */, + PRESHIFT(0x0043a000) /* 0.016510010 */, + -PRESHIFT(0x0c3d9000) /* -0.765029907 */, + PRESHIFT(0x11c83000) /* 1.111373901 */, + PRESHIFT(0x06076000) /* 0.376800537 */, + PRESHIFT(0x024ad000) /* 0.143264771 */, + PRESHIFT(0x00a67000) /* 0.040634155 */, + PRESHIFT(0x007f0000) /* 0.031005859 */, + PRESHIFT(0x0006f000) /* 0.001693726 */, + PRESHIFT(0x000a9000) /* 0.002578735 */, + PRESHIFT(0x0000e000) /* 0.000213623 */, + + -PRESHIFT(0x00002000) /* -0.000030518 */, + -PRESHIFT(0x00035000) /* -0.000808716 */, + PRESHIFT(0x000e3000) /* 0.003463745 */, + -PRESHIFT(0x00397000) /* -0.014022827 */, + PRESHIFT(0x005ff000) /* 0.023422241 */, + -PRESHIFT(0x01dad000) /* -0.115921021 */, + PRESHIFT(0x0043a000) /* 0.016510010 */, + -PRESHIFT(0x0c3d9000) /* -0.765029907 */, + PRESHIFT(0x11c83000) /* 1.111373901 */, + PRESHIFT(0x06076000) /* 0.376800537 */, + PRESHIFT(0x024ad000) /* 0.143264771 */, + PRESHIFT(0x00a67000) /* 0.040634155 */, + PRESHIFT(0x007f0000) /* 0.031005859 */, + PRESHIFT(0x0006f000) /* 0.001693726 */, + PRESHIFT(0x000a9000) /* 0.002578735 */, + PRESHIFT(0x0000e000) /* 0.000213623 */ }, + + { -PRESHIFT(0x00002000) /* -0.000030518 */, /* 8 */ + -PRESHIFT(0x0003a000) /* -0.000885010 */, + PRESHIFT(0x000e0000) /* 0.003417969 */, + -PRESHIFT(0x003df000) /* -0.015121460 */, + PRESHIFT(0x00586000) /* 0.021575928 */, + -PRESHIFT(0x01ee6000) /* -0.120697021 */, + PRESHIFT(0x00046000) /* 0.001068115 */, + -PRESHIFT(0x0ca8d000) /* -0.791213989 */, + PRESHIFT(0x119e9000) /* 1.101211548 */, + PRESHIFT(0x05991000) /* 0.349868774 */, + PRESHIFT(0x02578000) /* 0.146362305 */, + PRESHIFT(0x0091a000) /* 0.035552979 */, + PRESHIFT(0x007d1000) /* 0.030532837 */, + PRESHIFT(0x00048000) /* 0.001098633 */, + PRESHIFT(0x000a1000) /* 0.002456665 */, + PRESHIFT(0x0000d000) /* 0.000198364 */, + + -PRESHIFT(0x00002000) /* -0.000030518 */, + -PRESHIFT(0x0003a000) /* -0.000885010 */, + PRESHIFT(0x000e0000) /* 0.003417969 */, + -PRESHIFT(0x003df000) /* -0.015121460 */, + PRESHIFT(0x00586000) /* 0.021575928 */, + -PRESHIFT(0x01ee6000) /* -0.120697021 */, + PRESHIFT(0x00046000) /* 0.001068115 */, + -PRESHIFT(0x0ca8d000) /* -0.791213989 */, + PRESHIFT(0x119e9000) /* 1.101211548 */, + PRESHIFT(0x05991000) /* 0.349868774 */, + PRESHIFT(0x02578000) /* 0.146362305 */, + PRESHIFT(0x0091a000) /* 0.035552979 */, + PRESHIFT(0x007d1000) /* 0.030532837 */, + PRESHIFT(0x00048000) /* 0.001098633 */, + PRESHIFT(0x000a1000) /* 0.002456665 */, + PRESHIFT(0x0000d000) /* 0.000198364 */ }, + + { -PRESHIFT(0x00002000) /* -0.000030518 */, /* 9 */ + -PRESHIFT(0x0003f000) /* -0.000961304 */, + PRESHIFT(0x000dd000) /* 0.003372192 */, + -PRESHIFT(0x00428000) /* -0.016235352 */, + PRESHIFT(0x00500000) /* 0.019531250 */, + -PRESHIFT(0x02011000) /* -0.125259399 */, + -PRESHIFT(0x003e6000) /* -0.015228271 */, + -PRESHIFT(0x0d11e000) /* -0.816864014 */, + PRESHIFT(0x116fc000) /* 1.089782715 */, + PRESHIFT(0x052c5000) /* 0.323318481 */, + PRESHIFT(0x02616000) /* 0.148773193 */, + PRESHIFT(0x007d6000) /* 0.030609131 */, + PRESHIFT(0x007aa000) /* 0.029937744 */, + PRESHIFT(0x00024000) /* 0.000549316 */, + PRESHIFT(0x0009a000) /* 0.002349854 */, + PRESHIFT(0x0000b000) /* 0.000167847 */, + + -PRESHIFT(0x00002000) /* -0.000030518 */, + -PRESHIFT(0x0003f000) /* -0.000961304 */, + PRESHIFT(0x000dd000) /* 0.003372192 */, + -PRESHIFT(0x00428000) /* -0.016235352 */, + PRESHIFT(0x00500000) /* 0.019531250 */, + -PRESHIFT(0x02011000) /* -0.125259399 */, + -PRESHIFT(0x003e6000) /* -0.015228271 */, + -PRESHIFT(0x0d11e000) /* -0.816864014 */, + PRESHIFT(0x116fc000) /* 1.089782715 */, + PRESHIFT(0x052c5000) /* 0.323318481 */, + PRESHIFT(0x02616000) /* 0.148773193 */, + PRESHIFT(0x007d6000) /* 0.030609131 */, + PRESHIFT(0x007aa000) /* 0.029937744 */, + PRESHIFT(0x00024000) /* 0.000549316 */, + PRESHIFT(0x0009a000) /* 0.002349854 */, + PRESHIFT(0x0000b000) /* 0.000167847 */ }, + + { -PRESHIFT(0x00002000) /* -0.000030518 */, /* 10 */ + -PRESHIFT(0x00044000) /* -0.001037598 */, + PRESHIFT(0x000d7000) /* 0.003280640 */, + -PRESHIFT(0x00471000) /* -0.017349243 */, + PRESHIFT(0x0046b000) /* 0.017257690 */, + -PRESHIFT(0x0212b000) /* -0.129562378 */, + -PRESHIFT(0x0084a000) /* -0.032379150 */, + -PRESHIFT(0x0d78a000) /* -0.841949463 */, + PRESHIFT(0x113be000) /* 1.077117920 */, + PRESHIFT(0x04c16000) /* 0.297210693 */, + PRESHIFT(0x02687000) /* 0.150497437 */, + PRESHIFT(0x0069c000) /* 0.025817871 */, + PRESHIFT(0x0077f000) /* 0.029281616 */, + PRESHIFT(0x00002000) /* 0.000030518 */, + PRESHIFT(0x00093000) /* 0.002243042 */, + PRESHIFT(0x0000a000) /* 0.000152588 */, + + -PRESHIFT(0x00002000) /* -0.000030518 */, + -PRESHIFT(0x00044000) /* -0.001037598 */, + PRESHIFT(0x000d7000) /* 0.003280640 */, + -PRESHIFT(0x00471000) /* -0.017349243 */, + PRESHIFT(0x0046b000) /* 0.017257690 */, + -PRESHIFT(0x0212b000) /* -0.129562378 */, + -PRESHIFT(0x0084a000) /* -0.032379150 */, + -PRESHIFT(0x0d78a000) /* -0.841949463 */, + PRESHIFT(0x113be000) /* 1.077117920 */, + PRESHIFT(0x04c16000) /* 0.297210693 */, + PRESHIFT(0x02687000) /* 0.150497437 */, + PRESHIFT(0x0069c000) /* 0.025817871 */, + PRESHIFT(0x0077f000) /* 0.029281616 */, + PRESHIFT(0x00002000) /* 0.000030518 */, + PRESHIFT(0x00093000) /* 0.002243042 */, + PRESHIFT(0x0000a000) /* 0.000152588 */ }, + + { -PRESHIFT(0x00003000) /* -0.000045776 */, /* 11 */ + -PRESHIFT(0x00049000) /* -0.001113892 */, + PRESHIFT(0x000d0000) /* 0.003173828 */, + -PRESHIFT(0x004ba000) /* -0.018463135 */, + PRESHIFT(0x003ca000) /* 0.014801025 */, + -PRESHIFT(0x02233000) /* -0.133590698 */, + -PRESHIFT(0x00ce4000) /* -0.050354004 */, + -PRESHIFT(0x0ddca000) /* -0.866363525 */, + PRESHIFT(0x1102f000) /* 1.063217163 */, + PRESHIFT(0x04587000) /* 0.271591187 */, + PRESHIFT(0x026cf000) /* 0.151596069 */, + PRESHIFT(0x0056c000) /* 0.021179199 */, + PRESHIFT(0x0074e000) /* 0.028533936 */, + -PRESHIFT(0x0001d000) /* -0.000442505 */, + PRESHIFT(0x0008b000) /* 0.002120972 */, + PRESHIFT(0x00009000) /* 0.000137329 */, + + -PRESHIFT(0x00003000) /* -0.000045776 */, + -PRESHIFT(0x00049000) /* -0.001113892 */, + PRESHIFT(0x000d0000) /* 0.003173828 */, + -PRESHIFT(0x004ba000) /* -0.018463135 */, + PRESHIFT(0x003ca000) /* 0.014801025 */, + -PRESHIFT(0x02233000) /* -0.133590698 */, + -PRESHIFT(0x00ce4000) /* -0.050354004 */, + -PRESHIFT(0x0ddca000) /* -0.866363525 */, + PRESHIFT(0x1102f000) /* 1.063217163 */, + PRESHIFT(0x04587000) /* 0.271591187 */, + PRESHIFT(0x026cf000) /* 0.151596069 */, + PRESHIFT(0x0056c000) /* 0.021179199 */, + PRESHIFT(0x0074e000) /* 0.028533936 */, + -PRESHIFT(0x0001d000) /* -0.000442505 */, + PRESHIFT(0x0008b000) /* 0.002120972 */, + PRESHIFT(0x00009000) /* 0.000137329 */ }, + + { -PRESHIFT(0x00003000) /* -0.000045776 */, /* 12 */ + -PRESHIFT(0x0004f000) /* -0.001205444 */, + PRESHIFT(0x000c8000) /* 0.003051758 */, + -PRESHIFT(0x00503000) /* -0.019577026 */, + PRESHIFT(0x0031a000) /* 0.012115479 */, + -PRESHIFT(0x02326000) /* -0.137298584 */, + -PRESHIFT(0x011b5000) /* -0.069168091 */, + -PRESHIFT(0x0e3dd000) /* -0.890090942 */, + PRESHIFT(0x10c54000) /* 1.048156738 */, + PRESHIFT(0x03f1b000) /* 0.246505737 */, + PRESHIFT(0x026ee000) /* 0.152069092 */, + PRESHIFT(0x00447000) /* 0.016708374 */, + PRESHIFT(0x00719000) /* 0.027725220 */, + -PRESHIFT(0x00039000) /* -0.000869751 */, + PRESHIFT(0x00084000) /* 0.002014160 */, + PRESHIFT(0x00008000) /* 0.000122070 */, + + -PRESHIFT(0x00003000) /* -0.000045776 */, + -PRESHIFT(0x0004f000) /* -0.001205444 */, + PRESHIFT(0x000c8000) /* 0.003051758 */, + -PRESHIFT(0x00503000) /* -0.019577026 */, + PRESHIFT(0x0031a000) /* 0.012115479 */, + -PRESHIFT(0x02326000) /* -0.137298584 */, + -PRESHIFT(0x011b5000) /* -0.069168091 */, + -PRESHIFT(0x0e3dd000) /* -0.890090942 */, + PRESHIFT(0x10c54000) /* 1.048156738 */, + PRESHIFT(0x03f1b000) /* 0.246505737 */, + PRESHIFT(0x026ee000) /* 0.152069092 */, + PRESHIFT(0x00447000) /* 0.016708374 */, + PRESHIFT(0x00719000) /* 0.027725220 */, + -PRESHIFT(0x00039000) /* -0.000869751 */, + PRESHIFT(0x00084000) /* 0.002014160 */, + PRESHIFT(0x00008000) /* 0.000122070 */ }, + + { -PRESHIFT(0x00004000) /* -0.000061035 */, /* 13 */ + -PRESHIFT(0x00055000) /* -0.001296997 */, + PRESHIFT(0x000bd000) /* 0.002883911 */, + -PRESHIFT(0x0054c000) /* -0.020690918 */, + PRESHIFT(0x0025d000) /* 0.009231567 */, + -PRESHIFT(0x02403000) /* -0.140670776 */, + -PRESHIFT(0x016ba000) /* -0.088775635 */, + -PRESHIFT(0x0e9be000) /* -0.913055420 */, + PRESHIFT(0x1082d000) /* 1.031936646 */, + PRESHIFT(0x038d4000) /* 0.221984863 */, + PRESHIFT(0x026e7000) /* 0.151962280 */, + PRESHIFT(0x0032e000) /* 0.012420654 */, + PRESHIFT(0x006df000) /* 0.026840210 */, + -PRESHIFT(0x00053000) /* -0.001266479 */, + PRESHIFT(0x0007d000) /* 0.001907349 */, + PRESHIFT(0x00007000) /* 0.000106812 */, + + -PRESHIFT(0x00004000) /* -0.000061035 */, + -PRESHIFT(0x00055000) /* -0.001296997 */, + PRESHIFT(0x000bd000) /* 0.002883911 */, + -PRESHIFT(0x0054c000) /* -0.020690918 */, + PRESHIFT(0x0025d000) /* 0.009231567 */, + -PRESHIFT(0x02403000) /* -0.140670776 */, + -PRESHIFT(0x016ba000) /* -0.088775635 */, + -PRESHIFT(0x0e9be000) /* -0.913055420 */, + PRESHIFT(0x1082d000) /* 1.031936646 */, + PRESHIFT(0x038d4000) /* 0.221984863 */, + PRESHIFT(0x026e7000) /* 0.151962280 */, + PRESHIFT(0x0032e000) /* 0.012420654 */, + PRESHIFT(0x006df000) /* 0.026840210 */, + -PRESHIFT(0x00053000) /* -0.001266479 */, + PRESHIFT(0x0007d000) /* 0.001907349 */, + PRESHIFT(0x00007000) /* 0.000106812 */ }, + + { -PRESHIFT(0x00004000) /* -0.000061035 */, /* 14 */ + -PRESHIFT(0x0005b000) /* -0.001388550 */, + PRESHIFT(0x000b1000) /* 0.002700806 */, + -PRESHIFT(0x00594000) /* -0.021789551 */, + PRESHIFT(0x00192000) /* 0.006134033 */, + -PRESHIFT(0x024c8000) /* -0.143676758 */, + -PRESHIFT(0x01bf2000) /* -0.109161377 */, + -PRESHIFT(0x0ef69000) /* -0.935195923 */, + PRESHIFT(0x103be000) /* 1.014617920 */, + PRESHIFT(0x032b4000) /* 0.198059082 */, + PRESHIFT(0x026bc000) /* 0.151306152 */, + PRESHIFT(0x00221000) /* 0.008316040 */, + PRESHIFT(0x006a2000) /* 0.025909424 */, + -PRESHIFT(0x0006a000) /* -0.001617432 */, + PRESHIFT(0x00075000) /* 0.001785278 */, + PRESHIFT(0x00007000) /* 0.000106812 */, + + -PRESHIFT(0x00004000) /* -0.000061035 */, + -PRESHIFT(0x0005b000) /* -0.001388550 */, + PRESHIFT(0x000b1000) /* 0.002700806 */, + -PRESHIFT(0x00594000) /* -0.021789551 */, + PRESHIFT(0x00192000) /* 0.006134033 */, + -PRESHIFT(0x024c8000) /* -0.143676758 */, + -PRESHIFT(0x01bf2000) /* -0.109161377 */, + -PRESHIFT(0x0ef69000) /* -0.935195923 */, + PRESHIFT(0x103be000) /* 1.014617920 */, + PRESHIFT(0x032b4000) /* 0.198059082 */, + PRESHIFT(0x026bc000) /* 0.151306152 */, + PRESHIFT(0x00221000) /* 0.008316040 */, + PRESHIFT(0x006a2000) /* 0.025909424 */, + -PRESHIFT(0x0006a000) /* -0.001617432 */, + PRESHIFT(0x00075000) /* 0.001785278 */, + PRESHIFT(0x00007000) /* 0.000106812 */ }, + + { -PRESHIFT(0x00005000) /* -0.000076294 */, /* 15 */ + -PRESHIFT(0x00061000) /* -0.001480103 */, + PRESHIFT(0x000a3000) /* 0.002487183 */, + -PRESHIFT(0x005da000) /* -0.022857666 */, + PRESHIFT(0x000b9000) /* 0.002822876 */, + -PRESHIFT(0x02571000) /* -0.146255493 */, + -PRESHIFT(0x0215c000) /* -0.130310059 */, + -PRESHIFT(0x0f4dc000) /* -0.956481934 */, + PRESHIFT(0x0ff0a000) /* 0.996246338 */, + PRESHIFT(0x02cbf000) /* 0.174789429 */, + PRESHIFT(0x0266e000) /* 0.150115967 */, + PRESHIFT(0x00120000) /* 0.004394531 */, + PRESHIFT(0x00662000) /* 0.024932861 */, + -PRESHIFT(0x0007f000) /* -0.001937866 */, + PRESHIFT(0x0006f000) /* 0.001693726 */, + PRESHIFT(0x00006000) /* 0.000091553 */, + + -PRESHIFT(0x00005000) /* -0.000076294 */, + -PRESHIFT(0x00061000) /* -0.001480103 */, + PRESHIFT(0x000a3000) /* 0.002487183 */, + -PRESHIFT(0x005da000) /* -0.022857666 */, + PRESHIFT(0x000b9000) /* 0.002822876 */, + -PRESHIFT(0x02571000) /* -0.146255493 */, + -PRESHIFT(0x0215c000) /* -0.130310059 */, + -PRESHIFT(0x0f4dc000) /* -0.956481934 */, + PRESHIFT(0x0ff0a000) /* 0.996246338 */, + PRESHIFT(0x02cbf000) /* 0.174789429 */, + PRESHIFT(0x0266e000) /* 0.150115967 */, + PRESHIFT(0x00120000) /* 0.004394531 */, + PRESHIFT(0x00662000) /* 0.024932861 */, + -PRESHIFT(0x0007f000) /* -0.001937866 */, + PRESHIFT(0x0006f000) /* 0.001693726 */, + PRESHIFT(0x00006000) /* 0.000091553 */ }, + + { -PRESHIFT(0x00005000) /* -0.000076294 */, /* 16 */ + -PRESHIFT(0x00068000) /* -0.001586914 */, + PRESHIFT(0x00092000) /* 0.002227783 */, + -PRESHIFT(0x0061f000) /* -0.023910522 */, + -PRESHIFT(0x0002d000) /* -0.000686646 */, + -PRESHIFT(0x025ff000) /* -0.148422241 */, + -PRESHIFT(0x026f7000) /* -0.152206421 */, + -PRESHIFT(0x0fa13000) /* -0.976852417 */, + PRESHIFT(0x0fa13000) /* 0.976852417 */, + PRESHIFT(0x026f7000) /* 0.152206421 */, + PRESHIFT(0x025ff000) /* 0.148422241 */, + PRESHIFT(0x0002d000) /* 0.000686646 */, + PRESHIFT(0x0061f000) /* 0.023910522 */, + -PRESHIFT(0x00092000) /* -0.002227783 */, + PRESHIFT(0x00068000) /* 0.001586914 */, + PRESHIFT(0x00005000) /* 0.000076294 */, + + -PRESHIFT(0x00005000) /* -0.000076294 */, + -PRESHIFT(0x00068000) /* -0.001586914 */, + PRESHIFT(0x00092000) /* 0.002227783 */, + -PRESHIFT(0x0061f000) /* -0.023910522 */, + -PRESHIFT(0x0002d000) /* -0.000686646 */, + -PRESHIFT(0x025ff000) /* -0.148422241 */, + -PRESHIFT(0x026f7000) /* -0.152206421 */, + -PRESHIFT(0x0fa13000) /* -0.976852417 */, + PRESHIFT(0x0fa13000) /* 0.976852417 */, + PRESHIFT(0x026f7000) /* 0.152206421 */, + PRESHIFT(0x025ff000) /* 0.148422241 */, + PRESHIFT(0x0002d000) /* 0.000686646 */, + PRESHIFT(0x0061f000) /* 0.023910522 */, + -PRESHIFT(0x00092000) /* -0.002227783 */, + PRESHIFT(0x00068000) /* 0.001586914 */, + PRESHIFT(0x00005000) /* 0.000076294 */ } diff --git a/code/libmad/README.md b/code/libmad/README.md new file mode 100644 index 00000000..fa8a2db6 --- /dev/null +++ b/code/libmad/README.md @@ -0,0 +1,178 @@ +# libmad - MPEG audio decoder library +Copyright (C) 2000-2004 Underbit Technologies, Inc. +Copyright (C) 2021-2023 Tenacity Team and Contributors + +`$Id: README,v 1.4 2004/01/23 09:41:32 rob Exp $` + +--- + +# Introduction + +MAD (libmad) is a high-quality MPEG audio decoder. It currently supports +MPEG-1 and the MPEG-2 extension to Lower Sampling Frequencies, as well as +the so-called MPEG 2.5 format. All three audio layers (Layer I, Layer II, +and Layer III a.k.a. MP3) are fully implemented. + +MAD does not yet support MPEG-2 multichannel audio (although it should be +backward compatible with such streams) nor does it currently support AAC. + +MAD has the following special features: + + - 24-bit PCM output + - 100% fixed-point (integer) computation + - completely new implementation based on the ISO/IEC standards + - distributed under the terms of the GNU General Public License (GPL) + +Because MAD provides full 24-bit PCM output, applications using MAD are +able to produce high quality audio. Even when the output device supports +only 16-bit PCM, applications can use the extra resolution to increase the +audible dynamic range through the use of dithering or noise shaping. + +Because MAD uses integer computation rather than floating point, it is +well suited for architectures without a floating point unit. All +calculations are performed with a 32-bit fixed-point integer +representation. + +Because MAD is a new implementation of the ISO/IEC standards, it is +unencumbered by the errors of other implementations. MAD is NOT a +derivation of the ISO reference source or any other code. Considerable +effort has been expended to ensure a correct implementation, even in cases +where the standards are ambiguous or misleading. + +Because MAD is distributed under the terms of the GPL, its redistribution +is not generally restricted, so long as the terms of the GPL are followed. +This means MAD can be incorporated into other software as long as that +software is also distributed under the GPL. (Should this be undesirable, +alternate arrangements may be possible by contacting Underbit.) + +# About The Code + +The code is optimized and performs very well, although specific +improvements can still be made. The output from the decoder library +consists of 32-bit signed linear fixed-point values that can be easily +scaled for any size PCM output, up to 24 bits per sample. + +The API for libmad can be found in the `mad.h' header file. Note that this +file is automatically generated, and will not exist until after you have +built the library. + +There are two APIs available, one high-level, and the other low-level. +With the low-level API, each step of the decoding process must be handled +explicitly, offering the greatest amount of control. With the high-level +API, after callbacks are configured, a single routine will decode an +entire bitstream. + +The high-level API may either be used synchronously or asynchronously. If +used asynchronously, decoding will occur in a separate process. +Communication is possible with the decoding process by passing control +messages. + +The file `minimad.c' contains an example usage of the libmad API that +shows only the bare minimum required to implement a useful decoder. It +expects a regular file to be redirected to standard input, and it sends +decoded 16-bit signed little-endian PCM samples to standard output. If a +decoding error occurs, it is reported to standard error and decoding +continues. Note that the scale() routine in this code is only provided as +an example; it rounds MAD's high-resolution samples down to 16 bits, but +does not perform any dithering or noise shaping. It is therefore not +recommended to use this routine as-is in your own code if sound quality is +important. + +## Integer Performance + +To get the best possible performance, it is recommended that an assembly +version of the fixed-point multiply and related routines be selected. +Several such assembly routines have been written for various CPUs. + +If an assembly version is not available, a fast approximation version will +be used. This will result in reduced accuracy of the decoder. + +Alternatively, if 64-bit integers are supported as a datatype by the +compiler, another version can be used that is much more accurate. +However, using an assembly version is generally much faster and just as +accurate. + +More information can be gathered from the `fixed.h' header file. + +MAD's CPU-intensive subband synthesis routine can be further optimized at +the expense of a slight loss in output accuracy due to a modified method +for fixed-point multiplication with a small windowing constant. While this +is helpful for performance and the output accuracy loss is generally +undetectable, it is disabled by default and must be explicitly enabled. + +Under some architectures, other special optimizations may also be +available. + +## Audio Quality + +The output from MAD has been found to satisfy the ISO/IEC 11172-4 +computational accuracy requirements for compliance. In most +configurations, MAD is a Full Layer III ISO/IEC 11172-3 audio decoder as +defined by the standard. + +When the approximation version of the fixed-point multiply is used, MAD is +a limited accuracy ISO/IEC 11172-3 audio decoder as defined by the +standard. + +MAD can alternatively be configured to produce output with less or more +accuracy than the default, as a tradeoff with performance. + +MAD produces output samples with a precision greater than 24 bits. Because +most output formats use fewer bits, typically 16, it is recommended that a +dithering algorithm be used (rather than rounding or truncating) to obtain +the highest quality audio. However, dithering may unfavorably affect an +analytic examination of the output (such as compliance testing); you may +therefore wish to use rounding in this case instead. + +## Portability Issues + +GCC is preferred to compile the code, but other compilers may also work. +The assembly code in `fixed.h' depends on the inline assembly features of +your compiler. If you're not using GCC or MSVC++, you can either write +your own assembly macros or use the default (low quality output) version. + +The union initialization of `huffman.c' may not be portable to all +platforms when GCC is not used. + +The code should not be sensitive to word sizes or byte ordering, however +it does assume A % B has the same sign as A. + +# Building and Installing + +libmad uses the CMake build system and has no dependencies. To build it, run: + +``` bash +cmake -D CMAKE_INSTALL_PREFIX=/where/you/want/to/install/to -S . -B build +cmake --build build --parallel number-of-cpu-cores +cmake --install build +``` + +The following CMake options are available which can be toggled by passing +'-D OPTION=VALUE' to the CMake configure step (the first call to cmake above): + + * ASO (ON|OFF): Enable CPU Architecture Specific Optimizations + (x86, ARM, and MIPS only). ON by default. + * EXAMPLE (ON|OFF): Build the example application. Only works on POSIX + operating systems. ON by default on POSIX operating systems. The example + application is not installed. + +## Supported Platforms + +libmad relies on a POSIX environment. On Windows, you should use Cygwin to +build libmad. + +It is planned that in a future release + +# Copyright + +Please read the `COPYRIGHT` file for copyright and warranty information. +Also, the file `COPYING` contains the full text of the GNU GPL. + +Send inquiries, comments, bug reports, suggestions, patches, etc. to: + + Underbit Technologies, Inc. + +See also the MAD home page on the Web: + + http://www.underbit.com/products/mad/ + diff --git a/code/libmad/TODO b/code/libmad/TODO new file mode 100644 index 00000000..1ea107c2 --- /dev/null +++ b/code/libmad/TODO @@ -0,0 +1,69 @@ + + libmad - MPEG audio decoder library + Copyright (C) 2000-2004 Underbit Technologies, Inc. + + $Id: TODO,v 1.3 2004/02/05 09:02:39 rob Exp $ + +=============================================================================== + +libmad: + - more API layers (buffering, PCM samples, dithering, etc.) + - x86 performance optimization compiler flags + - function documentation, general docs + - finish async API + - parse system streams? + - MPEG-2 MC, AAC? + - logarithmic multiplication? + - multiple frame decoding for better locality of reference? + - frame serial numbers, Layer III frame continuity checks + +fixed.h: + - experiment with FPM_INTEL: + +# if 1 +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrl %3,%1\n\t" \ + "shll %4,%2\n\t" \ + "orl %2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), \ + "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed64hi_t __hi_; \ + mad_fixed64lo_t __lo_; \ + mad_fixed_t __result; \ + asm ("sall %2,%1" \ + : "=r" (__hi_) \ + : "0" (hi), "I" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + asm ("shrl %2,%1" \ + : "=r" (__lo_) \ + : "0" (lo), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + asm ("orl %1,%2" \ + : "=rm" (__result) \ + : "r" (__hi_), "0" (__lo_) \ + : "cc"); \ + __result; \ + }) +# endif + +libmad Layer I: + - check frame length sanity + +libmad Layer II: + - check frame length sanity + +libmad Layer III: + - circular buffer + - optimize zero_part from Huffman decoding throughout + - MPEG 2.5 8000 Hz sf bands? mixed blocks? + - stereo->mono conversion optimization? + - enable frame-at-a-time decoding + - improve portability of huffman.c + diff --git a/code/libmad/bit.c b/code/libmad/bit.c new file mode 100644 index 00000000..72a094ca --- /dev/null +++ b/code/libmad/bit.c @@ -0,0 +1,236 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: bit.c,v 1.12 2004/01/23 09:41:32 rob Exp $ + */ + +# include "global.h" + +# ifdef HAVE_LIMITS_H +# include +# else +# define CHAR_BIT 8 +# endif + +# include "mad.h" + +/* + * This is the lookup table for computing the CRC-check word. + * As described in section 2.4.3.1 and depicted in Figure A.9 + * of ISO/IEC 11172-3, the generator polynomial is: + * + * G(X) = X^16 + X^15 + X^2 + 1 + */ +static +unsigned short const crc_table[256] = { + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 +}; + +# define CRC_POLY 0x8005 + +/* + * NAME: bit->init() + * DESCRIPTION: initialize bit pointer struct + */ +void mad_bit_init(struct mad_bitptr *bitptr, unsigned char const *byte) +{ + bitptr->byte = byte; + bitptr->cache = 0; + bitptr->left = CHAR_BIT; +} + +/* + * NAME: bit->length() + * DESCRIPTION: return number of bits between start and end points + */ +unsigned int mad_bit_length(struct mad_bitptr const *begin, + struct mad_bitptr const *end) +{ + return begin->left + + CHAR_BIT * (end->byte - (begin->byte + 1)) + (CHAR_BIT - end->left); +} + +/* + * NAME: bit->nextbyte() + * DESCRIPTION: return pointer to next unprocessed byte + */ +unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *bitptr) +{ + return bitptr->left == CHAR_BIT ? bitptr->byte : bitptr->byte + 1; +} + +/* + * NAME: bit->skip() + * DESCRIPTION: advance bit pointer + */ +void mad_bit_skip(struct mad_bitptr *bitptr, unsigned int len) +{ + bitptr->byte += len / CHAR_BIT; + bitptr->left -= len % CHAR_BIT; + + if (bitptr->left > CHAR_BIT) { + bitptr->byte++; + bitptr->left += CHAR_BIT; + } + + if (bitptr->left < CHAR_BIT) + bitptr->cache = *bitptr->byte; +} + +/* + * NAME: bit->read() + * DESCRIPTION: read an arbitrary number of bits and return their UIMSBF value + */ +unsigned long mad_bit_read(struct mad_bitptr *bitptr, unsigned int len) +{ + register unsigned long value; + + if (len == 0) + return 0; + + if (bitptr->left == CHAR_BIT) + bitptr->cache = *bitptr->byte; + + if (len < bitptr->left) { + value = (bitptr->cache & ((1 << bitptr->left) - 1)) >> + (bitptr->left - len); + bitptr->left -= len; + + return value; + } + + /* remaining bits in current byte */ + + value = bitptr->cache & ((1 << bitptr->left) - 1); + len -= bitptr->left; + + bitptr->byte++; + bitptr->left = CHAR_BIT; + + /* more bytes */ + + while (len >= CHAR_BIT) { + value = (value << CHAR_BIT) | *bitptr->byte++; + len -= CHAR_BIT; + } + + if (len > 0) { + bitptr->cache = *bitptr->byte; + + value = (value << len) | (bitptr->cache >> (CHAR_BIT - len)); + bitptr->left -= len; + } + + return value; +} + +# if 0 +/* + * NAME: bit->write() + * DESCRIPTION: write an arbitrary number of bits + */ +void mad_bit_write(struct mad_bitptr *bitptr, unsigned int len, + unsigned long value) +{ + unsigned char *ptr; + + ptr = (unsigned char *) bitptr->byte; + + /* ... */ +} +# endif + +/* + * NAME: bit->crc() + * DESCRIPTION: compute CRC-check word + */ +unsigned short mad_bit_crc(struct mad_bitptr bitptr, unsigned int len, + unsigned short init) +{ + register unsigned int crc; + + for (crc = init; len >= 32; len -= 32) { + register unsigned long data; + + data = mad_bit_read(&bitptr, 32); + + crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 24)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 16)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 8)) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 0)) & 0xff]; + } + + switch (len / 8) { + case 3: crc = (crc << 8) ^ + crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff]; + case 2: crc = (crc << 8) ^ + crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff]; + case 1: crc = (crc << 8) ^ + crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff]; + + len %= 8; + + case 0: break; + } + + while (len--) { + register unsigned int msb; + + msb = mad_bit_read(&bitptr, 1) ^ (crc >> 15); + + crc <<= 1; + if (msb & 1) + crc ^= CRC_POLY; + } + + return crc & 0xffff; +} diff --git a/code/libmad/decoder.c b/code/libmad/decoder.c new file mode 100644 index 00000000..b631a686 --- /dev/null +++ b/code/libmad/decoder.c @@ -0,0 +1,589 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: decoder.c,v 1.22 2004/01/23 09:41:32 rob Exp $ + */ + +# include "global.h" + +# ifdef HAVE_SYS_TYPES_H +# include +# endif + +# ifdef HAVE_SYS_WAIT_H +# include +# endif + +# ifdef HAVE_UNISTD_H +# include +# endif + +# ifdef HAVE_FCNTL_H +# include +# endif + +# include + +# ifdef HAVE_ERRNO_H +# include +# endif + +# include "mad.h" + +/* + * NAME: decoder->init() + * DESCRIPTION: initialize a decoder object with callback routines + */ +void mad_decoder_init(struct mad_decoder *decoder, void *data, + enum mad_flow (*input_func)(void *, + struct mad_stream *), + enum mad_flow (*header_func)(void *, + struct mad_header const *), + enum mad_flow (*filter_func)(void *, + struct mad_stream const *, + struct mad_frame *), + enum mad_flow (*output_func)(void *, + struct mad_header const *, + struct mad_pcm *), + enum mad_flow (*error_func)(void *, + struct mad_stream *, + struct mad_frame *), + enum mad_flow (*message_func)(void *, + void *, unsigned int *)) +{ + decoder->mode = -1; + + decoder->options = 0; + + decoder->async.pid = 0; + decoder->async.in = -1; + decoder->async.out = -1; + + decoder->sync = 0; + + decoder->cb_data = data; + + decoder->input_func = input_func; + decoder->header_func = header_func; + decoder->filter_func = filter_func; + decoder->output_func = output_func; + decoder->error_func = error_func; + decoder->message_func = message_func; +} + +int mad_decoder_finish(struct mad_decoder *decoder) +{ +# if defined(USE_ASYNC) + if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) { + pid_t pid; + int status; + + close(decoder->async.in); + + do + pid = waitpid(decoder->async.pid, &status, 0); + while (pid == -1 && errno == EINTR); + + decoder->mode = -1; + + close(decoder->async.out); + + decoder->async.pid = 0; + decoder->async.in = -1; + decoder->async.out = -1; + + if (pid == -1) + return -1; + + return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0; + } +# endif + + return 0; +} + +# if defined(USE_ASYNC) +static +enum mad_flow send_io(int fd, void const *data, size_t len) +{ + char const *ptr = data; + ssize_t count; + + while (len) { + do + count = write(fd, ptr, len); + while (count == -1 && errno == EINTR); + + if (count == -1) + return MAD_FLOW_BREAK; + + len -= count; + ptr += count; + } + + return MAD_FLOW_CONTINUE; +} + +static +enum mad_flow receive_io(int fd, void *buffer, size_t len) +{ + char *ptr = buffer; + ssize_t count; + + while (len) { + do + count = read(fd, ptr, len); + while (count == -1 && errno == EINTR); + + if (count == -1) + return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK; + else if (count == 0) + return MAD_FLOW_STOP; + + len -= count; + ptr += count; + } + + return MAD_FLOW_CONTINUE; +} + +static +enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len) +{ + int flags, blocking; + enum mad_flow result; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return MAD_FLOW_BREAK; + + blocking = flags & ~O_NONBLOCK; + + if (blocking != flags && + fcntl(fd, F_SETFL, blocking) == -1) + return MAD_FLOW_BREAK; + + result = receive_io(fd, buffer, len); + + if (flags != blocking && + fcntl(fd, F_SETFL, flags) == -1) + return MAD_FLOW_BREAK; + + return result; +} + +static +enum mad_flow send(int fd, void const *message, unsigned int size) +{ + enum mad_flow result; + + /* send size */ + + result = send_io(fd, &size, sizeof(size)); + + /* send message */ + + if (result == MAD_FLOW_CONTINUE) + result = send_io(fd, message, size); + + return result; +} + +static +enum mad_flow receive(int fd, void **message, unsigned int *size) +{ + enum mad_flow result; + unsigned int actual; + + if (*message == 0) + *size = 0; + + /* receive size */ + + result = receive_io(fd, &actual, sizeof(actual)); + + /* receive message */ + + if (result == MAD_FLOW_CONTINUE) { + if (actual > *size) + actual -= *size; + else { + *size = actual; + actual = 0; + } + + if (*size > 0) { + if (*message == 0) { + *message = malloc(*size); + if (*message == 0) + return MAD_FLOW_BREAK; + } + + result = receive_io_blocking(fd, *message, *size); + } + + /* throw away remainder of message */ + + while (actual && result == MAD_FLOW_CONTINUE) { + char sink[256]; + unsigned int len; + + len = actual > sizeof(sink) ? sizeof(sink) : actual; + + result = receive_io_blocking(fd, sink, len); + + actual -= len; + } + } + + return result; +} + +static +enum mad_flow check_message(struct mad_decoder *decoder) +{ + enum mad_flow result; + void *message = 0; + unsigned int size; + + result = receive(decoder->async.in, &message, &size); + + if (result == MAD_FLOW_CONTINUE) { + if (decoder->message_func == 0) + size = 0; + else { + result = decoder->message_func(decoder->cb_data, message, &size); + + if (result == MAD_FLOW_IGNORE || + result == MAD_FLOW_BREAK) + size = 0; + } + + if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE) + result = MAD_FLOW_BREAK; + } + + if (message) + free(message); + + return result; +} +# endif + +static +enum mad_flow error_default(void *data, struct mad_stream *stream, + struct mad_frame *frame) +{ + int *bad_last_frame = data; + + switch (stream->error) { + case MAD_ERROR_BADCRC: + if (*bad_last_frame) + mad_frame_mute(frame); + else + *bad_last_frame = 1; + + return MAD_FLOW_IGNORE; + + default: + return MAD_FLOW_CONTINUE; + } +} + +static +int run_sync(struct mad_decoder *decoder) +{ + enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); + void *error_data; + int bad_last_frame = 0; + struct mad_stream *stream; + struct mad_frame *frame; + struct mad_synth *synth; + int result = 0; + + if (decoder->input_func == 0) + return 0; + + if (decoder->error_func) { + error_func = decoder->error_func; + error_data = decoder->cb_data; + } + else { + error_func = error_default; + error_data = &bad_last_frame; + } + + stream = &decoder->sync->stream; + frame = &decoder->sync->frame; + synth = &decoder->sync->synth; + + mad_stream_init(stream); + mad_frame_init(frame); + mad_synth_init(synth); + + mad_stream_options(stream, decoder->options); + + do { + switch (decoder->input_func(decoder->cb_data, stream)) { + case MAD_FLOW_STOP: + goto done; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_IGNORE: + continue; + case MAD_FLOW_CONTINUE: + break; + } + + while (1) + { + #if defined(USE_ASYNC) + if (decoder->mode == MAD_DECODER_MODE_ASYNC) { + switch (check_message(decoder)) { + case MAD_FLOW_IGNORE: + case MAD_FLOW_CONTINUE: + break; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_STOP: + goto done; + } + } + #endif + + if (decoder->header_func) + { + if (mad_header_decode(&frame->header, stream) == -1) + { + if (!MAD_RECOVERABLE(stream->error)) + { + break; + } + + switch (error_func(error_data, stream, frame)) + { + case MAD_FLOW_STOP: + goto done; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_IGNORE: + case MAD_FLOW_CONTINUE: + default: + continue; + } + } + + switch (decoder->header_func(decoder->cb_data, &frame->header)) + { + case MAD_FLOW_STOP: + goto done; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_IGNORE: + continue; + case MAD_FLOW_CONTINUE: + break; + } + } + + if (mad_frame_decode(frame, stream) == -1) + { + if (!MAD_RECOVERABLE(stream->error)) + break; + + switch (error_func(error_data, stream, frame)) + { + case MAD_FLOW_STOP: + goto done; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_IGNORE: + break; + case MAD_FLOW_CONTINUE: + default: + continue; + } + } else + { + bad_last_frame = 0; + } + + if (decoder->filter_func) + { + switch (decoder->filter_func(decoder->cb_data, stream, frame)) + { + case MAD_FLOW_STOP: + goto done; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_IGNORE: + continue; + case MAD_FLOW_CONTINUE: + break; + } + } + + mad_synth_frame(synth, frame); + + if (decoder->output_func) + { + switch (decoder->output_func(decoder->cb_data, + &frame->header, &synth->pcm)) + { + case MAD_FLOW_STOP: + goto done; + case MAD_FLOW_BREAK: + goto fail; + case MAD_FLOW_IGNORE: + case MAD_FLOW_CONTINUE: + break; + } + } + } + } + while (stream->error == MAD_ERROR_BUFLEN); + +fail: + result = -1; + +done: + mad_synth_finish(synth); + mad_frame_finish(frame); + mad_stream_finish(stream); + + return result; +} + +# if defined(USE_ASYNC) +static +int run_async(struct mad_decoder *decoder) +{ + pid_t pid; + int ptoc[2], ctop[2], flags; + + if (pipe(ptoc) == -1) + return -1; + + if (pipe(ctop) == -1) { + close(ptoc[0]); + close(ptoc[1]); + return -1; + } + + flags = fcntl(ptoc[0], F_GETFL); + if (flags == -1 || + fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) { + close(ctop[0]); + close(ctop[1]); + close(ptoc[0]); + close(ptoc[1]); + return -1; + } + + pid = fork(); + if (pid == -1) { + close(ctop[0]); + close(ctop[1]); + close(ptoc[0]); + close(ptoc[1]); + return -1; + } + + decoder->async.pid = pid; + + if (pid) { + /* parent */ + + close(ptoc[0]); + close(ctop[1]); + + decoder->async.in = ctop[0]; + decoder->async.out = ptoc[1]; + + return 0; + } + + /* child */ + + close(ptoc[1]); + close(ctop[0]); + + decoder->async.in = ptoc[0]; + decoder->async.out = ctop[1]; + + _exit(run_sync(decoder)); + + /* not reached */ + return -1; +} +# endif + +/* + * NAME: decoder->run() + * DESCRIPTION: run the decoder thread either synchronously or asynchronously + */ +int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode) +{ + int result; + int (*run)(struct mad_decoder *) = 0; + + switch (decoder->mode = mode) { + case MAD_DECODER_MODE_SYNC: + run = run_sync; + break; + + case MAD_DECODER_MODE_ASYNC: +# if defined(USE_ASYNC) + run = run_async; +# endif + break; + } + + if (run == 0) + return -1; + + decoder->sync = malloc(sizeof(*decoder->sync)); + if (decoder->sync == 0) + return -1; + + result = run(decoder); + + free(decoder->sync); + decoder->sync = 0; + + return result; +} + +/* + * NAME: decoder->message() + * DESCRIPTION: send a message to and receive a reply from the decoder process + */ +int mad_decoder_message(struct mad_decoder *decoder, + void *message, unsigned int *len) +{ +# if defined(USE_ASYNC) + if (decoder->mode != MAD_DECODER_MODE_ASYNC || + send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE || + receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE) + return -1; + + return 0; +# else + return -1; +# endif +} diff --git a/code/libmad/fixed.c b/code/libmad/fixed.c new file mode 100644 index 00000000..3e4055f8 --- /dev/null +++ b/code/libmad/fixed.c @@ -0,0 +1,77 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: fixed.c,v 1.13 2004/01/23 09:41:32 rob Exp $ + */ + +# include "global.h" + +# include "mad.h" + +/* + * NAME: fixed->abs() + * DESCRIPTION: return absolute value of a fixed-point number + */ +mad_fixed_t mad_f_abs(mad_fixed_t x) +{ + return x < 0 ? -x : x; +} + +/* + * NAME: fixed->div() + * DESCRIPTION: perform division using fixed-point math + */ +mad_fixed_t mad_f_div(mad_fixed_t x, mad_fixed_t y) +{ + mad_fixed_t q, r; + unsigned int bits; + + q = mad_f_abs(x / y); + + if (x < 0) { + x = -x; + y = -y; + } + + r = x % y; + + if (y < 0) { + x = -x; + y = -y; + } + + if (q > mad_f_intpart(MAD_F_MAX) && + !(q == -mad_f_intpart(MAD_F_MIN) && r == 0 && (x < 0) != (y < 0))) + return 0; + + for (bits = MAD_F_FRACBITS; bits && r; --bits) { + q <<= 1, r <<= 1; + if (r >= y) + r -= y, ++q; + } + + /* round */ + if (2 * r >= y) + ++q; + + /* fix sign */ + if ((x < 0) != (y < 0)) + q = -q; + + return q << bits; +} diff --git a/code/libmad/frame.c b/code/libmad/frame.c new file mode 100644 index 00000000..03c94bfe --- /dev/null +++ b/code/libmad/frame.c @@ -0,0 +1,510 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: frame.c,v 1.29 2004/02/04 22:59:19 rob Exp $ + */ + +# include "global.h" + +# include + +# include "mad.h" +# include "layer12.h" +# include "layer3.h" + +static +unsigned long const bitrate_table[5][15] = { + /* MPEG-1 */ + { 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, /* Layer I */ + 256000, 288000, 320000, 352000, 384000, 416000, 448000 }, + { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer II */ + 128000, 160000, 192000, 224000, 256000, 320000, 384000 }, + { 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, /* Layer III */ + 112000, 128000, 160000, 192000, 224000, 256000, 320000 }, + + /* MPEG-2 LSF */ + { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer I */ + 128000, 144000, 160000, 176000, 192000, 224000, 256000 }, + { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, /* Layers */ + 64000, 80000, 96000, 112000, 128000, 144000, 160000 } /* II & III */ +}; + +static +unsigned int const samplerate_table[3] = { 44100, 48000, 32000 }; + +static +int (*const decoder_table[3])(struct mad_stream *, struct mad_frame *) = { + mad_layer_I, + mad_layer_II, + mad_layer_III +}; + +/* + * NAME: header->init() + * DESCRIPTION: initialize header struct + */ +void mad_header_init(struct mad_header *header) +{ + header->layer = 0; + header->mode = 0; + header->mode_extension = 0; + header->emphasis = 0; + + header->bitrate = 0; + header->samplerate = 0; + + header->crc_check = 0; + header->crc_target = 0; + + header->flags = 0; + header->private_bits = 0; + + header->duration = mad_timer_zero; +} + +/* + * NAME: frame->init() + * DESCRIPTION: initialize frame struct + */ +void mad_frame_init(struct mad_frame *frame) +{ + mad_header_init(&frame->header); + + frame->options = 0; + + frame->overlap = 0; + mad_frame_mute(frame); +} + +/* + * NAME: frame->finish() + * DESCRIPTION: deallocate any dynamic memory associated with frame + */ +void mad_frame_finish(struct mad_frame *frame) +{ + mad_header_finish(&frame->header); + + if (frame->overlap) { + free(frame->overlap); + frame->overlap = 0; + } +} + +/* + * NAME: decode_header() + * DESCRIPTION: read header data and following CRC word + */ +static +int decode_header(struct mad_header *header, struct mad_stream *stream) +{ + unsigned int index; + struct mad_bitptr bufend_ptr; + + header->flags = 0; + header->private_bits = 0; + + mad_bit_init(&bufend_ptr, stream->bufend); + + /* header() */ + if (mad_bit_length(&stream->ptr, &bufend_ptr) < 32) { + stream->error = MAD_ERROR_BUFLEN; + return -1; + } + + /* syncword */ + mad_bit_skip(&stream->ptr, 11); + + /* MPEG 2.5 indicator (really part of syncword) */ + if (mad_bit_read(&stream->ptr, 1) == 0) + header->flags |= MAD_FLAG_MPEG_2_5_EXT; + + /* ID */ + if (mad_bit_read(&stream->ptr, 1) == 0) + header->flags |= MAD_FLAG_LSF_EXT; + else if (header->flags & MAD_FLAG_MPEG_2_5_EXT) { + stream->error = MAD_ERROR_LOSTSYNC; + return -1; + } + + /* layer */ + header->layer = 4 - mad_bit_read(&stream->ptr, 2); + + if (header->layer == 4) { + stream->error = MAD_ERROR_BADLAYER; + return -1; + } + + /* protection_bit */ + if (mad_bit_read(&stream->ptr, 1) == 0) { + header->flags |= MAD_FLAG_PROTECTION; + header->crc_check = mad_bit_crc(stream->ptr, 16, 0xffff); + } + + /* bitrate_index */ + index = mad_bit_read(&stream->ptr, 4); + + if (index == 15) { + stream->error = MAD_ERROR_BADBITRATE; + return -1; + } + + if (header->flags & MAD_FLAG_LSF_EXT) + header->bitrate = bitrate_table[3 + (header->layer >> 1)][index]; + else + header->bitrate = bitrate_table[header->layer - 1][index]; + + /* sampling_frequency */ + index = mad_bit_read(&stream->ptr, 2); + + if (index == 3) { + stream->error = MAD_ERROR_BADSAMPLERATE; + return -1; + } + + header->samplerate = samplerate_table[index]; + + if (header->flags & MAD_FLAG_LSF_EXT) { + header->samplerate /= 2; + + if (header->flags & MAD_FLAG_MPEG_2_5_EXT) + header->samplerate /= 2; + } + + /* padding_bit */ + if (mad_bit_read(&stream->ptr, 1)) + header->flags |= MAD_FLAG_PADDING; + + /* private_bit */ + if (mad_bit_read(&stream->ptr, 1)) + header->private_bits |= MAD_PRIVATE_HEADER; + + /* mode */ + header->mode = 3 - mad_bit_read(&stream->ptr, 2); + + /* mode_extension */ + header->mode_extension = mad_bit_read(&stream->ptr, 2); + + /* copyright */ + if (mad_bit_read(&stream->ptr, 1)) + header->flags |= MAD_FLAG_COPYRIGHT; + + /* original/copy */ + if (mad_bit_read(&stream->ptr, 1)) + header->flags |= MAD_FLAG_ORIGINAL; + + /* emphasis */ + header->emphasis = mad_bit_read(&stream->ptr, 2); + +# if defined(OPT_STRICT) + /* + * ISO/IEC 11172-3 says this is a reserved emphasis value, but + * streams exist which use it anyway. Since the value is not important + * to the decoder proper, we allow it unless OPT_STRICT is defined. + */ + if (header->emphasis == MAD_EMPHASIS_RESERVED) { + stream->error = MAD_ERROR_BADEMPHASIS; + return -1; + } +# endif + + /* error_check() */ + + /* crc_check */ + if (header->flags & MAD_FLAG_PROTECTION) { + if (mad_bit_length(&stream->ptr, &bufend_ptr) < 16) { + stream->error = MAD_ERROR_BUFLEN; + return -1; + } + header->crc_target = mad_bit_read(&stream->ptr, 16); + } + + return 0; +} + +/* + * NAME: free_bitrate() + * DESCRIPTION: attempt to discover the bitstream's free bitrate + */ +static +int free_bitrate(struct mad_stream *stream, struct mad_header const *header) +{ + struct mad_bitptr keep_ptr; + unsigned long rate = 0; + unsigned int pad_slot, slots_per_frame; + unsigned char const *ptr = 0; + + keep_ptr = stream->ptr; + + pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0; + slots_per_frame = (header->layer == MAD_LAYER_III && + (header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144; + + while (mad_stream_sync(stream) == 0) { + struct mad_stream peek_stream; + struct mad_header peek_header; + + peek_stream = *stream; + peek_header = *header; + + if (decode_header(&peek_header, &peek_stream) == 0 && + peek_header.layer == header->layer && + peek_header.samplerate == header->samplerate) { + unsigned int N; + + ptr = mad_bit_nextbyte(&stream->ptr); + + N = ptr - stream->this_frame; + + if (header->layer == MAD_LAYER_I) { + rate = (unsigned long) header->samplerate * + (N - 4 * pad_slot + 4) / 48 / 1000; + } + else { + rate = (unsigned long) header->samplerate * + (N - pad_slot + 1) / slots_per_frame / 1000; + } + + if (rate >= 8) + break; + } + + mad_bit_skip(&stream->ptr, 8); + } + + stream->ptr = keep_ptr; + + if (rate < 8 || (header->layer == MAD_LAYER_III && rate > 640)) { + stream->error = MAD_ERROR_LOSTSYNC; + return -1; + } + + stream->freerate = rate * 1000; + + return 0; +} + +/* + * NAME: header->decode() + * DESCRIPTION: read the next frame header from the stream + */ +int mad_header_decode(struct mad_header *header, struct mad_stream *stream) +{ + register unsigned char const *ptr, *end; + unsigned int pad_slot, N; + + ptr = stream->next_frame; + end = stream->bufend; + + if (ptr == 0) { + stream->error = MAD_ERROR_BUFPTR; + goto fail; + } + + /* stream skip */ + if (stream->skiplen) { + if (!stream->sync) + ptr = stream->this_frame; + + if (end - ptr < stream->skiplen) { + stream->skiplen -= end - ptr; + stream->next_frame = end; + + stream->error = MAD_ERROR_BUFLEN; + goto fail; + } + + ptr += stream->skiplen; + stream->skiplen = 0; + + stream->sync = 1; + } + + sync: + /* synchronize */ + if (stream->sync) { + if (end - ptr < MAD_BUFFER_GUARD) { + stream->next_frame = ptr; + + stream->error = MAD_ERROR_BUFLEN; + goto fail; + } + else if ((end - ptr >= 2) && !(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) { + /* mark point where frame sync word was expected */ + stream->this_frame = ptr; + stream->next_frame = ptr + 1; + + stream->error = MAD_ERROR_LOSTSYNC; + goto fail; + } + } + else { + mad_bit_init(&stream->ptr, ptr); + + if (mad_stream_sync(stream) == -1) { + if (end - stream->next_frame >= MAD_BUFFER_GUARD) + stream->next_frame = end - MAD_BUFFER_GUARD; + + stream->error = MAD_ERROR_BUFLEN; + goto fail; + } + + ptr = mad_bit_nextbyte(&stream->ptr); + } + + stream->error = MAD_ERROR_NONE; + + /* begin processing */ + stream->this_frame = ptr; + stream->next_frame = ptr + 1; /* possibly bogus sync word */ + + mad_bit_init(&stream->ptr, stream->this_frame); + + if (decode_header(header, stream) == -1) + goto fail; + + /* calculate frame duration */ + mad_timer_set(&header->duration, 0, + 32 * MAD_NSBSAMPLES(header), header->samplerate); + + /* calculate free bit rate */ + if (header->bitrate == 0) { + if ((stream->freerate == 0 || !stream->sync || + (header->layer == MAD_LAYER_III && stream->freerate > 640000)) && + free_bitrate(stream, header) == -1) + goto fail; + + header->bitrate = stream->freerate; + header->flags |= MAD_FLAG_FREEFORMAT; + } + + /* calculate beginning of next frame */ + pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0; + + if (header->layer == MAD_LAYER_I) + N = ((12 * header->bitrate / header->samplerate) + pad_slot) * 4; + else { + unsigned int slots_per_frame; + + slots_per_frame = (header->layer == MAD_LAYER_III && + (header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144; + + N = (slots_per_frame * header->bitrate / header->samplerate) + pad_slot; + } + + /* verify there is enough data left in buffer to decode this frame */ + if (N + MAD_BUFFER_GUARD > end - stream->this_frame) { + stream->next_frame = stream->this_frame; + + stream->error = MAD_ERROR_BUFLEN; + goto fail; + } + + stream->next_frame = stream->this_frame + N; + + if (!stream->sync) { + /* check that a valid frame header follows this frame */ + + ptr = stream->next_frame; + if ((end - ptr >= 2) && !(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) { + ptr = stream->next_frame = stream->this_frame + 1; + goto sync; + } + + stream->sync = 1; + } + + header->flags |= MAD_FLAG_INCOMPLETE; + + return 0; + + fail: + stream->sync = 0; + + return -1; +} + +/* + * NAME: frame->decode() + * DESCRIPTION: decode a single frame from a bitstream + */ +int mad_frame_decode(struct mad_frame *frame, struct mad_stream *stream) +{ + frame->options = stream->options; + + /* header() */ + /* error_check() */ + + if (!(frame->header.flags & MAD_FLAG_INCOMPLETE) && + mad_header_decode(&frame->header, stream) == -1) + goto fail; + + /* audio_data() */ + + frame->header.flags &= ~MAD_FLAG_INCOMPLETE; + + if (decoder_table[frame->header.layer - 1](stream, frame) == -1) { + if (!MAD_RECOVERABLE(stream->error)) + stream->next_frame = stream->this_frame; + + goto fail; + } + + /* ancillary_data() */ + + if (frame->header.layer != MAD_LAYER_III) { + struct mad_bitptr next_frame; + + mad_bit_init(&next_frame, stream->next_frame); + + stream->anc_ptr = stream->ptr; + stream->anc_bitlen = mad_bit_length(&stream->ptr, &next_frame); + + mad_bit_finish(&next_frame); + } + + return 0; + + fail: + stream->anc_bitlen = 0; + return -1; +} + +/* + * NAME: frame->mute() + * DESCRIPTION: zero all subband values so the frame becomes silent + */ +void mad_frame_mute(struct mad_frame *frame) +{ + unsigned int s, sb; + + for (s = 0; s < 36; ++s) { + for (sb = 0; sb < 32; ++sb) { + frame->sbsample[0][s][sb] = + frame->sbsample[1][s][sb] = 0; + } + } + + if (frame->overlap) { + for (s = 0; s < 18; ++s) { + for (sb = 0; sb < 32; ++sb) { + (*frame->overlap)[0][sb][s] = + (*frame->overlap)[1][sb][s] = 0; + } + } + } +} diff --git a/code/libmad/global.h b/code/libmad/global.h new file mode 100644 index 00000000..a6debfd8 --- /dev/null +++ b/code/libmad/global.h @@ -0,0 +1,58 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: global.h,v 1.11 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBMAD_GLOBAL_H +# define LIBMAD_GLOBAL_H + +/* conditional debugging */ + +# if defined(DEBUG) && defined(NDEBUG) +# error "cannot define both DEBUG and NDEBUG" +# endif + +# if defined(DEBUG) +# include +# endif + +/* conditional features */ + +# if defined(OPT_SPEED) && defined(OPT_ACCURACY) +# error "cannot optimize for both speed and accuracy" +# endif + +# if defined(OPT_SPEED) && !defined(OPT_SSO) +# define OPT_SSO +# endif + +# if defined(HAVE_UNISTD_H) && defined(HAVE_WAITPID) && \ + defined(HAVE_FCNTL) && defined(HAVE_PIPE) && defined(HAVE_FORK) +# define USE_ASYNC +# endif + +# if !defined(HAVE_ASSERT_H) +# if defined(NDEBUG) +# define assert(x) /* nothing */ +# else +# define assert(x) do { if (!(x)) abort(); } while (0) +# endif +# endif + +# endif diff --git a/code/libmad/huffman.c b/code/libmad/huffman.c new file mode 100644 index 00000000..9050c700 --- /dev/null +++ b/code/libmad/huffman.c @@ -0,0 +1,3105 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: huffman.c,v 1.10 2004/01/23 09:41:32 rob Exp $ + */ + +# include "global.h" + +# include "huffman.h" + +/* + * These are the Huffman code words for Layer III. + * The data for these tables are derived from Table B.7 of ISO/IEC 11172-3. + * + * These tables support decoding up to 4 Huffman code bits at a time. + */ + +# if defined(__GNUC__) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +# define PTR(offs, bits) { .ptr = { 0, bits, offs } } +# define V(v, w, x, y, hlen) { .value = { 1, hlen, v, w, x, y } } +# else +# define PTR(offs, bits) { { 0, bits, offs } } +# if defined(WORDS_BIGENDIAN) +# define V(v, w, x, y, hlen) { { 1, hlen, (v << 11) | (w << 10) | \ + (x << 9) | (y << 8) } } +# else +# define V(v, w, x, y, hlen) { { 1, hlen, (v << 0) | (w << 1) | \ + (x << 2) | (y << 3) } } +# endif +# endif + +static +union huffquad const hufftabA[] = { + /* 0000 */ PTR(16, 2), + /* 0001 */ PTR(20, 2), + /* 0010 */ PTR(24, 1), + /* 0011 */ PTR(26, 1), + /* 0100 */ V(0, 0, 1, 0, 4), + /* 0101 */ V(0, 0, 0, 1, 4), + /* 0110 */ V(0, 1, 0, 0, 4), + /* 0111 */ V(1, 0, 0, 0, 4), + /* 1000 */ V(0, 0, 0, 0, 1), + /* 1001 */ V(0, 0, 0, 0, 1), + /* 1010 */ V(0, 0, 0, 0, 1), + /* 1011 */ V(0, 0, 0, 0, 1), + /* 1100 */ V(0, 0, 0, 0, 1), + /* 1101 */ V(0, 0, 0, 0, 1), + /* 1110 */ V(0, 0, 0, 0, 1), + /* 1111 */ V(0, 0, 0, 0, 1), + + /* 0000 ... */ + /* 00 */ V(1, 0, 1, 1, 2), /* 16 */ + /* 01 */ V(1, 1, 1, 1, 2), + /* 10 */ V(1, 1, 0, 1, 2), + /* 11 */ V(1, 1, 1, 0, 2), + + /* 0001 ... */ + /* 00 */ V(0, 1, 1, 1, 2), /* 20 */ + /* 01 */ V(0, 1, 0, 1, 2), + /* 10 */ V(1, 0, 0, 1, 1), + /* 11 */ V(1, 0, 0, 1, 1), + + /* 0010 ... */ + /* 0 */ V(0, 1, 1, 0, 1), /* 24 */ + /* 1 */ V(0, 0, 1, 1, 1), + + /* 0011 ... */ + /* 0 */ V(1, 0, 1, 0, 1), /* 26 */ + /* 1 */ V(1, 1, 0, 0, 1) +}; + +static +union huffquad const hufftabB[] = { + /* 0000 */ V(1, 1, 1, 1, 4), + /* 0001 */ V(1, 1, 1, 0, 4), + /* 0010 */ V(1, 1, 0, 1, 4), + /* 0011 */ V(1, 1, 0, 0, 4), + /* 0100 */ V(1, 0, 1, 1, 4), + /* 0101 */ V(1, 0, 1, 0, 4), + /* 0110 */ V(1, 0, 0, 1, 4), + /* 0111 */ V(1, 0, 0, 0, 4), + /* 1000 */ V(0, 1, 1, 1, 4), + /* 1001 */ V(0, 1, 1, 0, 4), + /* 1010 */ V(0, 1, 0, 1, 4), + /* 1011 */ V(0, 1, 0, 0, 4), + /* 1100 */ V(0, 0, 1, 1, 4), + /* 1101 */ V(0, 0, 1, 0, 4), + /* 1110 */ V(0, 0, 0, 1, 4), + /* 1111 */ V(0, 0, 0, 0, 4) +}; + +# undef V +# undef PTR + +# if defined(__GNUC__) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +# define PTR(offs, bits) { .ptr = { 0, bits, offs } } +# define V(x, y, hlen) { .value = { 1, hlen, x, y } } +# else +# define PTR(offs, bits) { { 0, bits, offs } } +# if defined(WORDS_BIGENDIAN) +# define V(x, y, hlen) { { 1, hlen, (x << 8) | (y << 4) } } +# else +# define V(x, y, hlen) { { 1, hlen, (x << 0) | (y << 4) } } +# endif +# endif + +static +union huffpair const hufftab0[] = { + /* */ V(0, 0, 0) +}; + +static +union huffpair const hufftab1[] = { + /* 000 */ V(1, 1, 3), + /* 001 */ V(0, 1, 3), + /* 010 */ V(1, 0, 2), + /* 011 */ V(1, 0, 2), + /* 100 */ V(0, 0, 1), + /* 101 */ V(0, 0, 1), + /* 110 */ V(0, 0, 1), + /* 111 */ V(0, 0, 1) +}; + +static +union huffpair const hufftab2[] = { + /* 000 */ PTR(8, 3), + /* 001 */ V(1, 1, 3), + /* 010 */ V(0, 1, 3), + /* 011 */ V(1, 0, 3), + /* 100 */ V(0, 0, 1), + /* 101 */ V(0, 0, 1), + /* 110 */ V(0, 0, 1), + /* 111 */ V(0, 0, 1), + + /* 000 ... */ + /* 000 */ V(2, 2, 3), /* 8 */ + /* 001 */ V(0, 2, 3), + /* 010 */ V(1, 2, 2), + /* 011 */ V(1, 2, 2), + /* 100 */ V(2, 1, 2), + /* 101 */ V(2, 1, 2), + /* 110 */ V(2, 0, 2), + /* 111 */ V(2, 0, 2) +}; + +static +union huffpair const hufftab3[] = { + /* 000 */ PTR(8, 3), + /* 001 */ V(1, 0, 3), + /* 010 */ V(1, 1, 2), + /* 011 */ V(1, 1, 2), + /* 100 */ V(0, 1, 2), + /* 101 */ V(0, 1, 2), + /* 110 */ V(0, 0, 2), + /* 111 */ V(0, 0, 2), + + /* 000 ... */ + /* 000 */ V(2, 2, 3), /* 8 */ + /* 001 */ V(0, 2, 3), + /* 010 */ V(1, 2, 2), + /* 011 */ V(1, 2, 2), + /* 100 */ V(2, 1, 2), + /* 101 */ V(2, 1, 2), + /* 110 */ V(2, 0, 2), + /* 111 */ V(2, 0, 2) +}; + +static +union huffpair const hufftab5[] = { + /* 000 */ PTR(8, 4), + /* 001 */ V(1, 1, 3), + /* 010 */ V(0, 1, 3), + /* 011 */ V(1, 0, 3), + /* 100 */ V(0, 0, 1), + /* 101 */ V(0, 0, 1), + /* 110 */ V(0, 0, 1), + /* 111 */ V(0, 0, 1), + + /* 000 ... */ + /* 0000 */ PTR(24, 1), /* 8 */ + /* 0001 */ V(3, 2, 4), + /* 0010 */ V(3, 1, 3), + /* 0011 */ V(3, 1, 3), + /* 0100 */ V(1, 3, 4), + /* 0101 */ V(0, 3, 4), + /* 0110 */ V(3, 0, 4), + /* 0111 */ V(2, 2, 4), + /* 1000 */ V(1, 2, 3), + /* 1001 */ V(1, 2, 3), + /* 1010 */ V(2, 1, 3), + /* 1011 */ V(2, 1, 3), + /* 1100 */ V(0, 2, 3), + /* 1101 */ V(0, 2, 3), + /* 1110 */ V(2, 0, 3), + /* 1111 */ V(2, 0, 3), + + /* 000 0000 ... */ + /* 0 */ V(3, 3, 1), /* 24 */ + /* 1 */ V(2, 3, 1) +}; + +static +union huffpair const hufftab6[] = { + /* 0000 */ PTR(16, 3), + /* 0001 */ PTR(24, 1), + /* 0010 */ PTR(26, 1), + /* 0011 */ V(1, 2, 4), + /* 0100 */ V(2, 1, 4), + /* 0101 */ V(2, 0, 4), + /* 0110 */ V(0, 1, 3), + /* 0111 */ V(0, 1, 3), + /* 1000 */ V(1, 1, 2), + /* 1001 */ V(1, 1, 2), + /* 1010 */ V(1, 1, 2), + /* 1011 */ V(1, 1, 2), + /* 1100 */ V(1, 0, 3), + /* 1101 */ V(1, 0, 3), + /* 1110 */ V(0, 0, 3), + /* 1111 */ V(0, 0, 3), + + /* 0000 ... */ + /* 000 */ V(3, 3, 3), /* 16 */ + /* 001 */ V(0, 3, 3), + /* 010 */ V(2, 3, 2), + /* 011 */ V(2, 3, 2), + /* 100 */ V(3, 2, 2), + /* 101 */ V(3, 2, 2), + /* 110 */ V(3, 0, 2), + /* 111 */ V(3, 0, 2), + + /* 0001 ... */ + /* 0 */ V(1, 3, 1), /* 24 */ + /* 1 */ V(3, 1, 1), + + /* 0010 ... */ + /* 0 */ V(2, 2, 1), /* 26 */ + /* 1 */ V(0, 2, 1) +}; + +static +union huffpair const hufftab7[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 2), + /* 0011 */ V(1, 1, 4), + /* 0100 */ V(0, 1, 3), + /* 0101 */ V(0, 1, 3), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(52, 2), /* 16 */ + /* 0001 */ PTR(56, 1), + /* 0010 */ PTR(58, 1), + /* 0011 */ V(1, 5, 4), + /* 0100 */ V(5, 1, 4), + /* 0101 */ PTR(60, 1), + /* 0110 */ V(5, 0, 4), + /* 0111 */ PTR(62, 1), + /* 1000 */ V(2, 4, 4), + /* 1001 */ V(4, 2, 4), + /* 1010 */ V(1, 4, 3), + /* 1011 */ V(1, 4, 3), + /* 1100 */ V(4, 1, 3), + /* 1101 */ V(4, 1, 3), + /* 1110 */ V(4, 0, 3), + /* 1111 */ V(4, 0, 3), + + /* 0001 ... */ + /* 0000 */ V(0, 4, 4), /* 32 */ + /* 0001 */ V(2, 3, 4), + /* 0010 */ V(3, 2, 4), + /* 0011 */ V(0, 3, 4), + /* 0100 */ V(1, 3, 3), + /* 0101 */ V(1, 3, 3), + /* 0110 */ V(3, 1, 3), + /* 0111 */ V(3, 1, 3), + /* 1000 */ V(3, 0, 3), + /* 1001 */ V(3, 0, 3), + /* 1010 */ V(2, 2, 3), + /* 1011 */ V(2, 2, 3), + /* 1100 */ V(1, 2, 2), + /* 1101 */ V(1, 2, 2), + /* 1110 */ V(1, 2, 2), + /* 1111 */ V(1, 2, 2), + + /* 0010 ... */ + /* 00 */ V(2, 1, 1), /* 48 */ + /* 01 */ V(2, 1, 1), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 00 */ V(5, 5, 2), /* 52 */ + /* 01 */ V(4, 5, 2), + /* 10 */ V(5, 4, 2), + /* 11 */ V(5, 3, 2), + + /* 0000 0001 ... */ + /* 0 */ V(3, 5, 1), /* 56 */ + /* 1 */ V(4, 4, 1), + + /* 0000 0010 ... */ + /* 0 */ V(2, 5, 1), /* 58 */ + /* 1 */ V(5, 2, 1), + + /* 0000 0101 ... */ + /* 0 */ V(0, 5, 1), /* 60 */ + /* 1 */ V(3, 4, 1), + + /* 0000 0111 ... */ + /* 0 */ V(4, 3, 1), /* 62 */ + /* 1 */ V(3, 3, 1) +}; + +# if 0 +/* this version saves 8 entries (16 bytes) at the expense of + an extra lookup in 4 out of 36 cases */ +static +union huffpair const hufftab8[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 2), + /* 0010 */ V(1, 2, 4), + /* 0011 */ V(2, 1, 4), + /* 0100 */ V(1, 1, 2), + /* 0101 */ V(1, 1, 2), + /* 0110 */ V(1, 1, 2), + /* 0111 */ V(1, 1, 2), + /* 1000 */ V(0, 1, 3), + /* 1001 */ V(0, 1, 3), + /* 1010 */ V(1, 0, 3), + /* 1011 */ V(1, 0, 3), + /* 1100 */ V(0, 0, 2), + /* 1101 */ V(0, 0, 2), + /* 1110 */ V(0, 0, 2), + /* 1111 */ V(0, 0, 2), + + /* 0000 ... */ + /* 0000 */ PTR(36, 3), /* 16 */ + /* 0001 */ PTR(44, 2), + /* 0010 */ PTR(48, 1), + /* 0011 */ V(1, 5, 4), + /* 0100 */ V(5, 1, 4), + /* 0101 */ PTR(50, 1), + /* 0110 */ PTR(52, 1), + /* 0111 */ V(2, 4, 4), + /* 1000 */ V(4, 2, 4), + /* 1001 */ V(1, 4, 4), + /* 1010 */ V(4, 1, 3), + /* 1011 */ V(4, 1, 3), + /* 1100 */ V(0, 4, 4), + /* 1101 */ V(4, 0, 4), + /* 1110 */ V(2, 3, 4), + /* 1111 */ V(3, 2, 4), + + /* 0001 ... */ + /* 00 */ PTR(54, 2), /* 32 */ + /* 01 */ V(2, 2, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(5, 5, 3), /* 36 */ + /* 001 */ V(5, 4, 3), + /* 010 */ V(4, 5, 2), + /* 011 */ V(4, 5, 2), + /* 100 */ V(5, 3, 1), + /* 101 */ V(5, 3, 1), + /* 110 */ V(5, 3, 1), + /* 111 */ V(5, 3, 1), + + /* 0000 0001 ... */ + /* 00 */ V(3, 5, 2), /* 44 */ + /* 01 */ V(4, 4, 2), + /* 10 */ V(2, 5, 1), + /* 11 */ V(2, 5, 1), + + /* 0000 0010 ... */ + /* 0 */ V(5, 2, 1), /* 48 */ + /* 1 */ V(0, 5, 1), + + /* 0000 0101 ... */ + /* 0 */ V(3, 4, 1), /* 50 */ + /* 1 */ V(4, 3, 1), + + /* 0000 0110 ... */ + /* 0 */ V(5, 0, 1), /* 52 */ + /* 1 */ V(3, 3, 1), + + /* 0001 00 ... */ + /* 00 */ V(1, 3, 2), /* 54 */ + /* 01 */ V(3, 1, 2), + /* 10 */ V(0, 3, 2), + /* 11 */ V(3, 0, 2), +}; +# else +static +union huffpair const hufftab8[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ V(1, 2, 4), + /* 0011 */ V(2, 1, 4), + /* 0100 */ V(1, 1, 2), + /* 0101 */ V(1, 1, 2), + /* 0110 */ V(1, 1, 2), + /* 0111 */ V(1, 1, 2), + /* 1000 */ V(0, 1, 3), + /* 1001 */ V(0, 1, 3), + /* 1010 */ V(1, 0, 3), + /* 1011 */ V(1, 0, 3), + /* 1100 */ V(0, 0, 2), + /* 1101 */ V(0, 0, 2), + /* 1110 */ V(0, 0, 2), + /* 1111 */ V(0, 0, 2), + + /* 0000 ... */ + /* 0000 */ PTR(48, 3), /* 16 */ + /* 0001 */ PTR(56, 2), + /* 0010 */ PTR(60, 1), + /* 0011 */ V(1, 5, 4), + /* 0100 */ V(5, 1, 4), + /* 0101 */ PTR(62, 1), + /* 0110 */ PTR(64, 1), + /* 0111 */ V(2, 4, 4), + /* 1000 */ V(4, 2, 4), + /* 1001 */ V(1, 4, 4), + /* 1010 */ V(4, 1, 3), + /* 1011 */ V(4, 1, 3), + /* 1100 */ V(0, 4, 4), + /* 1101 */ V(4, 0, 4), + /* 1110 */ V(2, 3, 4), + /* 1111 */ V(3, 2, 4), + + /* 0001 ... */ + /* 0000 */ V(1, 3, 4), /* 32 */ + /* 0001 */ V(3, 1, 4), + /* 0010 */ V(0, 3, 4), + /* 0011 */ V(3, 0, 4), + /* 0100 */ V(2, 2, 2), + /* 0101 */ V(2, 2, 2), + /* 0110 */ V(2, 2, 2), + /* 0111 */ V(2, 2, 2), + /* 1000 */ V(0, 2, 2), + /* 1001 */ V(0, 2, 2), + /* 1010 */ V(0, 2, 2), + /* 1011 */ V(0, 2, 2), + /* 1100 */ V(2, 0, 2), + /* 1101 */ V(2, 0, 2), + /* 1110 */ V(2, 0, 2), + /* 1111 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(5, 5, 3), /* 48 */ + /* 001 */ V(5, 4, 3), + /* 010 */ V(4, 5, 2), + /* 011 */ V(4, 5, 2), + /* 100 */ V(5, 3, 1), + /* 101 */ V(5, 3, 1), + /* 110 */ V(5, 3, 1), + /* 111 */ V(5, 3, 1), + + /* 0000 0001 ... */ + /* 00 */ V(3, 5, 2), /* 56 */ + /* 01 */ V(4, 4, 2), + /* 10 */ V(2, 5, 1), + /* 11 */ V(2, 5, 1), + + /* 0000 0010 ... */ + /* 0 */ V(5, 2, 1), /* 60 */ + /* 1 */ V(0, 5, 1), + + /* 0000 0101 ... */ + /* 0 */ V(3, 4, 1), /* 62 */ + /* 1 */ V(4, 3, 1), + + /* 0000 0110 ... */ + /* 0 */ V(5, 0, 1), /* 64 */ + /* 1 */ V(3, 3, 1) +}; +# endif + +static +union huffpair const hufftab9[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 3), + /* 0010 */ PTR(40, 2), + /* 0011 */ PTR(44, 2), + /* 0100 */ PTR(48, 1), + /* 0101 */ V(1, 2, 4), + /* 0110 */ V(2, 1, 4), + /* 0111 */ V(2, 0, 4), + /* 1000 */ V(1, 1, 3), + /* 1001 */ V(1, 1, 3), + /* 1010 */ V(0, 1, 3), + /* 1011 */ V(0, 1, 3), + /* 1100 */ V(1, 0, 3), + /* 1101 */ V(1, 0, 3), + /* 1110 */ V(0, 0, 3), + /* 1111 */ V(0, 0, 3), + + /* 0000 ... */ + /* 0000 */ PTR(50, 1), /* 16 */ + /* 0001 */ V(3, 5, 4), + /* 0010 */ V(5, 3, 4), + /* 0011 */ PTR(52, 1), + /* 0100 */ V(4, 4, 4), + /* 0101 */ V(2, 5, 4), + /* 0110 */ V(5, 2, 4), + /* 0111 */ V(1, 5, 4), + /* 1000 */ V(5, 1, 3), + /* 1001 */ V(5, 1, 3), + /* 1010 */ V(3, 4, 3), + /* 1011 */ V(3, 4, 3), + /* 1100 */ V(4, 3, 3), + /* 1101 */ V(4, 3, 3), + /* 1110 */ V(5, 0, 4), + /* 1111 */ V(0, 4, 4), + + /* 0001 ... */ + /* 000 */ V(2, 4, 3), /* 32 */ + /* 001 */ V(4, 2, 3), + /* 010 */ V(3, 3, 3), + /* 011 */ V(4, 0, 3), + /* 100 */ V(1, 4, 2), + /* 101 */ V(1, 4, 2), + /* 110 */ V(4, 1, 2), + /* 111 */ V(4, 1, 2), + + /* 0010 ... */ + /* 00 */ V(2, 3, 2), /* 40 */ + /* 01 */ V(3, 2, 2), + /* 10 */ V(1, 3, 1), + /* 11 */ V(1, 3, 1), + + /* 0011 ... */ + /* 00 */ V(3, 1, 1), /* 44 */ + /* 01 */ V(3, 1, 1), + /* 10 */ V(0, 3, 2), + /* 11 */ V(3, 0, 2), + + /* 0100 ... */ + /* 0 */ V(2, 2, 1), /* 48 */ + /* 1 */ V(0, 2, 1), + + /* 0000 0000 ... */ + /* 0 */ V(5, 5, 1), /* 50 */ + /* 1 */ V(4, 5, 1), + + /* 0000 0011 ... */ + /* 0 */ V(5, 4, 1), /* 52 */ + /* 1 */ V(0, 5, 1) +}; + +static +union huffpair const hufftab10[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 2), + /* 0011 */ V(1, 1, 4), + /* 0100 */ V(0, 1, 3), + /* 0101 */ V(0, 1, 3), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(52, 3), /* 16 */ + /* 0001 */ PTR(60, 2), + /* 0010 */ PTR(64, 3), + /* 0011 */ PTR(72, 1), + /* 0100 */ PTR(74, 2), + /* 0101 */ PTR(78, 2), + /* 0110 */ PTR(82, 2), + /* 0111 */ V(1, 7, 4), + /* 1000 */ V(7, 1, 4), + /* 1001 */ PTR(86, 1), + /* 1010 */ PTR(88, 2), + /* 1011 */ PTR(92, 2), + /* 1100 */ V(1, 6, 4), + /* 1101 */ V(6, 1, 4), + /* 1110 */ V(6, 0, 4), + /* 1111 */ PTR(96, 1), + + /* 0001 ... */ + /* 0000 */ PTR(98, 1), /* 32 */ + /* 0001 */ PTR(100, 1), + /* 0010 */ V(1, 4, 4), + /* 0011 */ V(4, 1, 4), + /* 0100 */ V(4, 0, 4), + /* 0101 */ V(2, 3, 4), + /* 0110 */ V(3, 2, 4), + /* 0111 */ V(0, 3, 4), + /* 1000 */ V(1, 3, 3), + /* 1001 */ V(1, 3, 3), + /* 1010 */ V(3, 1, 3), + /* 1011 */ V(3, 1, 3), + /* 1100 */ V(3, 0, 3), + /* 1101 */ V(3, 0, 3), + /* 1110 */ V(2, 2, 3), + /* 1111 */ V(2, 2, 3), + + /* 0010 ... */ + /* 00 */ V(1, 2, 2), /* 48 */ + /* 01 */ V(2, 1, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(7, 7, 3), /* 52 */ + /* 001 */ V(6, 7, 3), + /* 010 */ V(7, 6, 3), + /* 011 */ V(5, 7, 3), + /* 100 */ V(7, 5, 3), + /* 101 */ V(6, 6, 3), + /* 110 */ V(4, 7, 2), + /* 111 */ V(4, 7, 2), + + /* 0000 0001 ... */ + /* 00 */ V(7, 4, 2), /* 60 */ + /* 01 */ V(5, 6, 2), + /* 10 */ V(6, 5, 2), + /* 11 */ V(3, 7, 2), + + /* 0000 0010 ... */ + /* 000 */ V(7, 3, 2), /* 64 */ + /* 001 */ V(7, 3, 2), + /* 010 */ V(4, 6, 2), + /* 011 */ V(4, 6, 2), + /* 100 */ V(5, 5, 3), + /* 101 */ V(5, 4, 3), + /* 110 */ V(6, 3, 2), + /* 111 */ V(6, 3, 2), + + /* 0000 0011 ... */ + /* 0 */ V(2, 7, 1), /* 72 */ + /* 1 */ V(7, 2, 1), + + /* 0000 0100 ... */ + /* 00 */ V(6, 4, 2), /* 74 */ + /* 01 */ V(0, 7, 2), + /* 10 */ V(7, 0, 1), + /* 11 */ V(7, 0, 1), + + /* 0000 0101 ... */ + /* 00 */ V(6, 2, 1), /* 78 */ + /* 01 */ V(6, 2, 1), + /* 10 */ V(4, 5, 2), + /* 11 */ V(3, 5, 2), + + /* 0000 0110 ... */ + /* 00 */ V(0, 6, 1), /* 82 */ + /* 01 */ V(0, 6, 1), + /* 10 */ V(5, 3, 2), + /* 11 */ V(4, 4, 2), + + /* 0000 1001 ... */ + /* 0 */ V(3, 6, 1), /* 86 */ + /* 1 */ V(2, 6, 1), + + /* 0000 1010 ... */ + /* 00 */ V(2, 5, 2), /* 88 */ + /* 01 */ V(5, 2, 2), + /* 10 */ V(1, 5, 1), + /* 11 */ V(1, 5, 1), + + /* 0000 1011 ... */ + /* 00 */ V(5, 1, 1), /* 92 */ + /* 01 */ V(5, 1, 1), + /* 10 */ V(3, 4, 2), + /* 11 */ V(4, 3, 2), + + /* 0000 1111 ... */ + /* 0 */ V(0, 5, 1), /* 96 */ + /* 1 */ V(5, 0, 1), + + /* 0001 0000 ... */ + /* 0 */ V(2, 4, 1), /* 98 */ + /* 1 */ V(4, 2, 1), + + /* 0001 0001 ... */ + /* 0 */ V(3, 3, 1), /* 100 */ + /* 1 */ V(0, 4, 1) +}; + +static +union huffpair const hufftab11[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 3), + /* 0100 */ V(1, 2, 4), + /* 0101 */ PTR(72, 1), + /* 0110 */ V(1, 1, 3), + /* 0111 */ V(1, 1, 3), + /* 1000 */ V(0, 1, 3), + /* 1001 */ V(0, 1, 3), + /* 1010 */ V(1, 0, 3), + /* 1011 */ V(1, 0, 3), + /* 1100 */ V(0, 0, 2), + /* 1101 */ V(0, 0, 2), + /* 1110 */ V(0, 0, 2), + /* 1111 */ V(0, 0, 2), + + /* 0000 ... */ + /* 0000 */ PTR(74, 2), /* 16 */ + /* 0001 */ PTR(78, 3), + /* 0010 */ PTR(86, 2), + /* 0011 */ PTR(90, 1), + /* 0100 */ PTR(92, 2), + /* 0101 */ V(2, 7, 4), + /* 0110 */ V(7, 2, 4), + /* 0111 */ PTR(96, 1), + /* 1000 */ V(7, 1, 3), + /* 1001 */ V(7, 1, 3), + /* 1010 */ V(1, 7, 4), + /* 1011 */ V(7, 0, 4), + /* 1100 */ V(3, 6, 4), + /* 1101 */ V(6, 3, 4), + /* 1110 */ V(6, 0, 4), + /* 1111 */ PTR(98, 1), + + /* 0001 ... */ + /* 0000 */ PTR(100, 1), /* 32 */ + /* 0001 */ V(1, 5, 4), + /* 0010 */ V(6, 2, 3), + /* 0011 */ V(6, 2, 3), + /* 0100 */ V(2, 6, 4), + /* 0101 */ V(0, 6, 4), + /* 0110 */ V(1, 6, 3), + /* 0111 */ V(1, 6, 3), + /* 1000 */ V(6, 1, 3), + /* 1001 */ V(6, 1, 3), + /* 1010 */ V(5, 1, 4), + /* 1011 */ V(3, 4, 4), + /* 1100 */ V(5, 0, 4), + /* 1101 */ PTR(102, 1), + /* 1110 */ V(2, 4, 4), + /* 1111 */ V(4, 2, 4), + + /* 0010 ... */ + /* 0000 */ V(1, 4, 4), /* 48 */ + /* 0001 */ V(4, 1, 4), + /* 0010 */ V(0, 4, 4), + /* 0011 */ V(4, 0, 4), + /* 0100 */ V(2, 3, 3), + /* 0101 */ V(2, 3, 3), + /* 0110 */ V(3, 2, 3), + /* 0111 */ V(3, 2, 3), + /* 1000 */ V(1, 3, 2), + /* 1001 */ V(1, 3, 2), + /* 1010 */ V(1, 3, 2), + /* 1011 */ V(1, 3, 2), + /* 1100 */ V(3, 1, 2), + /* 1101 */ V(3, 1, 2), + /* 1110 */ V(3, 1, 2), + /* 1111 */ V(3, 1, 2), + + /* 0011 ... */ + /* 000 */ V(0, 3, 3), /* 64 */ + /* 001 */ V(3, 0, 3), + /* 010 */ V(2, 2, 2), + /* 011 */ V(2, 2, 2), + /* 100 */ V(2, 1, 1), + /* 101 */ V(2, 1, 1), + /* 110 */ V(2, 1, 1), + /* 111 */ V(2, 1, 1), + + /* 0101 ... */ + /* 0 */ V(0, 2, 1), /* 72 */ + /* 1 */ V(2, 0, 1), + + /* 0000 0000 ... */ + /* 00 */ V(7, 7, 2), /* 74 */ + /* 01 */ V(6, 7, 2), + /* 10 */ V(7, 6, 2), + /* 11 */ V(7, 5, 2), + + /* 0000 0001 ... */ + /* 000 */ V(6, 6, 2), /* 78 */ + /* 001 */ V(6, 6, 2), + /* 010 */ V(4, 7, 2), + /* 011 */ V(4, 7, 2), + /* 100 */ V(7, 4, 2), + /* 101 */ V(7, 4, 2), + /* 110 */ V(5, 7, 3), + /* 111 */ V(5, 5, 3), + + /* 0000 0010 ... */ + /* 00 */ V(5, 6, 2), /* 86 */ + /* 01 */ V(6, 5, 2), + /* 10 */ V(3, 7, 1), + /* 11 */ V(3, 7, 1), + + /* 0000 0011 ... */ + /* 0 */ V(7, 3, 1), /* 90 */ + /* 1 */ V(4, 6, 1), + + /* 0000 0100 ... */ + /* 00 */ V(4, 5, 2), /* 92 */ + /* 01 */ V(5, 4, 2), + /* 10 */ V(3, 5, 2), + /* 11 */ V(5, 3, 2), + + /* 0000 0111 ... */ + /* 0 */ V(6, 4, 1), /* 96 */ + /* 1 */ V(0, 7, 1), + + /* 0000 1111 ... */ + /* 0 */ V(4, 4, 1), /* 98 */ + /* 1 */ V(2, 5, 1), + + /* 0001 0000 ... */ + /* 0 */ V(5, 2, 1), /* 100 */ + /* 1 */ V(0, 5, 1), + + /* 0001 1101 ... */ + /* 0 */ V(4, 3, 1), /* 102 */ + /* 1 */ V(3, 3, 1) +}; + +static +union huffpair const hufftab12[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 2), + /* 0100 */ PTR(68, 3), + /* 0101 */ PTR(76, 1), + /* 0110 */ V(1, 2, 4), + /* 0111 */ V(2, 1, 4), + /* 1000 */ PTR(78, 1), + /* 1001 */ V(0, 0, 4), + /* 1010 */ V(1, 1, 3), + /* 1011 */ V(1, 1, 3), + /* 1100 */ V(0, 1, 3), + /* 1101 */ V(0, 1, 3), + /* 1110 */ V(1, 0, 3), + /* 1111 */ V(1, 0, 3), + + /* 0000 ... */ + /* 0000 */ PTR(80, 2), /* 16 */ + /* 0001 */ PTR(84, 1), + /* 0010 */ PTR(86, 1), + /* 0011 */ PTR(88, 1), + /* 0100 */ V(5, 6, 4), + /* 0101 */ V(3, 7, 4), + /* 0110 */ PTR(90, 1), + /* 0111 */ V(2, 7, 4), + /* 1000 */ V(7, 2, 4), + /* 1001 */ V(4, 6, 4), + /* 1010 */ V(6, 4, 4), + /* 1011 */ V(1, 7, 4), + /* 1100 */ V(7, 1, 4), + /* 1101 */ PTR(92, 1), + /* 1110 */ V(3, 6, 4), + /* 1111 */ V(6, 3, 4), + + /* 0001 ... */ + /* 0000 */ V(4, 5, 4), /* 32 */ + /* 0001 */ V(5, 4, 4), + /* 0010 */ V(4, 4, 4), + /* 0011 */ PTR(94, 1), + /* 0100 */ V(2, 6, 3), + /* 0101 */ V(2, 6, 3), + /* 0110 */ V(6, 2, 3), + /* 0111 */ V(6, 2, 3), + /* 1000 */ V(6, 1, 3), + /* 1001 */ V(6, 1, 3), + /* 1010 */ V(1, 6, 4), + /* 1011 */ V(6, 0, 4), + /* 1100 */ V(3, 5, 4), + /* 1101 */ V(5, 3, 4), + /* 1110 */ V(2, 5, 4), + /* 1111 */ V(5, 2, 4), + + /* 0010 ... */ + /* 0000 */ V(1, 5, 3), /* 48 */ + /* 0001 */ V(1, 5, 3), + /* 0010 */ V(5, 1, 3), + /* 0011 */ V(5, 1, 3), + /* 0100 */ V(3, 4, 3), + /* 0101 */ V(3, 4, 3), + /* 0110 */ V(4, 3, 3), + /* 0111 */ V(4, 3, 3), + /* 1000 */ V(5, 0, 4), + /* 1001 */ V(0, 4, 4), + /* 1010 */ V(2, 4, 3), + /* 1011 */ V(2, 4, 3), + /* 1100 */ V(4, 2, 3), + /* 1101 */ V(4, 2, 3), + /* 1110 */ V(1, 4, 3), + /* 1111 */ V(1, 4, 3), + + /* 0011 ... */ + /* 00 */ V(3, 3, 2), /* 64 */ + /* 01 */ V(4, 1, 2), + /* 10 */ V(2, 3, 2), + /* 11 */ V(3, 2, 2), + + /* 0100 ... */ + /* 000 */ V(4, 0, 3), /* 68 */ + /* 001 */ V(0, 3, 3), + /* 010 */ V(3, 0, 2), + /* 011 */ V(3, 0, 2), + /* 100 */ V(1, 3, 1), + /* 101 */ V(1, 3, 1), + /* 110 */ V(1, 3, 1), + /* 111 */ V(1, 3, 1), + + /* 0101 ... */ + /* 0 */ V(3, 1, 1), /* 76 */ + /* 1 */ V(2, 2, 1), + + /* 1000 ... */ + /* 0 */ V(0, 2, 1), /* 78 */ + /* 1 */ V(2, 0, 1), + + /* 0000 0000 ... */ + /* 00 */ V(7, 7, 2), /* 80 */ + /* 01 */ V(6, 7, 2), + /* 10 */ V(7, 6, 1), + /* 11 */ V(7, 6, 1), + + /* 0000 0001 ... */ + /* 0 */ V(5, 7, 1), /* 84 */ + /* 1 */ V(7, 5, 1), + + /* 0000 0010 ... */ + /* 0 */ V(6, 6, 1), /* 86 */ + /* 1 */ V(4, 7, 1), + + /* 0000 0011 ... */ + /* 0 */ V(7, 4, 1), /* 88 */ + /* 1 */ V(6, 5, 1), + + /* 0000 0110 ... */ + /* 0 */ V(7, 3, 1), /* 90 */ + /* 1 */ V(5, 5, 1), + + /* 0000 1101 ... */ + /* 0 */ V(0, 7, 1), /* 92 */ + /* 1 */ V(7, 0, 1), + + /* 0001 0011 ... */ + /* 0 */ V(0, 6, 1), /* 94 */ + /* 1 */ V(0, 5, 1) +}; + +static +union huffpair const hufftab13[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 2), + /* 0100 */ V(1, 1, 4), + /* 0101 */ V(0, 1, 4), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(68, 4), /* 16 */ + /* 0001 */ PTR(84, 4), + /* 0010 */ PTR(100, 4), + /* 0011 */ PTR(116, 4), + /* 0100 */ PTR(132, 4), + /* 0101 */ PTR(148, 4), + /* 0110 */ PTR(164, 3), + /* 0111 */ PTR(172, 3), + /* 1000 */ PTR(180, 3), + /* 1001 */ PTR(188, 3), + /* 1010 */ PTR(196, 3), + /* 1011 */ PTR(204, 3), + /* 1100 */ PTR(212, 1), + /* 1101 */ PTR(214, 2), + /* 1110 */ PTR(218, 3), + /* 1111 */ PTR(226, 1), + + /* 0001 ... */ + /* 0000 */ PTR(228, 2), /* 32 */ + /* 0001 */ PTR(232, 2), + /* 0010 */ PTR(236, 2), + /* 0011 */ PTR(240, 2), + /* 0100 */ V(8, 1, 4), + /* 0101 */ PTR(244, 1), + /* 0110 */ PTR(246, 1), + /* 0111 */ PTR(248, 1), + /* 1000 */ PTR(250, 2), + /* 1001 */ PTR(254, 1), + /* 1010 */ V(1, 5, 4), + /* 1011 */ V(5, 1, 4), + /* 1100 */ PTR(256, 1), + /* 1101 */ PTR(258, 1), + /* 1110 */ PTR(260, 1), + /* 1111 */ V(1, 4, 4), + + /* 0010 ... */ + /* 0000 */ V(4, 1, 3), /* 48 */ + /* 0001 */ V(4, 1, 3), + /* 0010 */ V(0, 4, 4), + /* 0011 */ V(4, 0, 4), + /* 0100 */ V(2, 3, 4), + /* 0101 */ V(3, 2, 4), + /* 0110 */ V(1, 3, 3), + /* 0111 */ V(1, 3, 3), + /* 1000 */ V(3, 1, 3), + /* 1001 */ V(3, 1, 3), + /* 1010 */ V(0, 3, 3), + /* 1011 */ V(0, 3, 3), + /* 1100 */ V(3, 0, 3), + /* 1101 */ V(3, 0, 3), + /* 1110 */ V(2, 2, 3), + /* 1111 */ V(2, 2, 3), + + /* 0011 ... */ + /* 00 */ V(1, 2, 2), /* 64 */ + /* 01 */ V(2, 1, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 0000 */ PTR(262, 4), /* 68 */ + /* 0001 */ PTR(278, 4), + /* 0010 */ PTR(294, 4), + /* 0011 */ PTR(310, 3), + /* 0100 */ PTR(318, 2), + /* 0101 */ PTR(322, 2), + /* 0110 */ PTR(326, 3), + /* 0111 */ PTR(334, 2), + /* 1000 */ PTR(338, 1), + /* 1001 */ PTR(340, 2), + /* 1010 */ PTR(344, 2), + /* 1011 */ PTR(348, 2), + /* 1100 */ PTR(352, 2), + /* 1101 */ PTR(356, 2), + /* 1110 */ V(1, 15, 4), + /* 1111 */ V(15, 1, 4), + + /* 0000 0001 ... */ + /* 0000 */ V(15, 0, 4), /* 84 */ + /* 0001 */ PTR(360, 1), + /* 0010 */ PTR(362, 1), + /* 0011 */ PTR(364, 1), + /* 0100 */ V(14, 2, 4), + /* 0101 */ PTR(366, 1), + /* 0110 */ V(1, 14, 4), + /* 0111 */ V(14, 1, 4), + /* 1000 */ PTR(368, 1), + /* 1001 */ PTR(370, 1), + /* 1010 */ PTR(372, 1), + /* 1011 */ PTR(374, 1), + /* 1100 */ PTR(376, 1), + /* 1101 */ PTR(378, 1), + /* 1110 */ V(12, 6, 4), + /* 1111 */ V(3, 13, 4), + + /* 0000 0010 ... */ + /* 0000 */ PTR(380, 1), /* 100 */ + /* 0001 */ V(2, 13, 4), + /* 0010 */ V(13, 2, 4), + /* 0011 */ V(1, 13, 4), + /* 0100 */ V(11, 7, 4), + /* 0101 */ PTR(382, 1), + /* 0110 */ PTR(384, 1), + /* 0111 */ V(12, 3, 4), + /* 1000 */ PTR(386, 1), + /* 1001 */ V(4, 11, 4), + /* 1010 */ V(13, 1, 3), + /* 1011 */ V(13, 1, 3), + /* 1100 */ V(0, 13, 4), + /* 1101 */ V(13, 0, 4), + /* 1110 */ V(8, 10, 4), + /* 1111 */ V(10, 8, 4), + + /* 0000 0011 ... */ + /* 0000 */ V(4, 12, 4), /* 116 */ + /* 0001 */ V(12, 4, 4), + /* 0010 */ V(6, 11, 4), + /* 0011 */ V(11, 6, 4), + /* 0100 */ V(3, 12, 3), + /* 0101 */ V(3, 12, 3), + /* 0110 */ V(2, 12, 3), + /* 0111 */ V(2, 12, 3), + /* 1000 */ V(12, 2, 3), + /* 1001 */ V(12, 2, 3), + /* 1010 */ V(5, 11, 3), + /* 1011 */ V(5, 11, 3), + /* 1100 */ V(11, 5, 4), + /* 1101 */ V(8, 9, 4), + /* 1110 */ V(1, 12, 3), + /* 1111 */ V(1, 12, 3), + + /* 0000 0100 ... */ + /* 0000 */ V(12, 1, 3), /* 132 */ + /* 0001 */ V(12, 1, 3), + /* 0010 */ V(9, 8, 4), + /* 0011 */ V(0, 12, 4), + /* 0100 */ V(12, 0, 3), + /* 0101 */ V(12, 0, 3), + /* 0110 */ V(11, 4, 4), + /* 0111 */ V(6, 10, 4), + /* 1000 */ V(10, 6, 4), + /* 1001 */ V(7, 9, 4), + /* 1010 */ V(3, 11, 3), + /* 1011 */ V(3, 11, 3), + /* 1100 */ V(11, 3, 3), + /* 1101 */ V(11, 3, 3), + /* 1110 */ V(8, 8, 4), + /* 1111 */ V(5, 10, 4), + + /* 0000 0101 ... */ + /* 0000 */ V(2, 11, 3), /* 148 */ + /* 0001 */ V(2, 11, 3), + /* 0010 */ V(10, 5, 4), + /* 0011 */ V(6, 9, 4), + /* 0100 */ V(10, 4, 3), + /* 0101 */ V(10, 4, 3), + /* 0110 */ V(7, 8, 4), + /* 0111 */ V(8, 7, 4), + /* 1000 */ V(9, 4, 3), + /* 1001 */ V(9, 4, 3), + /* 1010 */ V(7, 7, 4), + /* 1011 */ V(7, 6, 4), + /* 1100 */ V(11, 2, 2), + /* 1101 */ V(11, 2, 2), + /* 1110 */ V(11, 2, 2), + /* 1111 */ V(11, 2, 2), + + /* 0000 0110 ... */ + /* 000 */ V(1, 11, 2), /* 164 */ + /* 001 */ V(1, 11, 2), + /* 010 */ V(11, 1, 2), + /* 011 */ V(11, 1, 2), + /* 100 */ V(0, 11, 3), + /* 101 */ V(11, 0, 3), + /* 110 */ V(9, 6, 3), + /* 111 */ V(4, 10, 3), + + /* 0000 0111 ... */ + /* 000 */ V(3, 10, 3), /* 172 */ + /* 001 */ V(10, 3, 3), + /* 010 */ V(5, 9, 3), + /* 011 */ V(9, 5, 3), + /* 100 */ V(2, 10, 2), + /* 101 */ V(2, 10, 2), + /* 110 */ V(10, 2, 2), + /* 111 */ V(10, 2, 2), + + /* 0000 1000 ... */ + /* 000 */ V(1, 10, 2), /* 180 */ + /* 001 */ V(1, 10, 2), + /* 010 */ V(10, 1, 2), + /* 011 */ V(10, 1, 2), + /* 100 */ V(0, 10, 3), + /* 101 */ V(6, 8, 3), + /* 110 */ V(10, 0, 2), + /* 111 */ V(10, 0, 2), + + /* 0000 1001 ... */ + /* 000 */ V(8, 6, 3), /* 188 */ + /* 001 */ V(4, 9, 3), + /* 010 */ V(9, 3, 2), + /* 011 */ V(9, 3, 2), + /* 100 */ V(3, 9, 3), + /* 101 */ V(5, 8, 3), + /* 110 */ V(8, 5, 3), + /* 111 */ V(6, 7, 3), + + /* 0000 1010 ... */ + /* 000 */ V(2, 9, 2), /* 196 */ + /* 001 */ V(2, 9, 2), + /* 010 */ V(9, 2, 2), + /* 011 */ V(9, 2, 2), + /* 100 */ V(5, 7, 3), + /* 101 */ V(7, 5, 3), + /* 110 */ V(3, 8, 2), + /* 111 */ V(3, 8, 2), + + /* 0000 1011 ... */ + /* 000 */ V(8, 3, 2), /* 204 */ + /* 001 */ V(8, 3, 2), + /* 010 */ V(6, 6, 3), + /* 011 */ V(4, 7, 3), + /* 100 */ V(7, 4, 3), + /* 101 */ V(5, 6, 3), + /* 110 */ V(6, 5, 3), + /* 111 */ V(7, 3, 3), + + /* 0000 1100 ... */ + /* 0 */ V(1, 9, 1), /* 212 */ + /* 1 */ V(9, 1, 1), + + /* 0000 1101 ... */ + /* 00 */ V(0, 9, 2), /* 214 */ + /* 01 */ V(9, 0, 2), + /* 10 */ V(4, 8, 2), + /* 11 */ V(8, 4, 2), + + /* 0000 1110 ... */ + /* 000 */ V(7, 2, 2), /* 218 */ + /* 001 */ V(7, 2, 2), + /* 010 */ V(4, 6, 3), + /* 011 */ V(6, 4, 3), + /* 100 */ V(2, 8, 1), + /* 101 */ V(2, 8, 1), + /* 110 */ V(2, 8, 1), + /* 111 */ V(2, 8, 1), + + /* 0000 1111 ... */ + /* 0 */ V(8, 2, 1), /* 226 */ + /* 1 */ V(1, 8, 1), + + /* 0001 0000 ... */ + /* 00 */ V(3, 7, 2), /* 228 */ + /* 01 */ V(2, 7, 2), + /* 10 */ V(1, 7, 1), + /* 11 */ V(1, 7, 1), + + /* 0001 0001 ... */ + /* 00 */ V(7, 1, 1), /* 232 */ + /* 01 */ V(7, 1, 1), + /* 10 */ V(5, 5, 2), + /* 11 */ V(0, 7, 2), + + /* 0001 0010 ... */ + /* 00 */ V(7, 0, 2), /* 236 */ + /* 01 */ V(3, 6, 2), + /* 10 */ V(6, 3, 2), + /* 11 */ V(4, 5, 2), + + /* 0001 0011 ... */ + /* 00 */ V(5, 4, 2), /* 240 */ + /* 01 */ V(2, 6, 2), + /* 10 */ V(6, 2, 2), + /* 11 */ V(3, 5, 2), + + /* 0001 0101 ... */ + /* 0 */ V(0, 8, 1), /* 244 */ + /* 1 */ V(8, 0, 1), + + /* 0001 0110 ... */ + /* 0 */ V(1, 6, 1), /* 246 */ + /* 1 */ V(6, 1, 1), + + /* 0001 0111 ... */ + /* 0 */ V(0, 6, 1), /* 248 */ + /* 1 */ V(6, 0, 1), + + /* 0001 1000 ... */ + /* 00 */ V(5, 3, 2), /* 250 */ + /* 01 */ V(4, 4, 2), + /* 10 */ V(2, 5, 1), + /* 11 */ V(2, 5, 1), + + /* 0001 1001 ... */ + /* 0 */ V(5, 2, 1), /* 254 */ + /* 1 */ V(0, 5, 1), + + /* 0001 1100 ... */ + /* 0 */ V(3, 4, 1), /* 256 */ + /* 1 */ V(4, 3, 1), + + /* 0001 1101 ... */ + /* 0 */ V(5, 0, 1), /* 258 */ + /* 1 */ V(2, 4, 1), + + /* 0001 1110 ... */ + /* 0 */ V(4, 2, 1), /* 260 */ + /* 1 */ V(3, 3, 1), + + /* 0000 0000 0000 ... */ + /* 0000 */ PTR(388, 3), /* 262 */ + /* 0001 */ V(15, 15, 4), + /* 0010 */ V(14, 15, 4), + /* 0011 */ V(13, 15, 4), + /* 0100 */ V(14, 14, 4), + /* 0101 */ V(12, 15, 4), + /* 0110 */ V(13, 14, 4), + /* 0111 */ V(11, 15, 4), + /* 1000 */ V(15, 11, 4), + /* 1001 */ V(12, 14, 4), + /* 1010 */ V(13, 12, 4), + /* 1011 */ PTR(396, 1), + /* 1100 */ V(14, 12, 3), + /* 1101 */ V(14, 12, 3), + /* 1110 */ V(13, 13, 3), + /* 1111 */ V(13, 13, 3), + + /* 0000 0000 0001 ... */ + /* 0000 */ V(15, 10, 4), /* 278 */ + /* 0001 */ V(12, 13, 4), + /* 0010 */ V(11, 14, 3), + /* 0011 */ V(11, 14, 3), + /* 0100 */ V(14, 11, 3), + /* 0101 */ V(14, 11, 3), + /* 0110 */ V(9, 15, 3), + /* 0111 */ V(9, 15, 3), + /* 1000 */ V(15, 9, 3), + /* 1001 */ V(15, 9, 3), + /* 1010 */ V(14, 10, 3), + /* 1011 */ V(14, 10, 3), + /* 1100 */ V(11, 13, 3), + /* 1101 */ V(11, 13, 3), + /* 1110 */ V(13, 11, 3), + /* 1111 */ V(13, 11, 3), + + /* 0000 0000 0010 ... */ + /* 0000 */ V(8, 15, 3), /* 294 */ + /* 0001 */ V(8, 15, 3), + /* 0010 */ V(15, 8, 3), + /* 0011 */ V(15, 8, 3), + /* 0100 */ V(12, 12, 3), + /* 0101 */ V(12, 12, 3), + /* 0110 */ V(10, 14, 4), + /* 0111 */ V(9, 14, 4), + /* 1000 */ V(8, 14, 3), + /* 1001 */ V(8, 14, 3), + /* 1010 */ V(7, 15, 4), + /* 1011 */ V(7, 14, 4), + /* 1100 */ V(15, 7, 2), + /* 1101 */ V(15, 7, 2), + /* 1110 */ V(15, 7, 2), + /* 1111 */ V(15, 7, 2), + + /* 0000 0000 0011 ... */ + /* 000 */ V(13, 10, 2), /* 310 */ + /* 001 */ V(13, 10, 2), + /* 010 */ V(10, 13, 3), + /* 011 */ V(11, 12, 3), + /* 100 */ V(12, 11, 3), + /* 101 */ V(15, 6, 3), + /* 110 */ V(6, 15, 2), + /* 111 */ V(6, 15, 2), + + /* 0000 0000 0100 ... */ + /* 00 */ V(14, 8, 2), /* 318 */ + /* 01 */ V(5, 15, 2), + /* 10 */ V(9, 13, 2), + /* 11 */ V(13, 9, 2), + + /* 0000 0000 0101 ... */ + /* 00 */ V(15, 5, 2), /* 322 */ + /* 01 */ V(14, 7, 2), + /* 10 */ V(10, 12, 2), + /* 11 */ V(11, 11, 2), + + /* 0000 0000 0110 ... */ + /* 000 */ V(4, 15, 2), /* 326 */ + /* 001 */ V(4, 15, 2), + /* 010 */ V(15, 4, 2), + /* 011 */ V(15, 4, 2), + /* 100 */ V(12, 10, 3), + /* 101 */ V(14, 6, 3), + /* 110 */ V(15, 3, 2), + /* 111 */ V(15, 3, 2), + + /* 0000 0000 0111 ... */ + /* 00 */ V(3, 15, 1), /* 334 */ + /* 01 */ V(3, 15, 1), + /* 10 */ V(8, 13, 2), + /* 11 */ V(13, 8, 2), + + /* 0000 0000 1000 ... */ + /* 0 */ V(2, 15, 1), /* 338 */ + /* 1 */ V(15, 2, 1), + + /* 0000 0000 1001 ... */ + /* 00 */ V(6, 14, 2), /* 340 */ + /* 01 */ V(9, 12, 2), + /* 10 */ V(0, 15, 1), + /* 11 */ V(0, 15, 1), + + /* 0000 0000 1010 ... */ + /* 00 */ V(12, 9, 2), /* 344 */ + /* 01 */ V(5, 14, 2), + /* 10 */ V(10, 11, 1), + /* 11 */ V(10, 11, 1), + + /* 0000 0000 1011 ... */ + /* 00 */ V(7, 13, 2), /* 348 */ + /* 01 */ V(13, 7, 2), + /* 10 */ V(4, 14, 1), + /* 11 */ V(4, 14, 1), + + /* 0000 0000 1100 ... */ + /* 00 */ V(12, 8, 2), /* 352 */ + /* 01 */ V(13, 6, 2), + /* 10 */ V(3, 14, 1), + /* 11 */ V(3, 14, 1), + + /* 0000 0000 1101 ... */ + /* 00 */ V(11, 9, 1), /* 356 */ + /* 01 */ V(11, 9, 1), + /* 10 */ V(9, 11, 2), + /* 11 */ V(10, 10, 2), + + /* 0000 0001 0001 ... */ + /* 0 */ V(11, 10, 1), /* 360 */ + /* 1 */ V(14, 5, 1), + + /* 0000 0001 0010 ... */ + /* 0 */ V(14, 4, 1), /* 362 */ + /* 1 */ V(8, 12, 1), + + /* 0000 0001 0011 ... */ + /* 0 */ V(6, 13, 1), /* 364 */ + /* 1 */ V(14, 3, 1), + + /* 0000 0001 0101 ... */ + /* 0 */ V(2, 14, 1), /* 366 */ + /* 1 */ V(0, 14, 1), + + /* 0000 0001 1000 ... */ + /* 0 */ V(14, 0, 1), /* 368 */ + /* 1 */ V(5, 13, 1), + + /* 0000 0001 1001 ... */ + /* 0 */ V(13, 5, 1), /* 370 */ + /* 1 */ V(7, 12, 1), + + /* 0000 0001 1010 ... */ + /* 0 */ V(12, 7, 1), /* 372 */ + /* 1 */ V(4, 13, 1), + + /* 0000 0001 1011 ... */ + /* 0 */ V(8, 11, 1), /* 374 */ + /* 1 */ V(11, 8, 1), + + /* 0000 0001 1100 ... */ + /* 0 */ V(13, 4, 1), /* 376 */ + /* 1 */ V(9, 10, 1), + + /* 0000 0001 1101 ... */ + /* 0 */ V(10, 9, 1), /* 378 */ + /* 1 */ V(6, 12, 1), + + /* 0000 0010 0000 ... */ + /* 0 */ V(13, 3, 1), /* 380 */ + /* 1 */ V(7, 11, 1), + + /* 0000 0010 0101 ... */ + /* 0 */ V(5, 12, 1), /* 382 */ + /* 1 */ V(12, 5, 1), + + /* 0000 0010 0110 ... */ + /* 0 */ V(9, 9, 1), /* 384 */ + /* 1 */ V(7, 10, 1), + + /* 0000 0010 1000 ... */ + /* 0 */ V(10, 7, 1), /* 386 */ + /* 1 */ V(9, 7, 1), + + /* 0000 0000 0000 0000 ... */ + /* 000 */ V(15, 14, 3), /* 388 */ + /* 001 */ V(15, 12, 3), + /* 010 */ V(15, 13, 2), + /* 011 */ V(15, 13, 2), + /* 100 */ V(14, 13, 1), + /* 101 */ V(14, 13, 1), + /* 110 */ V(14, 13, 1), + /* 111 */ V(14, 13, 1), + + /* 0000 0000 0000 1011 ... */ + /* 0 */ V(10, 15, 1), /* 396 */ + /* 1 */ V(14, 9, 1) +}; + +static +union huffpair const hufftab15[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 4), + /* 0100 */ PTR(80, 4), + /* 0101 */ PTR(96, 3), + /* 0110 */ PTR(104, 3), + /* 0111 */ PTR(112, 2), + /* 1000 */ PTR(116, 1), + /* 1001 */ PTR(118, 1), + /* 1010 */ V(1, 1, 3), + /* 1011 */ V(1, 1, 3), + /* 1100 */ V(0, 1, 4), + /* 1101 */ V(1, 0, 4), + /* 1110 */ V(0, 0, 3), + /* 1111 */ V(0, 0, 3), + + /* 0000 ... */ + /* 0000 */ PTR(120, 4), /* 16 */ + /* 0001 */ PTR(136, 4), + /* 0010 */ PTR(152, 4), + /* 0011 */ PTR(168, 4), + /* 0100 */ PTR(184, 4), + /* 0101 */ PTR(200, 3), + /* 0110 */ PTR(208, 3), + /* 0111 */ PTR(216, 4), + /* 1000 */ PTR(232, 3), + /* 1001 */ PTR(240, 3), + /* 1010 */ PTR(248, 3), + /* 1011 */ PTR(256, 3), + /* 1100 */ PTR(264, 2), + /* 1101 */ PTR(268, 3), + /* 1110 */ PTR(276, 3), + /* 1111 */ PTR(284, 2), + + /* 0001 ... */ + /* 0000 */ PTR(288, 2), /* 32 */ + /* 0001 */ PTR(292, 2), + /* 0010 */ PTR(296, 2), + /* 0011 */ PTR(300, 2), + /* 0100 */ PTR(304, 2), + /* 0101 */ PTR(308, 2), + /* 0110 */ PTR(312, 2), + /* 0111 */ PTR(316, 2), + /* 1000 */ PTR(320, 1), + /* 1001 */ PTR(322, 1), + /* 1010 */ PTR(324, 1), + /* 1011 */ PTR(326, 2), + /* 1100 */ PTR(330, 1), + /* 1101 */ PTR(332, 1), + /* 1110 */ PTR(334, 2), + /* 1111 */ PTR(338, 1), + + /* 0010 ... */ + /* 0000 */ PTR(340, 1), /* 48 */ + /* 0001 */ PTR(342, 1), + /* 0010 */ V(9, 1, 4), + /* 0011 */ PTR(344, 1), + /* 0100 */ PTR(346, 1), + /* 0101 */ PTR(348, 1), + /* 0110 */ PTR(350, 1), + /* 0111 */ PTR(352, 1), + /* 1000 */ V(2, 8, 4), + /* 1001 */ V(8, 2, 4), + /* 1010 */ V(1, 8, 4), + /* 1011 */ V(8, 1, 4), + /* 1100 */ PTR(354, 1), + /* 1101 */ PTR(356, 1), + /* 1110 */ PTR(358, 1), + /* 1111 */ PTR(360, 1), + + /* 0011 ... */ + /* 0000 */ V(2, 7, 4), /* 64 */ + /* 0001 */ V(7, 2, 4), + /* 0010 */ V(6, 4, 4), + /* 0011 */ V(1, 7, 4), + /* 0100 */ V(5, 5, 4), + /* 0101 */ V(7, 1, 4), + /* 0110 */ PTR(362, 1), + /* 0111 */ V(3, 6, 4), + /* 1000 */ V(6, 3, 4), + /* 1001 */ V(4, 5, 4), + /* 1010 */ V(5, 4, 4), + /* 1011 */ V(2, 6, 4), + /* 1100 */ V(6, 2, 4), + /* 1101 */ V(1, 6, 4), + /* 1110 */ PTR(364, 1), + /* 1111 */ V(3, 5, 4), + + /* 0100 ... */ + /* 0000 */ V(6, 1, 3), /* 80 */ + /* 0001 */ V(6, 1, 3), + /* 0010 */ V(5, 3, 4), + /* 0011 */ V(4, 4, 4), + /* 0100 */ V(2, 5, 3), + /* 0101 */ V(2, 5, 3), + /* 0110 */ V(5, 2, 3), + /* 0111 */ V(5, 2, 3), + /* 1000 */ V(1, 5, 3), + /* 1001 */ V(1, 5, 3), + /* 1010 */ V(5, 1, 3), + /* 1011 */ V(5, 1, 3), + /* 1100 */ V(0, 5, 4), + /* 1101 */ V(5, 0, 4), + /* 1110 */ V(3, 4, 3), + /* 1111 */ V(3, 4, 3), + + /* 0101 ... */ + /* 000 */ V(4, 3, 3), /* 96 */ + /* 001 */ V(2, 4, 3), + /* 010 */ V(4, 2, 3), + /* 011 */ V(3, 3, 3), + /* 100 */ V(4, 1, 2), + /* 101 */ V(4, 1, 2), + /* 110 */ V(1, 4, 3), + /* 111 */ V(0, 4, 3), + + /* 0110 ... */ + /* 000 */ V(2, 3, 2), /* 104 */ + /* 001 */ V(2, 3, 2), + /* 010 */ V(3, 2, 2), + /* 011 */ V(3, 2, 2), + /* 100 */ V(4, 0, 3), + /* 101 */ V(0, 3, 3), + /* 110 */ V(1, 3, 2), + /* 111 */ V(1, 3, 2), + + /* 0111 ... */ + /* 00 */ V(3, 1, 2), /* 112 */ + /* 01 */ V(3, 0, 2), + /* 10 */ V(2, 2, 1), + /* 11 */ V(2, 2, 1), + + /* 1000 ... */ + /* 0 */ V(1, 2, 1), /* 116 */ + /* 1 */ V(2, 1, 1), + + /* 1001 ... */ + /* 0 */ V(0, 2, 1), /* 118 */ + /* 1 */ V(2, 0, 1), + + /* 0000 0000 ... */ + /* 0000 */ PTR(366, 1), /* 120 */ + /* 0001 */ PTR(368, 1), + /* 0010 */ V(14, 14, 4), + /* 0011 */ PTR(370, 1), + /* 0100 */ PTR(372, 1), + /* 0101 */ PTR(374, 1), + /* 0110 */ V(15, 11, 4), + /* 0111 */ PTR(376, 1), + /* 1000 */ V(13, 13, 4), + /* 1001 */ V(10, 15, 4), + /* 1010 */ V(15, 10, 4), + /* 1011 */ V(11, 14, 4), + /* 1100 */ V(14, 11, 4), + /* 1101 */ V(12, 13, 4), + /* 1110 */ V(13, 12, 4), + /* 1111 */ V(9, 15, 4), + + /* 0000 0001 ... */ + /* 0000 */ V(15, 9, 4), /* 136 */ + /* 0001 */ V(14, 10, 4), + /* 0010 */ V(11, 13, 4), + /* 0011 */ V(13, 11, 4), + /* 0100 */ V(8, 15, 4), + /* 0101 */ V(15, 8, 4), + /* 0110 */ V(12, 12, 4), + /* 0111 */ V(9, 14, 4), + /* 1000 */ V(14, 9, 4), + /* 1001 */ V(7, 15, 4), + /* 1010 */ V(15, 7, 4), + /* 1011 */ V(10, 13, 4), + /* 1100 */ V(13, 10, 4), + /* 1101 */ V(11, 12, 4), + /* 1110 */ V(6, 15, 4), + /* 1111 */ PTR(378, 1), + + /* 0000 0010 ... */ + /* 0000 */ V(12, 11, 3), /* 152 */ + /* 0001 */ V(12, 11, 3), + /* 0010 */ V(15, 6, 3), + /* 0011 */ V(15, 6, 3), + /* 0100 */ V(8, 14, 4), + /* 0101 */ V(14, 8, 4), + /* 0110 */ V(5, 15, 4), + /* 0111 */ V(9, 13, 4), + /* 1000 */ V(15, 5, 3), + /* 1001 */ V(15, 5, 3), + /* 1010 */ V(7, 14, 3), + /* 1011 */ V(7, 14, 3), + /* 1100 */ V(14, 7, 3), + /* 1101 */ V(14, 7, 3), + /* 1110 */ V(10, 12, 3), + /* 1111 */ V(10, 12, 3), + + /* 0000 0011 ... */ + /* 0000 */ V(12, 10, 3), /* 168 */ + /* 0001 */ V(12, 10, 3), + /* 0010 */ V(11, 11, 3), + /* 0011 */ V(11, 11, 3), + /* 0100 */ V(13, 9, 4), + /* 0101 */ V(8, 13, 4), + /* 0110 */ V(4, 15, 3), + /* 0111 */ V(4, 15, 3), + /* 1000 */ V(15, 4, 3), + /* 1001 */ V(15, 4, 3), + /* 1010 */ V(3, 15, 3), + /* 1011 */ V(3, 15, 3), + /* 1100 */ V(15, 3, 3), + /* 1101 */ V(15, 3, 3), + /* 1110 */ V(13, 8, 3), + /* 1111 */ V(13, 8, 3), + + /* 0000 0100 ... */ + /* 0000 */ V(14, 6, 3), /* 184 */ + /* 0001 */ V(14, 6, 3), + /* 0010 */ V(2, 15, 3), + /* 0011 */ V(2, 15, 3), + /* 0100 */ V(15, 2, 3), + /* 0101 */ V(15, 2, 3), + /* 0110 */ V(6, 14, 4), + /* 0111 */ V(15, 0, 4), + /* 1000 */ V(1, 15, 3), + /* 1001 */ V(1, 15, 3), + /* 1010 */ V(15, 1, 3), + /* 1011 */ V(15, 1, 3), + /* 1100 */ V(9, 12, 3), + /* 1101 */ V(9, 12, 3), + /* 1110 */ V(12, 9, 3), + /* 1111 */ V(12, 9, 3), + + /* 0000 0101 ... */ + /* 000 */ V(5, 14, 3), /* 200 */ + /* 001 */ V(10, 11, 3), + /* 010 */ V(11, 10, 3), + /* 011 */ V(14, 5, 3), + /* 100 */ V(7, 13, 3), + /* 101 */ V(13, 7, 3), + /* 110 */ V(4, 14, 3), + /* 111 */ V(14, 4, 3), + + /* 0000 0110 ... */ + /* 000 */ V(8, 12, 3), /* 208 */ + /* 001 */ V(12, 8, 3), + /* 010 */ V(3, 14, 3), + /* 011 */ V(6, 13, 3), + /* 100 */ V(13, 6, 3), + /* 101 */ V(14, 3, 3), + /* 110 */ V(9, 11, 3), + /* 111 */ V(11, 9, 3), + + /* 0000 0111 ... */ + /* 0000 */ V(2, 14, 3), /* 216 */ + /* 0001 */ V(2, 14, 3), + /* 0010 */ V(10, 10, 3), + /* 0011 */ V(10, 10, 3), + /* 0100 */ V(14, 2, 3), + /* 0101 */ V(14, 2, 3), + /* 0110 */ V(1, 14, 3), + /* 0111 */ V(1, 14, 3), + /* 1000 */ V(14, 1, 3), + /* 1001 */ V(14, 1, 3), + /* 1010 */ V(0, 14, 4), + /* 1011 */ V(14, 0, 4), + /* 1100 */ V(5, 13, 3), + /* 1101 */ V(5, 13, 3), + /* 1110 */ V(13, 5, 3), + /* 1111 */ V(13, 5, 3), + + /* 0000 1000 ... */ + /* 000 */ V(7, 12, 3), /* 232 */ + /* 001 */ V(12, 7, 3), + /* 010 */ V(4, 13, 3), + /* 011 */ V(8, 11, 3), + /* 100 */ V(13, 4, 2), + /* 101 */ V(13, 4, 2), + /* 110 */ V(11, 8, 3), + /* 111 */ V(9, 10, 3), + + /* 0000 1001 ... */ + /* 000 */ V(10, 9, 3), /* 240 */ + /* 001 */ V(6, 12, 3), + /* 010 */ V(12, 6, 3), + /* 011 */ V(3, 13, 3), + /* 100 */ V(13, 3, 2), + /* 101 */ V(13, 3, 2), + /* 110 */ V(13, 2, 2), + /* 111 */ V(13, 2, 2), + + /* 0000 1010 ... */ + /* 000 */ V(2, 13, 3), /* 248 */ + /* 001 */ V(0, 13, 3), + /* 010 */ V(1, 13, 2), + /* 011 */ V(1, 13, 2), + /* 100 */ V(7, 11, 2), + /* 101 */ V(7, 11, 2), + /* 110 */ V(11, 7, 2), + /* 111 */ V(11, 7, 2), + + /* 0000 1011 ... */ + /* 000 */ V(13, 1, 2), /* 256 */ + /* 001 */ V(13, 1, 2), + /* 010 */ V(5, 12, 3), + /* 011 */ V(13, 0, 3), + /* 100 */ V(12, 5, 2), + /* 101 */ V(12, 5, 2), + /* 110 */ V(8, 10, 2), + /* 111 */ V(8, 10, 2), + + /* 0000 1100 ... */ + /* 00 */ V(10, 8, 2), /* 264 */ + /* 01 */ V(4, 12, 2), + /* 10 */ V(12, 4, 2), + /* 11 */ V(6, 11, 2), + + /* 0000 1101 ... */ + /* 000 */ V(11, 6, 2), /* 268 */ + /* 001 */ V(11, 6, 2), + /* 010 */ V(9, 9, 3), + /* 011 */ V(0, 12, 3), + /* 100 */ V(3, 12, 2), + /* 101 */ V(3, 12, 2), + /* 110 */ V(12, 3, 2), + /* 111 */ V(12, 3, 2), + + /* 0000 1110 ... */ + /* 000 */ V(7, 10, 2), /* 276 */ + /* 001 */ V(7, 10, 2), + /* 010 */ V(10, 7, 2), + /* 011 */ V(10, 7, 2), + /* 100 */ V(10, 6, 2), + /* 101 */ V(10, 6, 2), + /* 110 */ V(12, 0, 3), + /* 111 */ V(0, 11, 3), + + /* 0000 1111 ... */ + /* 00 */ V(12, 2, 1), /* 284 */ + /* 01 */ V(12, 2, 1), + /* 10 */ V(2, 12, 2), + /* 11 */ V(5, 11, 2), + + /* 0001 0000 ... */ + /* 00 */ V(11, 5, 2), /* 288 */ + /* 01 */ V(1, 12, 2), + /* 10 */ V(8, 9, 2), + /* 11 */ V(9, 8, 2), + + /* 0001 0001 ... */ + /* 00 */ V(12, 1, 2), /* 292 */ + /* 01 */ V(4, 11, 2), + /* 10 */ V(11, 4, 2), + /* 11 */ V(6, 10, 2), + + /* 0001 0010 ... */ + /* 00 */ V(3, 11, 2), /* 296 */ + /* 01 */ V(7, 9, 2), + /* 10 */ V(11, 3, 1), + /* 11 */ V(11, 3, 1), + + /* 0001 0011 ... */ + /* 00 */ V(9, 7, 2), /* 300 */ + /* 01 */ V(8, 8, 2), + /* 10 */ V(2, 11, 2), + /* 11 */ V(5, 10, 2), + + /* 0001 0100 ... */ + /* 00 */ V(11, 2, 1), /* 304 */ + /* 01 */ V(11, 2, 1), + /* 10 */ V(10, 5, 2), + /* 11 */ V(1, 11, 2), + + /* 0001 0101 ... */ + /* 00 */ V(11, 1, 1), /* 308 */ + /* 01 */ V(11, 1, 1), + /* 10 */ V(11, 0, 2), + /* 11 */ V(6, 9, 2), + + /* 0001 0110 ... */ + /* 00 */ V(9, 6, 2), /* 312 */ + /* 01 */ V(4, 10, 2), + /* 10 */ V(10, 4, 2), + /* 11 */ V(7, 8, 2), + + /* 0001 0111 ... */ + /* 00 */ V(8, 7, 2), /* 316 */ + /* 01 */ V(3, 10, 2), + /* 10 */ V(10, 3, 1), + /* 11 */ V(10, 3, 1), + + /* 0001 1000 ... */ + /* 0 */ V(5, 9, 1), /* 320 */ + /* 1 */ V(9, 5, 1), + + /* 0001 1001 ... */ + /* 0 */ V(2, 10, 1), /* 322 */ + /* 1 */ V(10, 2, 1), + + /* 0001 1010 ... */ + /* 0 */ V(1, 10, 1), /* 324 */ + /* 1 */ V(10, 1, 1), + + /* 0001 1011 ... */ + /* 00 */ V(0, 10, 2), /* 326 */ + /* 01 */ V(10, 0, 2), + /* 10 */ V(6, 8, 1), + /* 11 */ V(6, 8, 1), + + /* 0001 1100 ... */ + /* 0 */ V(8, 6, 1), /* 330 */ + /* 1 */ V(4, 9, 1), + + /* 0001 1101 ... */ + /* 0 */ V(9, 4, 1), /* 332 */ + /* 1 */ V(3, 9, 1), + + /* 0001 1110 ... */ + /* 00 */ V(9, 3, 1), /* 334 */ + /* 01 */ V(9, 3, 1), + /* 10 */ V(7, 7, 2), + /* 11 */ V(0, 9, 2), + + /* 0001 1111 ... */ + /* 0 */ V(5, 8, 1), /* 338 */ + /* 1 */ V(8, 5, 1), + + /* 0010 0000 ... */ + /* 0 */ V(2, 9, 1), /* 340 */ + /* 1 */ V(6, 7, 1), + + /* 0010 0001 ... */ + /* 0 */ V(7, 6, 1), /* 342 */ + /* 1 */ V(9, 2, 1), + + /* 0010 0011 ... */ + /* 0 */ V(1, 9, 1), /* 344 */ + /* 1 */ V(9, 0, 1), + + /* 0010 0100 ... */ + /* 0 */ V(4, 8, 1), /* 346 */ + /* 1 */ V(8, 4, 1), + + /* 0010 0101 ... */ + /* 0 */ V(5, 7, 1), /* 348 */ + /* 1 */ V(7, 5, 1), + + /* 0010 0110 ... */ + /* 0 */ V(3, 8, 1), /* 350 */ + /* 1 */ V(8, 3, 1), + + /* 0010 0111 ... */ + /* 0 */ V(6, 6, 1), /* 352 */ + /* 1 */ V(4, 7, 1), + + /* 0010 1100 ... */ + /* 0 */ V(7, 4, 1), /* 354 */ + /* 1 */ V(0, 8, 1), + + /* 0010 1101 ... */ + /* 0 */ V(8, 0, 1), /* 356 */ + /* 1 */ V(5, 6, 1), + + /* 0010 1110 ... */ + /* 0 */ V(6, 5, 1), /* 358 */ + /* 1 */ V(3, 7, 1), + + /* 0010 1111 ... */ + /* 0 */ V(7, 3, 1), /* 360 */ + /* 1 */ V(4, 6, 1), + + /* 0011 0110 ... */ + /* 0 */ V(0, 7, 1), /* 362 */ + /* 1 */ V(7, 0, 1), + + /* 0011 1110 ... */ + /* 0 */ V(0, 6, 1), /* 364 */ + /* 1 */ V(6, 0, 1), + + /* 0000 0000 0000 ... */ + /* 0 */ V(15, 15, 1), /* 366 */ + /* 1 */ V(14, 15, 1), + + /* 0000 0000 0001 ... */ + /* 0 */ V(15, 14, 1), /* 368 */ + /* 1 */ V(13, 15, 1), + + /* 0000 0000 0011 ... */ + /* 0 */ V(15, 13, 1), /* 370 */ + /* 1 */ V(12, 15, 1), + + /* 0000 0000 0100 ... */ + /* 0 */ V(15, 12, 1), /* 372 */ + /* 1 */ V(13, 14, 1), + + /* 0000 0000 0101 ... */ + /* 0 */ V(14, 13, 1), /* 374 */ + /* 1 */ V(11, 15, 1), + + /* 0000 0000 0111 ... */ + /* 0 */ V(12, 14, 1), /* 376 */ + /* 1 */ V(14, 12, 1), + + /* 0000 0001 1111 ... */ + /* 0 */ V(10, 14, 1), /* 378 */ + /* 1 */ V(0, 15, 1) +}; + +static +union huffpair const hufftab16[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ PTR(64, 2), + /* 0100 */ V(1, 1, 4), + /* 0101 */ V(0, 1, 4), + /* 0110 */ V(1, 0, 3), + /* 0111 */ V(1, 0, 3), + /* 1000 */ V(0, 0, 1), + /* 1001 */ V(0, 0, 1), + /* 1010 */ V(0, 0, 1), + /* 1011 */ V(0, 0, 1), + /* 1100 */ V(0, 0, 1), + /* 1101 */ V(0, 0, 1), + /* 1110 */ V(0, 0, 1), + /* 1111 */ V(0, 0, 1), + + /* 0000 ... */ + /* 0000 */ PTR(68, 3), /* 16 */ + /* 0001 */ PTR(76, 3), + /* 0010 */ PTR(84, 2), + /* 0011 */ V(15, 15, 4), + /* 0100 */ PTR(88, 2), + /* 0101 */ PTR(92, 1), + /* 0110 */ PTR(94, 4), + /* 0111 */ V(15, 2, 4), + /* 1000 */ PTR(110, 1), + /* 1001 */ V(1, 15, 4), + /* 1010 */ V(15, 1, 4), + /* 1011 */ PTR(112, 4), + /* 1100 */ PTR(128, 4), + /* 1101 */ PTR(144, 4), + /* 1110 */ PTR(160, 4), + /* 1111 */ PTR(176, 4), + + /* 0001 ... */ + /* 0000 */ PTR(192, 4), /* 32 */ + /* 0001 */ PTR(208, 3), + /* 0010 */ PTR(216, 3), + /* 0011 */ PTR(224, 3), + /* 0100 */ PTR(232, 3), + /* 0101 */ PTR(240, 3), + /* 0110 */ PTR(248, 3), + /* 0111 */ PTR(256, 3), + /* 1000 */ PTR(264, 2), + /* 1001 */ PTR(268, 2), + /* 1010 */ PTR(272, 1), + /* 1011 */ PTR(274, 2), + /* 1100 */ PTR(278, 2), + /* 1101 */ PTR(282, 1), + /* 1110 */ V(5, 1, 4), + /* 1111 */ PTR(284, 1), + + /* 0010 ... */ + /* 0000 */ PTR(286, 1), /* 48 */ + /* 0001 */ PTR(288, 1), + /* 0010 */ PTR(290, 1), + /* 0011 */ V(1, 4, 4), + /* 0100 */ V(4, 1, 4), + /* 0101 */ PTR(292, 1), + /* 0110 */ V(2, 3, 4), + /* 0111 */ V(3, 2, 4), + /* 1000 */ V(1, 3, 3), + /* 1001 */ V(1, 3, 3), + /* 1010 */ V(3, 1, 3), + /* 1011 */ V(3, 1, 3), + /* 1100 */ V(0, 3, 4), + /* 1101 */ V(3, 0, 4), + /* 1110 */ V(2, 2, 3), + /* 1111 */ V(2, 2, 3), + + /* 0011 ... */ + /* 00 */ V(1, 2, 2), /* 64 */ + /* 01 */ V(2, 1, 2), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0000 0000 ... */ + /* 000 */ V(14, 15, 3), /* 68 */ + /* 001 */ V(15, 14, 3), + /* 010 */ V(13, 15, 3), + /* 011 */ V(15, 13, 3), + /* 100 */ V(12, 15, 3), + /* 101 */ V(15, 12, 3), + /* 110 */ V(11, 15, 3), + /* 111 */ V(15, 11, 3), + + /* 0000 0001 ... */ + /* 000 */ V(10, 15, 2), /* 76 */ + /* 001 */ V(10, 15, 2), + /* 010 */ V(15, 10, 3), + /* 011 */ V(9, 15, 3), + /* 100 */ V(15, 9, 3), + /* 101 */ V(15, 8, 3), + /* 110 */ V(8, 15, 2), + /* 111 */ V(8, 15, 2), + + /* 0000 0010 ... */ + /* 00 */ V(7, 15, 2), /* 84 */ + /* 01 */ V(15, 7, 2), + /* 10 */ V(6, 15, 2), + /* 11 */ V(15, 6, 2), + + /* 0000 0100 ... */ + /* 00 */ V(5, 15, 2), /* 88 */ + /* 01 */ V(15, 5, 2), + /* 10 */ V(4, 15, 1), + /* 11 */ V(4, 15, 1), + + /* 0000 0101 ... */ + /* 0 */ V(15, 4, 1), /* 92 */ + /* 1 */ V(15, 3, 1), + + /* 0000 0110 ... */ + /* 0000 */ V(15, 0, 1), /* 94 */ + /* 0001 */ V(15, 0, 1), + /* 0010 */ V(15, 0, 1), + /* 0011 */ V(15, 0, 1), + /* 0100 */ V(15, 0, 1), + /* 0101 */ V(15, 0, 1), + /* 0110 */ V(15, 0, 1), + /* 0111 */ V(15, 0, 1), + /* 1000 */ V(3, 15, 2), + /* 1001 */ V(3, 15, 2), + /* 1010 */ V(3, 15, 2), + /* 1011 */ V(3, 15, 2), + /* 1100 */ PTR(294, 4), + /* 1101 */ PTR(310, 3), + /* 1110 */ PTR(318, 3), + /* 1111 */ PTR(326, 3), + + /* 0000 1000 ... */ + /* 0 */ V(2, 15, 1), /* 110 */ + /* 1 */ V(0, 15, 1), + + /* 0000 1011 ... */ + /* 0000 */ PTR(334, 2), /* 112 */ + /* 0001 */ PTR(338, 2), + /* 0010 */ PTR(342, 2), + /* 0011 */ PTR(346, 1), + /* 0100 */ PTR(348, 2), + /* 0101 */ PTR(352, 2), + /* 0110 */ PTR(356, 1), + /* 0111 */ PTR(358, 2), + /* 1000 */ PTR(362, 2), + /* 1001 */ PTR(366, 2), + /* 1010 */ PTR(370, 2), + /* 1011 */ V(14, 3, 4), + /* 1100 */ PTR(374, 1), + /* 1101 */ PTR(376, 1), + /* 1110 */ PTR(378, 1), + /* 1111 */ PTR(380, 1), + + /* 0000 1100 ... */ + /* 0000 */ PTR(382, 1), /* 128 */ + /* 0001 */ PTR(384, 1), + /* 0010 */ PTR(386, 1), + /* 0011 */ V(0, 13, 4), + /* 0100 */ PTR(388, 1), + /* 0101 */ PTR(390, 1), + /* 0110 */ PTR(392, 1), + /* 0111 */ V(3, 12, 4), + /* 1000 */ PTR(394, 1), + /* 1001 */ V(1, 12, 4), + /* 1010 */ V(12, 0, 4), + /* 1011 */ PTR(396, 1), + /* 1100 */ V(14, 2, 3), + /* 1101 */ V(14, 2, 3), + /* 1110 */ V(2, 14, 4), + /* 1111 */ V(1, 14, 4), + + /* 0000 1101 ... */ + /* 0000 */ V(13, 3, 4), /* 144 */ + /* 0001 */ V(2, 13, 4), + /* 0010 */ V(13, 2, 4), + /* 0011 */ V(13, 1, 4), + /* 0100 */ V(3, 11, 4), + /* 0101 */ PTR(398, 1), + /* 0110 */ V(1, 13, 3), + /* 0111 */ V(1, 13, 3), + /* 1000 */ V(12, 4, 4), + /* 1001 */ V(6, 11, 4), + /* 1010 */ V(12, 3, 4), + /* 1011 */ V(10, 7, 4), + /* 1100 */ V(2, 12, 3), + /* 1101 */ V(2, 12, 3), + /* 1110 */ V(12, 2, 4), + /* 1111 */ V(11, 5, 4), + + /* 0000 1110 ... */ + /* 0000 */ V(12, 1, 4), /* 160 */ + /* 0001 */ V(0, 12, 4), + /* 0010 */ V(4, 11, 4), + /* 0011 */ V(11, 4, 4), + /* 0100 */ V(6, 10, 4), + /* 0101 */ V(10, 6, 4), + /* 0110 */ V(11, 3, 3), + /* 0111 */ V(11, 3, 3), + /* 1000 */ V(5, 10, 4), + /* 1001 */ V(10, 5, 4), + /* 1010 */ V(2, 11, 3), + /* 1011 */ V(2, 11, 3), + /* 1100 */ V(11, 2, 3), + /* 1101 */ V(11, 2, 3), + /* 1110 */ V(1, 11, 3), + /* 1111 */ V(1, 11, 3), + + /* 0000 1111 ... */ + /* 0000 */ V(11, 1, 3), /* 176 */ + /* 0001 */ V(11, 1, 3), + /* 0010 */ V(0, 11, 4), + /* 0011 */ V(11, 0, 4), + /* 0100 */ V(6, 9, 4), + /* 0101 */ V(9, 6, 4), + /* 0110 */ V(4, 10, 4), + /* 0111 */ V(10, 4, 4), + /* 1000 */ V(7, 8, 4), + /* 1001 */ V(8, 7, 4), + /* 1010 */ V(10, 3, 3), + /* 1011 */ V(10, 3, 3), + /* 1100 */ V(3, 10, 4), + /* 1101 */ V(5, 9, 4), + /* 1110 */ V(2, 10, 3), + /* 1111 */ V(2, 10, 3), + + /* 0001 0000 ... */ + /* 0000 */ V(9, 5, 4), /* 192 */ + /* 0001 */ V(6, 8, 4), + /* 0010 */ V(10, 1, 3), + /* 0011 */ V(10, 1, 3), + /* 0100 */ V(8, 6, 4), + /* 0101 */ V(7, 7, 4), + /* 0110 */ V(9, 4, 3), + /* 0111 */ V(9, 4, 3), + /* 1000 */ V(4, 9, 4), + /* 1001 */ V(5, 7, 4), + /* 1010 */ V(6, 7, 3), + /* 1011 */ V(6, 7, 3), + /* 1100 */ V(10, 2, 2), + /* 1101 */ V(10, 2, 2), + /* 1110 */ V(10, 2, 2), + /* 1111 */ V(10, 2, 2), + + /* 0001 0001 ... */ + /* 000 */ V(1, 10, 2), /* 208 */ + /* 001 */ V(1, 10, 2), + /* 010 */ V(0, 10, 3), + /* 011 */ V(10, 0, 3), + /* 100 */ V(3, 9, 3), + /* 101 */ V(9, 3, 3), + /* 110 */ V(5, 8, 3), + /* 111 */ V(8, 5, 3), + + /* 0001 0010 ... */ + /* 000 */ V(2, 9, 2), /* 216 */ + /* 001 */ V(2, 9, 2), + /* 010 */ V(9, 2, 2), + /* 011 */ V(9, 2, 2), + /* 100 */ V(7, 6, 3), + /* 101 */ V(0, 9, 3), + /* 110 */ V(1, 9, 2), + /* 111 */ V(1, 9, 2), + + /* 0001 0011 ... */ + /* 000 */ V(9, 1, 2), /* 224 */ + /* 001 */ V(9, 1, 2), + /* 010 */ V(9, 0, 3), + /* 011 */ V(4, 8, 3), + /* 100 */ V(8, 4, 3), + /* 101 */ V(7, 5, 3), + /* 110 */ V(3, 8, 3), + /* 111 */ V(8, 3, 3), + + /* 0001 0100 ... */ + /* 000 */ V(6, 6, 3), /* 232 */ + /* 001 */ V(2, 8, 3), + /* 010 */ V(8, 2, 2), + /* 011 */ V(8, 2, 2), + /* 100 */ V(4, 7, 3), + /* 101 */ V(7, 4, 3), + /* 110 */ V(1, 8, 2), + /* 111 */ V(1, 8, 2), + + /* 0001 0101 ... */ + /* 000 */ V(8, 1, 2), /* 240 */ + /* 001 */ V(8, 1, 2), + /* 010 */ V(8, 0, 2), + /* 011 */ V(8, 0, 2), + /* 100 */ V(0, 8, 3), + /* 101 */ V(5, 6, 3), + /* 110 */ V(3, 7, 2), + /* 111 */ V(3, 7, 2), + + /* 0001 0110 ... */ + /* 000 */ V(7, 3, 2), /* 248 */ + /* 001 */ V(7, 3, 2), + /* 010 */ V(6, 5, 3), + /* 011 */ V(4, 6, 3), + /* 100 */ V(2, 7, 2), + /* 101 */ V(2, 7, 2), + /* 110 */ V(7, 2, 2), + /* 111 */ V(7, 2, 2), + + /* 0001 0111 ... */ + /* 000 */ V(6, 4, 3), /* 256 */ + /* 001 */ V(5, 5, 3), + /* 010 */ V(0, 7, 2), + /* 011 */ V(0, 7, 2), + /* 100 */ V(1, 7, 1), + /* 101 */ V(1, 7, 1), + /* 110 */ V(1, 7, 1), + /* 111 */ V(1, 7, 1), + + /* 0001 1000 ... */ + /* 00 */ V(7, 1, 1), /* 264 */ + /* 01 */ V(7, 1, 1), + /* 10 */ V(7, 0, 2), + /* 11 */ V(3, 6, 2), + + /* 0001 1001 ... */ + /* 00 */ V(6, 3, 2), /* 268 */ + /* 01 */ V(4, 5, 2), + /* 10 */ V(5, 4, 2), + /* 11 */ V(2, 6, 2), + + /* 0001 1010 ... */ + /* 0 */ V(6, 2, 1), /* 272 */ + /* 1 */ V(1, 6, 1), + + /* 0001 1011 ... */ + /* 00 */ V(6, 1, 1), /* 274 */ + /* 01 */ V(6, 1, 1), + /* 10 */ V(0, 6, 2), + /* 11 */ V(6, 0, 2), + + /* 0001 1100 ... */ + /* 00 */ V(5, 3, 1), /* 278 */ + /* 01 */ V(5, 3, 1), + /* 10 */ V(3, 5, 2), + /* 11 */ V(4, 4, 2), + + /* 0001 1101 ... */ + /* 0 */ V(2, 5, 1), /* 282 */ + /* 1 */ V(5, 2, 1), + + /* 0001 1111 ... */ + /* 0 */ V(1, 5, 1), /* 284 */ + /* 1 */ V(0, 5, 1), + + /* 0010 0000 ... */ + /* 0 */ V(3, 4, 1), /* 286 */ + /* 1 */ V(4, 3, 1), + + /* 0010 0001 ... */ + /* 0 */ V(5, 0, 1), /* 288 */ + /* 1 */ V(2, 4, 1), + + /* 0010 0010 ... */ + /* 0 */ V(4, 2, 1), /* 290 */ + /* 1 */ V(3, 3, 1), + + /* 0010 0101 ... */ + /* 0 */ V(0, 4, 1), /* 292 */ + /* 1 */ V(4, 0, 1), + + /* 0000 0110 1100 ... */ + /* 0000 */ V(12, 14, 4), /* 294 */ + /* 0001 */ PTR(400, 1), + /* 0010 */ V(13, 14, 3), + /* 0011 */ V(13, 14, 3), + /* 0100 */ V(14, 9, 3), + /* 0101 */ V(14, 9, 3), + /* 0110 */ V(14, 10, 4), + /* 0111 */ V(13, 9, 4), + /* 1000 */ V(14, 14, 2), + /* 1001 */ V(14, 14, 2), + /* 1010 */ V(14, 14, 2), + /* 1011 */ V(14, 14, 2), + /* 1100 */ V(14, 13, 3), + /* 1101 */ V(14, 13, 3), + /* 1110 */ V(14, 11, 3), + /* 1111 */ V(14, 11, 3), + + /* 0000 0110 1101 ... */ + /* 000 */ V(11, 14, 2), /* 310 */ + /* 001 */ V(11, 14, 2), + /* 010 */ V(12, 13, 2), + /* 011 */ V(12, 13, 2), + /* 100 */ V(13, 12, 3), + /* 101 */ V(13, 11, 3), + /* 110 */ V(10, 14, 2), + /* 111 */ V(10, 14, 2), + + /* 0000 0110 1110 ... */ + /* 000 */ V(12, 12, 2), /* 318 */ + /* 001 */ V(12, 12, 2), + /* 010 */ V(10, 13, 3), + /* 011 */ V(13, 10, 3), + /* 100 */ V(7, 14, 3), + /* 101 */ V(10, 12, 3), + /* 110 */ V(12, 10, 2), + /* 111 */ V(12, 10, 2), + + /* 0000 0110 1111 ... */ + /* 000 */ V(12, 9, 3), /* 326 */ + /* 001 */ V(7, 13, 3), + /* 010 */ V(5, 14, 2), + /* 011 */ V(5, 14, 2), + /* 100 */ V(11, 13, 1), + /* 101 */ V(11, 13, 1), + /* 110 */ V(11, 13, 1), + /* 111 */ V(11, 13, 1), + + /* 0000 1011 0000 ... */ + /* 00 */ V(9, 14, 1), /* 334 */ + /* 01 */ V(9, 14, 1), + /* 10 */ V(11, 12, 2), + /* 11 */ V(12, 11, 2), + + /* 0000 1011 0001 ... */ + /* 00 */ V(8, 14, 2), /* 338 */ + /* 01 */ V(14, 8, 2), + /* 10 */ V(9, 13, 2), + /* 11 */ V(14, 7, 2), + + /* 0000 1011 0010 ... */ + /* 00 */ V(11, 11, 2), /* 342 */ + /* 01 */ V(8, 13, 2), + /* 10 */ V(13, 8, 2), + /* 11 */ V(6, 14, 2), + + /* 0000 1011 0011 ... */ + /* 0 */ V(14, 6, 1), /* 346 */ + /* 1 */ V(9, 12, 1), + + /* 0000 1011 0100 ... */ + /* 00 */ V(10, 11, 2), /* 348 */ + /* 01 */ V(11, 10, 2), + /* 10 */ V(14, 5, 2), + /* 11 */ V(13, 7, 2), + + /* 0000 1011 0101 ... */ + /* 00 */ V(4, 14, 1), /* 352 */ + /* 01 */ V(4, 14, 1), + /* 10 */ V(14, 4, 2), + /* 11 */ V(8, 12, 2), + + /* 0000 1011 0110 ... */ + /* 0 */ V(12, 8, 1), /* 356 */ + /* 1 */ V(3, 14, 1), + + /* 0000 1011 0111 ... */ + /* 00 */ V(6, 13, 1), /* 358 */ + /* 01 */ V(6, 13, 1), + /* 10 */ V(13, 6, 2), + /* 11 */ V(9, 11, 2), + + /* 0000 1011 1000 ... */ + /* 00 */ V(11, 9, 2), /* 362 */ + /* 01 */ V(10, 10, 2), + /* 10 */ V(14, 1, 1), + /* 11 */ V(14, 1, 1), + + /* 0000 1011 1001 ... */ + /* 00 */ V(13, 4, 1), /* 366 */ + /* 01 */ V(13, 4, 1), + /* 10 */ V(11, 8, 2), + /* 11 */ V(10, 9, 2), + + /* 0000 1011 1010 ... */ + /* 00 */ V(7, 11, 1), /* 370 */ + /* 01 */ V(7, 11, 1), + /* 10 */ V(11, 7, 2), + /* 11 */ V(13, 0, 2), + + /* 0000 1011 1100 ... */ + /* 0 */ V(0, 14, 1), /* 374 */ + /* 1 */ V(14, 0, 1), + + /* 0000 1011 1101 ... */ + /* 0 */ V(5, 13, 1), /* 376 */ + /* 1 */ V(13, 5, 1), + + /* 0000 1011 1110 ... */ + /* 0 */ V(7, 12, 1), /* 378 */ + /* 1 */ V(12, 7, 1), + + /* 0000 1011 1111 ... */ + /* 0 */ V(4, 13, 1), /* 380 */ + /* 1 */ V(8, 11, 1), + + /* 0000 1100 0000 ... */ + /* 0 */ V(9, 10, 1), /* 382 */ + /* 1 */ V(6, 12, 1), + + /* 0000 1100 0001 ... */ + /* 0 */ V(12, 6, 1), /* 384 */ + /* 1 */ V(3, 13, 1), + + /* 0000 1100 0010 ... */ + /* 0 */ V(5, 12, 1), /* 386 */ + /* 1 */ V(12, 5, 1), + + /* 0000 1100 0100 ... */ + /* 0 */ V(8, 10, 1), /* 388 */ + /* 1 */ V(10, 8, 1), + + /* 0000 1100 0101 ... */ + /* 0 */ V(9, 9, 1), /* 390 */ + /* 1 */ V(4, 12, 1), + + /* 0000 1100 0110 ... */ + /* 0 */ V(11, 6, 1), /* 392 */ + /* 1 */ V(7, 10, 1), + + /* 0000 1100 1000 ... */ + /* 0 */ V(5, 11, 1), /* 394 */ + /* 1 */ V(8, 9, 1), + + /* 0000 1100 1011 ... */ + /* 0 */ V(9, 8, 1), /* 396 */ + /* 1 */ V(7, 9, 1), + + /* 0000 1101 0101 ... */ + /* 0 */ V(9, 7, 1), /* 398 */ + /* 1 */ V(8, 8, 1), + + /* 0000 0110 1100 0001 ... */ + /* 0 */ V(14, 12, 1), /* 400 */ + /* 1 */ V(13, 13, 1) +}; + +static +union huffpair const hufftab24[] = { + /* 0000 */ PTR(16, 4), + /* 0001 */ PTR(32, 4), + /* 0010 */ PTR(48, 4), + /* 0011 */ V(15, 15, 4), + /* 0100 */ PTR(64, 4), + /* 0101 */ PTR(80, 4), + /* 0110 */ PTR(96, 4), + /* 0111 */ PTR(112, 4), + /* 1000 */ PTR(128, 4), + /* 1001 */ PTR(144, 4), + /* 1010 */ PTR(160, 3), + /* 1011 */ PTR(168, 2), + /* 1100 */ V(1, 1, 4), + /* 1101 */ V(0, 1, 4), + /* 1110 */ V(1, 0, 4), + /* 1111 */ V(0, 0, 4), + + /* 0000 ... */ + /* 0000 */ V(14, 15, 4), /* 16 */ + /* 0001 */ V(15, 14, 4), + /* 0010 */ V(13, 15, 4), + /* 0011 */ V(15, 13, 4), + /* 0100 */ V(12, 15, 4), + /* 0101 */ V(15, 12, 4), + /* 0110 */ V(11, 15, 4), + /* 0111 */ V(15, 11, 4), + /* 1000 */ V(15, 10, 3), + /* 1001 */ V(15, 10, 3), + /* 1010 */ V(10, 15, 4), + /* 1011 */ V(9, 15, 4), + /* 1100 */ V(15, 9, 3), + /* 1101 */ V(15, 9, 3), + /* 1110 */ V(15, 8, 3), + /* 1111 */ V(15, 8, 3), + + /* 0001 ... */ + /* 0000 */ V(8, 15, 4), /* 32 */ + /* 0001 */ V(7, 15, 4), + /* 0010 */ V(15, 7, 3), + /* 0011 */ V(15, 7, 3), + /* 0100 */ V(6, 15, 3), + /* 0101 */ V(6, 15, 3), + /* 0110 */ V(15, 6, 3), + /* 0111 */ V(15, 6, 3), + /* 1000 */ V(5, 15, 3), + /* 1001 */ V(5, 15, 3), + /* 1010 */ V(15, 5, 3), + /* 1011 */ V(15, 5, 3), + /* 1100 */ V(4, 15, 3), + /* 1101 */ V(4, 15, 3), + /* 1110 */ V(15, 4, 3), + /* 1111 */ V(15, 4, 3), + + /* 0010 ... */ + /* 0000 */ V(3, 15, 3), /* 48 */ + /* 0001 */ V(3, 15, 3), + /* 0010 */ V(15, 3, 3), + /* 0011 */ V(15, 3, 3), + /* 0100 */ V(2, 15, 3), + /* 0101 */ V(2, 15, 3), + /* 0110 */ V(15, 2, 3), + /* 0111 */ V(15, 2, 3), + /* 1000 */ V(15, 1, 3), + /* 1001 */ V(15, 1, 3), + /* 1010 */ V(1, 15, 4), + /* 1011 */ V(15, 0, 4), + /* 1100 */ PTR(172, 3), + /* 1101 */ PTR(180, 3), + /* 1110 */ PTR(188, 3), + /* 1111 */ PTR(196, 3), + + /* 0100 ... */ + /* 0000 */ PTR(204, 4), /* 64 */ + /* 0001 */ PTR(220, 3), + /* 0010 */ PTR(228, 3), + /* 0011 */ PTR(236, 3), + /* 0100 */ PTR(244, 2), + /* 0101 */ PTR(248, 2), + /* 0110 */ PTR(252, 2), + /* 0111 */ PTR(256, 2), + /* 1000 */ PTR(260, 2), + /* 1001 */ PTR(264, 2), + /* 1010 */ PTR(268, 2), + /* 1011 */ PTR(272, 2), + /* 1100 */ PTR(276, 2), + /* 1101 */ PTR(280, 3), + /* 1110 */ PTR(288, 2), + /* 1111 */ PTR(292, 2), + + /* 0101 ... */ + /* 0000 */ PTR(296, 2), /* 80 */ + /* 0001 */ PTR(300, 3), + /* 0010 */ PTR(308, 2), + /* 0011 */ PTR(312, 3), + /* 0100 */ PTR(320, 1), + /* 0101 */ PTR(322, 2), + /* 0110 */ PTR(326, 2), + /* 0111 */ PTR(330, 1), + /* 1000 */ PTR(332, 2), + /* 1001 */ PTR(336, 1), + /* 1010 */ PTR(338, 1), + /* 1011 */ PTR(340, 1), + /* 1100 */ PTR(342, 1), + /* 1101 */ PTR(344, 1), + /* 1110 */ PTR(346, 1), + /* 1111 */ PTR(348, 1), + + /* 0110 ... */ + /* 0000 */ PTR(350, 1), /* 96 */ + /* 0001 */ PTR(352, 1), + /* 0010 */ PTR(354, 1), + /* 0011 */ PTR(356, 1), + /* 0100 */ PTR(358, 1), + /* 0101 */ PTR(360, 1), + /* 0110 */ PTR(362, 1), + /* 0111 */ PTR(364, 1), + /* 1000 */ PTR(366, 1), + /* 1001 */ PTR(368, 1), + /* 1010 */ PTR(370, 2), + /* 1011 */ PTR(374, 1), + /* 1100 */ PTR(376, 2), + /* 1101 */ V(7, 3, 4), + /* 1110 */ PTR(380, 1), + /* 1111 */ V(7, 2, 4), + + /* 0111 ... */ + /* 0000 */ V(4, 6, 4), /* 112 */ + /* 0001 */ V(6, 4, 4), + /* 0010 */ V(5, 5, 4), + /* 0011 */ V(7, 1, 4), + /* 0100 */ V(3, 6, 4), + /* 0101 */ V(6, 3, 4), + /* 0110 */ V(4, 5, 4), + /* 0111 */ V(5, 4, 4), + /* 1000 */ V(2, 6, 4), + /* 1001 */ V(6, 2, 4), + /* 1010 */ V(1, 6, 4), + /* 1011 */ V(6, 1, 4), + /* 1100 */ PTR(382, 1), + /* 1101 */ V(3, 5, 4), + /* 1110 */ V(5, 3, 4), + /* 1111 */ V(4, 4, 4), + + /* 1000 ... */ + /* 0000 */ V(2, 5, 4), /* 128 */ + /* 0001 */ V(5, 2, 4), + /* 0010 */ V(1, 5, 4), + /* 0011 */ PTR(384, 1), + /* 0100 */ V(5, 1, 3), + /* 0101 */ V(5, 1, 3), + /* 0110 */ V(3, 4, 4), + /* 0111 */ V(4, 3, 4), + /* 1000 */ V(2, 4, 3), + /* 1001 */ V(2, 4, 3), + /* 1010 */ V(4, 2, 3), + /* 1011 */ V(4, 2, 3), + /* 1100 */ V(3, 3, 3), + /* 1101 */ V(3, 3, 3), + /* 1110 */ V(1, 4, 3), + /* 1111 */ V(1, 4, 3), + + /* 1001 ... */ + /* 0000 */ V(4, 1, 3), /* 144 */ + /* 0001 */ V(4, 1, 3), + /* 0010 */ V(0, 4, 4), + /* 0011 */ V(4, 0, 4), + /* 0100 */ V(2, 3, 3), + /* 0101 */ V(2, 3, 3), + /* 0110 */ V(3, 2, 3), + /* 0111 */ V(3, 2, 3), + /* 1000 */ V(1, 3, 2), + /* 1001 */ V(1, 3, 2), + /* 1010 */ V(1, 3, 2), + /* 1011 */ V(1, 3, 2), + /* 1100 */ V(3, 1, 2), + /* 1101 */ V(3, 1, 2), + /* 1110 */ V(3, 1, 2), + /* 1111 */ V(3, 1, 2), + + /* 1010 ... */ + /* 000 */ V(0, 3, 3), /* 160 */ + /* 001 */ V(3, 0, 3), + /* 010 */ V(2, 2, 2), + /* 011 */ V(2, 2, 2), + /* 100 */ V(1, 2, 1), + /* 101 */ V(1, 2, 1), + /* 110 */ V(1, 2, 1), + /* 111 */ V(1, 2, 1), + + /* 1011 ... */ + /* 00 */ V(2, 1, 1), /* 168 */ + /* 01 */ V(2, 1, 1), + /* 10 */ V(0, 2, 2), + /* 11 */ V(2, 0, 2), + + /* 0010 1100 ... */ + /* 000 */ V(0, 15, 1), /* 172 */ + /* 001 */ V(0, 15, 1), + /* 010 */ V(0, 15, 1), + /* 011 */ V(0, 15, 1), + /* 100 */ V(14, 14, 3), + /* 101 */ V(13, 14, 3), + /* 110 */ V(14, 13, 3), + /* 111 */ V(12, 14, 3), + + /* 0010 1101 ... */ + /* 000 */ V(14, 12, 3), /* 180 */ + /* 001 */ V(13, 13, 3), + /* 010 */ V(11, 14, 3), + /* 011 */ V(14, 11, 3), + /* 100 */ V(12, 13, 3), + /* 101 */ V(13, 12, 3), + /* 110 */ V(10, 14, 3), + /* 111 */ V(14, 10, 3), + + /* 0010 1110 ... */ + /* 000 */ V(11, 13, 3), /* 188 */ + /* 001 */ V(13, 11, 3), + /* 010 */ V(12, 12, 3), + /* 011 */ V(9, 14, 3), + /* 100 */ V(14, 9, 3), + /* 101 */ V(10, 13, 3), + /* 110 */ V(13, 10, 3), + /* 111 */ V(11, 12, 3), + + /* 0010 1111 ... */ + /* 000 */ V(12, 11, 3), /* 196 */ + /* 001 */ V(8, 14, 3), + /* 010 */ V(14, 8, 3), + /* 011 */ V(9, 13, 3), + /* 100 */ V(13, 9, 3), + /* 101 */ V(7, 14, 3), + /* 110 */ V(14, 7, 3), + /* 111 */ V(10, 12, 3), + + /* 0100 0000 ... */ + /* 0000 */ V(12, 10, 3), /* 204 */ + /* 0001 */ V(12, 10, 3), + /* 0010 */ V(11, 11, 3), + /* 0011 */ V(11, 11, 3), + /* 0100 */ V(8, 13, 3), + /* 0101 */ V(8, 13, 3), + /* 0110 */ V(13, 8, 3), + /* 0111 */ V(13, 8, 3), + /* 1000 */ V(0, 14, 4), + /* 1001 */ V(14, 0, 4), + /* 1010 */ V(0, 13, 3), + /* 1011 */ V(0, 13, 3), + /* 1100 */ V(14, 6, 2), + /* 1101 */ V(14, 6, 2), + /* 1110 */ V(14, 6, 2), + /* 1111 */ V(14, 6, 2), + + /* 0100 0001 ... */ + /* 000 */ V(6, 14, 3), /* 220 */ + /* 001 */ V(9, 12, 3), + /* 010 */ V(12, 9, 2), + /* 011 */ V(12, 9, 2), + /* 100 */ V(5, 14, 2), + /* 101 */ V(5, 14, 2), + /* 110 */ V(11, 10, 2), + /* 111 */ V(11, 10, 2), + + /* 0100 0010 ... */ + /* 000 */ V(14, 5, 2), /* 228 */ + /* 001 */ V(14, 5, 2), + /* 010 */ V(10, 11, 3), + /* 011 */ V(7, 13, 3), + /* 100 */ V(13, 7, 2), + /* 101 */ V(13, 7, 2), + /* 110 */ V(14, 4, 2), + /* 111 */ V(14, 4, 2), + + /* 0100 0011 ... */ + /* 000 */ V(8, 12, 2), /* 236 */ + /* 001 */ V(8, 12, 2), + /* 010 */ V(12, 8, 2), + /* 011 */ V(12, 8, 2), + /* 100 */ V(4, 14, 3), + /* 101 */ V(2, 14, 3), + /* 110 */ V(3, 14, 2), + /* 111 */ V(3, 14, 2), + + /* 0100 0100 ... */ + /* 00 */ V(6, 13, 2), /* 244 */ + /* 01 */ V(13, 6, 2), + /* 10 */ V(14, 3, 2), + /* 11 */ V(9, 11, 2), + + /* 0100 0101 ... */ + /* 00 */ V(11, 9, 2), /* 248 */ + /* 01 */ V(10, 10, 2), + /* 10 */ V(14, 2, 2), + /* 11 */ V(1, 14, 2), + + /* 0100 0110 ... */ + /* 00 */ V(14, 1, 2), /* 252 */ + /* 01 */ V(5, 13, 2), + /* 10 */ V(13, 5, 2), + /* 11 */ V(7, 12, 2), + + /* 0100 0111 ... */ + /* 00 */ V(12, 7, 2), /* 256 */ + /* 01 */ V(4, 13, 2), + /* 10 */ V(8, 11, 2), + /* 11 */ V(11, 8, 2), + + /* 0100 1000 ... */ + /* 00 */ V(13, 4, 2), /* 260 */ + /* 01 */ V(9, 10, 2), + /* 10 */ V(10, 9, 2), + /* 11 */ V(6, 12, 2), + + /* 0100 1001 ... */ + /* 00 */ V(12, 6, 2), /* 264 */ + /* 01 */ V(3, 13, 2), + /* 10 */ V(13, 3, 2), + /* 11 */ V(2, 13, 2), + + /* 0100 1010 ... */ + /* 00 */ V(13, 2, 2), /* 268 */ + /* 01 */ V(1, 13, 2), + /* 10 */ V(7, 11, 2), + /* 11 */ V(11, 7, 2), + + /* 0100 1011 ... */ + /* 00 */ V(13, 1, 2), /* 272 */ + /* 01 */ V(5, 12, 2), + /* 10 */ V(12, 5, 2), + /* 11 */ V(8, 10, 2), + + /* 0100 1100 ... */ + /* 00 */ V(10, 8, 2), /* 276 */ + /* 01 */ V(9, 9, 2), + /* 10 */ V(4, 12, 2), + /* 11 */ V(12, 4, 2), + + /* 0100 1101 ... */ + /* 000 */ V(6, 11, 2), /* 280 */ + /* 001 */ V(6, 11, 2), + /* 010 */ V(11, 6, 2), + /* 011 */ V(11, 6, 2), + /* 100 */ V(13, 0, 3), + /* 101 */ V(0, 12, 3), + /* 110 */ V(3, 12, 2), + /* 111 */ V(3, 12, 2), + + /* 0100 1110 ... */ + /* 00 */ V(12, 3, 2), /* 288 */ + /* 01 */ V(7, 10, 2), + /* 10 */ V(10, 7, 2), + /* 11 */ V(2, 12, 2), + + /* 0100 1111 ... */ + /* 00 */ V(12, 2, 2), /* 292 */ + /* 01 */ V(5, 11, 2), + /* 10 */ V(11, 5, 2), + /* 11 */ V(1, 12, 2), + + /* 0101 0000 ... */ + /* 00 */ V(8, 9, 2), /* 296 */ + /* 01 */ V(9, 8, 2), + /* 10 */ V(12, 1, 2), + /* 11 */ V(4, 11, 2), + + /* 0101 0001 ... */ + /* 000 */ V(12, 0, 3), /* 300 */ + /* 001 */ V(0, 11, 3), + /* 010 */ V(3, 11, 2), + /* 011 */ V(3, 11, 2), + /* 100 */ V(11, 0, 3), + /* 101 */ V(0, 10, 3), + /* 110 */ V(1, 10, 2), + /* 111 */ V(1, 10, 2), + + /* 0101 0010 ... */ + /* 00 */ V(11, 4, 1), /* 308 */ + /* 01 */ V(11, 4, 1), + /* 10 */ V(6, 10, 2), + /* 11 */ V(10, 6, 2), + + /* 0101 0011 ... */ + /* 000 */ V(7, 9, 2), /* 312 */ + /* 001 */ V(7, 9, 2), + /* 010 */ V(9, 7, 2), + /* 011 */ V(9, 7, 2), + /* 100 */ V(10, 0, 3), + /* 101 */ V(0, 9, 3), + /* 110 */ V(9, 0, 2), + /* 111 */ V(9, 0, 2), + + /* 0101 0100 ... */ + /* 0 */ V(11, 3, 1), /* 320 */ + /* 1 */ V(8, 8, 1), + + /* 0101 0101 ... */ + /* 00 */ V(2, 11, 2), /* 322 */ + /* 01 */ V(5, 10, 2), + /* 10 */ V(11, 2, 1), + /* 11 */ V(11, 2, 1), + + /* 0101 0110 ... */ + /* 00 */ V(10, 5, 2), /* 326 */ + /* 01 */ V(1, 11, 2), + /* 10 */ V(11, 1, 2), + /* 11 */ V(6, 9, 2), + + /* 0101 0111 ... */ + /* 0 */ V(9, 6, 1), /* 330 */ + /* 1 */ V(10, 4, 1), + + /* 0101 1000 ... */ + /* 00 */ V(4, 10, 2), /* 332 */ + /* 01 */ V(7, 8, 2), + /* 10 */ V(8, 7, 1), + /* 11 */ V(8, 7, 1), + + /* 0101 1001 ... */ + /* 0 */ V(3, 10, 1), /* 336 */ + /* 1 */ V(10, 3, 1), + + /* 0101 1010 ... */ + /* 0 */ V(5, 9, 1), /* 338 */ + /* 1 */ V(9, 5, 1), + + /* 0101 1011 ... */ + /* 0 */ V(2, 10, 1), /* 340 */ + /* 1 */ V(10, 2, 1), + + /* 0101 1100 ... */ + /* 0 */ V(10, 1, 1), /* 342 */ + /* 1 */ V(6, 8, 1), + + /* 0101 1101 ... */ + /* 0 */ V(8, 6, 1), /* 344 */ + /* 1 */ V(7, 7, 1), + + /* 0101 1110 ... */ + /* 0 */ V(4, 9, 1), /* 346 */ + /* 1 */ V(9, 4, 1), + + /* 0101 1111 ... */ + /* 0 */ V(3, 9, 1), /* 348 */ + /* 1 */ V(9, 3, 1), + + /* 0110 0000 ... */ + /* 0 */ V(5, 8, 1), /* 350 */ + /* 1 */ V(8, 5, 1), + + /* 0110 0001 ... */ + /* 0 */ V(2, 9, 1), /* 352 */ + /* 1 */ V(6, 7, 1), + + /* 0110 0010 ... */ + /* 0 */ V(7, 6, 1), /* 354 */ + /* 1 */ V(9, 2, 1), + + /* 0110 0011 ... */ + /* 0 */ V(1, 9, 1), /* 356 */ + /* 1 */ V(9, 1, 1), + + /* 0110 0100 ... */ + /* 0 */ V(4, 8, 1), /* 358 */ + /* 1 */ V(8, 4, 1), + + /* 0110 0101 ... */ + /* 0 */ V(5, 7, 1), /* 360 */ + /* 1 */ V(7, 5, 1), + + /* 0110 0110 ... */ + /* 0 */ V(3, 8, 1), /* 362 */ + /* 1 */ V(8, 3, 1), + + /* 0110 0111 ... */ + /* 0 */ V(6, 6, 1), /* 364 */ + /* 1 */ V(2, 8, 1), + + /* 0110 1000 ... */ + /* 0 */ V(8, 2, 1), /* 366 */ + /* 1 */ V(1, 8, 1), + + /* 0110 1001 ... */ + /* 0 */ V(4, 7, 1), /* 368 */ + /* 1 */ V(7, 4, 1), + + /* 0110 1010 ... */ + /* 00 */ V(8, 1, 1), /* 370 */ + /* 01 */ V(8, 1, 1), + /* 10 */ V(0, 8, 2), + /* 11 */ V(8, 0, 2), + + /* 0110 1011 ... */ + /* 0 */ V(5, 6, 1), /* 374 */ + /* 1 */ V(6, 5, 1), + + /* 0110 1100 ... */ + /* 00 */ V(1, 7, 1), /* 376 */ + /* 01 */ V(1, 7, 1), + /* 10 */ V(0, 7, 2), + /* 11 */ V(7, 0, 2), + + /* 0110 1110 ... */ + /* 0 */ V(3, 7, 1), /* 380 */ + /* 1 */ V(2, 7, 1), + + /* 0111 1100 ... */ + /* 0 */ V(0, 6, 1), /* 382 */ + /* 1 */ V(6, 0, 1), + + /* 1000 0011 ... */ + /* 0 */ V(0, 5, 1), /* 384 */ + /* 1 */ V(5, 0, 1) +}; + +# undef V +# undef PTR + +/* external tables */ + +union huffquad const *const mad_huff_quad_table[2] = { hufftabA, hufftabB }; + +struct hufftable const mad_huff_pair_table[32] = { + /* 0 */ { hufftab0, 0, 0 }, + /* 1 */ { hufftab1, 0, 3 }, + /* 2 */ { hufftab2, 0, 3 }, + /* 3 */ { hufftab3, 0, 3 }, + /* 4 */ { 0 /* not used */ }, + /* 5 */ { hufftab5, 0, 3 }, + /* 6 */ { hufftab6, 0, 4 }, + /* 7 */ { hufftab7, 0, 4 }, + /* 8 */ { hufftab8, 0, 4 }, + /* 9 */ { hufftab9, 0, 4 }, + /* 10 */ { hufftab10, 0, 4 }, + /* 11 */ { hufftab11, 0, 4 }, + /* 12 */ { hufftab12, 0, 4 }, + /* 13 */ { hufftab13, 0, 4 }, + /* 14 */ { 0 /* not used */ }, + /* 15 */ { hufftab15, 0, 4 }, + /* 16 */ { hufftab16, 1, 4 }, + /* 17 */ { hufftab16, 2, 4 }, + /* 18 */ { hufftab16, 3, 4 }, + /* 19 */ { hufftab16, 4, 4 }, + /* 20 */ { hufftab16, 6, 4 }, + /* 21 */ { hufftab16, 8, 4 }, + /* 22 */ { hufftab16, 10, 4 }, + /* 23 */ { hufftab16, 13, 4 }, + /* 24 */ { hufftab24, 4, 4 }, + /* 25 */ { hufftab24, 5, 4 }, + /* 26 */ { hufftab24, 6, 4 }, + /* 27 */ { hufftab24, 7, 4 }, + /* 28 */ { hufftab24, 8, 4 }, + /* 29 */ { hufftab24, 9, 4 }, + /* 30 */ { hufftab24, 11, 4 }, + /* 31 */ { hufftab24, 13, 4 } +}; diff --git a/code/libmad/huffman.h b/code/libmad/huffman.h new file mode 100644 index 00000000..6325db44 --- /dev/null +++ b/code/libmad/huffman.h @@ -0,0 +1,66 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: huffman.h,v 1.11 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBMAD_HUFFMAN_H +# define LIBMAD_HUFFMAN_H + +union huffquad { + struct { + unsigned short final : 1; + unsigned short bits : 3; + unsigned short offset : 12; + } ptr; + struct { + unsigned short final : 1; + unsigned short hlen : 3; + unsigned short v : 1; + unsigned short w : 1; + unsigned short x : 1; + unsigned short y : 1; + } value; + unsigned short final : 1; +}; + +union huffpair { + struct { + unsigned short final : 1; + unsigned short bits : 3; + unsigned short offset : 12; + } ptr; + struct { + unsigned short final : 1; + unsigned short hlen : 3; + unsigned short x : 4; + unsigned short y : 4; + } value; + unsigned short final : 1; +}; + +struct hufftable { + union huffpair const *table; + unsigned short linbits; + unsigned short startbits; +}; + +extern union huffquad const *const mad_huff_quad_table[2]; +extern struct hufftable const mad_huff_pair_table[32]; + +# endif diff --git a/code/libmad/imdct_l_arm.S b/code/libmad/imdct_l_arm.S new file mode 100644 index 00000000..92d67e1a --- /dev/null +++ b/code/libmad/imdct_l_arm.S @@ -0,0 +1,1000 @@ +/***************************************************************************** +* Copyright (C) 2000-2001 Andre McCurdy +* +* 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 +* the Free Software Foundation@ either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY, without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program@ if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +***************************************************************************** +* +* Notes: +* +* +***************************************************************************** +* +* $Id: imdct_l_arm.S,v 1.7 2001/03/25 20:03:34 rob Rel $ +* +* 2001/03/24: Andre McCurdy +* - Corrected PIC unsafe loading of address of 'imdct36_long_karray' +* +* 2000/09/20: Robert Leslie +* - Added a global symbol with leading underscore per suggestion of +* Simon Burge to support linking with the a.out format. +* +* 2000/09/15: Robert Leslie +* - Fixed a small bug where flags were changed before a conditional branch. +* +* 2000/09/15: Andre McCurdy +* - Applied Nicolas Pitre's rounding optimisation in all remaining places. +* +* 2000/09/09: Nicolas Pitre +* - Optimized rounding + scaling operations. +* +* 2000/08/09: Andre McCurdy +* - Original created. +* +****************************************************************************/ + + +/* + On entry: + + r0 = pointer to 18 element input array + r1 = pointer to 36 element output array + r2 = windowing block type + + + Stack frame created during execution of the function: + + Initial Holds: + Stack + pointer + minus: + + 0 + 4 lr + 8 r11 + 12 r10 + 16 r9 + 20 r8 + 24 r7 + 28 r6 + 32 r5 + 36 r4 + + 40 r2 : windowing block type + + 44 ct00 high + 48 ct00 low + 52 ct01 high + 56 ct01 low + 60 ct04 high + 64 ct04 low + 68 ct06 high + 72 ct06 low + 76 ct05 high + 80 ct05 low + 84 ct03 high + 88 ct03 low + 92 -ct05 high + 96 -ct05 low + 100 -ct07 high + 104 -ct07 low + 108 ct07 high + 112 ct07 low + 116 ct02 high + 120 ct02 low +*/ + +#define BLOCK_MODE_NORMAL 0 +#define BLOCK_MODE_START 1 +#define BLOCK_MODE_STOP 3 + + +#define X0 0x00 +#define X1 0x04 +#define X2 0x08 +#define X3 0x0C +#define X4 0x10 +#define X5 0x14 +#define X6 0x18 +#define X7 0x1c +#define X8 0x20 +#define X9 0x24 +#define X10 0x28 +#define X11 0x2c +#define X12 0x30 +#define X13 0x34 +#define X14 0x38 +#define X15 0x3c +#define X16 0x40 +#define X17 0x44 + +#define x0 0x00 +#define x1 0x04 +#define x2 0x08 +#define x3 0x0C +#define x4 0x10 +#define x5 0x14 +#define x6 0x18 +#define x7 0x1c +#define x8 0x20 +#define x9 0x24 +#define x10 0x28 +#define x11 0x2c +#define x12 0x30 +#define x13 0x34 +#define x14 0x38 +#define x15 0x3c +#define x16 0x40 +#define x17 0x44 +#define x18 0x48 +#define x19 0x4c +#define x20 0x50 +#define x21 0x54 +#define x22 0x58 +#define x23 0x5c +#define x24 0x60 +#define x25 0x64 +#define x26 0x68 +#define x27 0x6c +#define x28 0x70 +#define x29 0x74 +#define x30 0x78 +#define x31 0x7c +#define x32 0x80 +#define x33 0x84 +#define x34 0x88 +#define x35 0x8c + +#define K00 0x0ffc19fd +#define K01 0x00b2aa3e +#define K02 0x0fdcf549 +#define K03 0x0216a2a2 +#define K04 0x0f9ee890 +#define K05 0x03768962 +#define K06 0x0f426cb5 +#define K07 0x04cfb0e2 +#define K08 0x0ec835e8 +#define K09 0x061f78aa +#define K10 0x0e313245 +#define K11 0x07635284 +#define K12 0x0d7e8807 +#define K13 0x0898c779 +#define K14 0x0cb19346 +#define K15 0x09bd7ca0 +#define K16 0x0bcbe352 +#define K17 0x0acf37ad + +#define minus_K02 0xf0230ab7 + +#define WL0 0x00b2aa3e +#define WL1 0x0216a2a2 +#define WL2 0x03768962 +#define WL3 0x04cfb0e2 +#define WL4 0x061f78aa +#define WL5 0x07635284 +#define WL6 0x0898c779 +#define WL7 0x09bd7ca0 +#define WL8 0x0acf37ad +#define WL9 0x0bcbe352 +#define WL10 0x0cb19346 +#define WL11 0x0d7e8807 +#define WL12 0x0e313245 +#define WL13 0x0ec835e8 +#define WL14 0x0f426cb5 +#define WL15 0x0f9ee890 +#define WL16 0x0fdcf549 +#define WL17 0x0ffc19fd + + +@***************************************************************************** + + + .text + .align + + .global III_imdct_l + .global _III_imdct_l + +III_imdct_l: +_III_imdct_l: + + stmdb sp!, { r2, r4 - r11, lr } @ all callee saved regs, plus arg3 + + ldr r4, =K08 @ r4 = K08 + ldr r5, =K09 @ r5 = K09 + ldr r8, [r0, #X4] @ r8 = X4 + ldr r9, [r0, #X13] @ r9 = X13 + rsb r6, r4, #0 @ r6 = -K08 + rsb r7, r5, #0 @ r7 = -K09 + + smull r2, r3, r4, r8 @ r2..r3 = (X4 * K08) + smlal r2, r3, r5, r9 @ r2..r3 = (X4 * K08) + (X13 * K09) = ct01 + + smull r10, lr, r8, r5 @ r10..lr = (X4 * K09) + smlal r10, lr, r9, r6 @ r10..lr = (X4 * K09) + (X13 * -K08) = ct00 + + ldr r8, [r0, #X7] @ r8 = X7 + ldr r9, [r0, #X16] @ r9 = X16 + + stmdb sp!, { r2, r3, r10, lr } @ stack ct00_h, ct00_l, ct01_h, ct01_l + + add r8, r8, r9 @ r8 = (X7 + X16) + ldr r9, [r0, #X1] @ r9 = X1 + + smlal r2, r3, r6, r8 @ r2..r3 = ct01 + ((X7 + X16) * -K08) + smlal r2, r3, r7, r9 @ r2..r3 += (X1 * -K09) + + ldr r7, [r0, #X10] @ r7 = X10 + + rsbs r10, r10, #0 + rsc lr, lr, #0 @ r10..lr = -ct00 + + smlal r2, r3, r5, r7 @ r2..r3 += (X10 * K09) = ct06 + + smlal r10, lr, r9, r6 @ r10..lr = -ct00 + ( X1 * -K08) + smlal r10, lr, r8, r5 @ r10..lr += ((X7 + X16) * K09) + smlal r10, lr, r7, r4 @ r10..lr += ( X10 * K08) = ct04 + + stmdb sp!, { r2, r3, r10, lr } @ stack ct04_h, ct04_l, ct06_h, ct06_l + + @---- + + ldr r7, [r0, #X0] + ldr r8, [r0, #X11] + ldr r9, [r0, #X12] + sub r7, r7, r8 + sub r7, r7, r9 @ r7 = (X0 - X11 -X12) = ct14 + + ldr r9, [r0, #X3] + ldr r8, [r0, #X8] + ldr r11, [r0, #X15] + sub r8, r8, r9 + add r8, r8, r11 @ r8 = (X8 - X3 + X15) = ct16 + + add r11, r7, r8 @ r11 = ct14 + ct16 = ct18 + + smlal r2, r3, r6, r11 @ r2..r3 = ct06 + ((X0 - X11 - X3 + X15 + X8 - X12) * -K08) + + ldr r6, [r0, #X2] + ldr r9, [r0, #X9] + ldr r12, [r0, #X14] + sub r6, r6, r9 + sub r6, r6, r12 @ r6 = (X2 - X9 - X14) = ct15 + + ldr r9, [r0, #X5] + ldr r12, [r0, #X6] + sub r9, r9, r12 + ldr r12, [r0, #X17] + sub r9, r9, r12 @ r9 = (X5 - X6 - X17) = ct17 + + add r12, r9, r6 @ r12 = ct15 + ct17 = ct19 + + smlal r2, r3, r5, r12 @ r2..r3 += ((X2 - X9 + X5 - X6 - X17 - X14) * K09) + + smlal r10, lr, r11, r5 @ r10..lr = ct04 + (ct18 * K09) + smlal r10, lr, r12, r4 @ r10..lr = ct04 + (ct18 * K09) + (ct19 * K08) + + movs r2, r2, lsr #28 + adc r2, r2, r3, lsl #4 @ r2 = bits[59..28] of r2..r3 + str r2, [r1, #x22] @ store result x22 + + movs r10, r10, lsr #28 + adc r10, r10, lr, lsl #4 @ r10 = bits[59..28] of r10..lr + str r10, [r1, #x4] @ store result x4 + + @---- + + ldmia sp, { r2, r3, r4, r5 } @ r2..r3 = ct06, r4..r5 = ct04 (dont update sp) + + @ r2..r3 = ct06 + @ r4..r5 = ct04 + @ r6 = ct15 + @ r7 = ct14 + @ r8 = ct16 + @ r9 = ct17 + @ r10 = . + @ r11 = . + @ r12 = . + @ lr = . + + ldr r10, =K03 @ r10 = K03 + ldr lr, =K15 @ lr = K15 + + smlal r2, r3, r10, r7 @ r2..r3 = ct06 + (ct14 * K03) + smlal r4, r5, lr, r7 @ r4..r5 = ct04 + (ct14 * K15) + + ldr r12, =K14 @ r12 = K14 + rsb r10, r10, #0 @ r10 = -K03 + + smlal r2, r3, lr, r6 @ r2..r3 += (ct15 * K15) + smlal r4, r5, r10, r6 @ r4..r5 += (ct15 * -K03) + smlal r2, r3, r12, r8 @ r2..r3 += (ct16 * K14) + + ldr r11, =minus_K02 @ r11 = -K02 + rsb r12, r12, #0 @ r12 = -K14 + + smlal r4, r5, r12, r9 @ r4..r5 += (ct17 * -K14) + smlal r2, r3, r11, r9 @ r2..r3 += (ct17 * -K02) + smlal r4, r5, r11, r8 @ r4..r5 += (ct16 * -K02) + + movs r2, r2, lsr #28 + adc r2, r2, r3, lsl #4 @ r2 = bits[59..28] of r2..r3 + str r2, [r1, #x7] @ store result x7 + + movs r4, r4, lsr #28 + adc r4, r4, r5, lsl #4 @ r4 = bits[59..28] of r4..r5 + str r4, [r1, #x1] @ store result x1 + + @---- + + ldmia sp, { r2, r3, r4, r5 } @ r2..r3 = ct06, r4..r5 = ct04 (dont update sp) + + @ r2..r3 = ct06 + @ r4..r5 = ct04 + @ r6 = ct15 + @ r7 = ct14 + @ r8 = ct16 + @ r9 = ct17 + @ r10 = -K03 + @ r11 = -K02 + @ r12 = -K14 + @ lr = K15 + + rsbs r2, r2, #0 + rsc r3, r3, #0 @ r2..r3 = -ct06 + + smlal r2, r3, r12, r7 @ r2..r3 = -ct06 + (ct14 * -K14) + smlal r2, r3, r10, r8 @ r2..r3 += (ct16 * -K03) + + smlal r4, r5, r12, r6 @ r4..r5 = ct04 + (ct15 * -K14) + smlal r4, r5, r10, r9 @ r4..r5 += (ct17 * -K03) + smlal r4, r5, lr, r8 @ r4..r5 += (ct16 * K15) + smlal r4, r5, r11, r7 @ r4..r5 += (ct14 * -K02) + + rsb lr, lr, #0 @ lr = -K15 + rsb r11, r11, #0 @ r11 = K02 + + smlal r2, r3, lr, r9 @ r2..r3 += (ct17 * -K15) + smlal r2, r3, r11, r6 @ r2..r3 += (ct15 * K02) + + movs r4, r4, lsr #28 + adc r4, r4, r5, lsl #4 @ r4 = bits[59..28] of r4..r5 + str r4, [r1, #x25] @ store result x25 + + movs r2, r2, lsr #28 + adc r2, r2, r3, lsl #4 @ r2 = bits[59..28] of r2..r3 + str r2, [r1, #x19] @ store result x19 + + @---- + + ldr r2, [sp, #16] @ r2 = ct01_l + ldr r3, [sp, #20] @ r3 = ct01_h + + ldr r6, [r0, #X1] + ldr r8, [r0, #X7] + ldr r9, [r0, #X10] + ldr r7, [r0, #X16] + + rsbs r2, r2, #0 + rsc r3, r3, #0 @ r2..r3 = -ct01 + + mov r4, r2 + mov r5, r3 @ r4..r5 = -ct01 + + @ r2..r3 = -ct01 + @ r4..r5 = -ct01 + @ r6 = X1 + @ r7 = X16 + @ r8 = X7 + @ r9 = X10 + @ r10 = -K03 + @ r11 = K02 + @ r12 = -K14 + @ lr = -K15 + + smlal r4, r5, r12, r7 @ r4..r5 = -ct01 + (X16 * -K14) + smlal r2, r3, lr, r9 @ r2..r3 = -ct01 + (X10 * -K15) + + smlal r4, r5, r10, r8 @ r4..r5 += (X7 * -K03) + smlal r2, r3, r10, r7 @ r2..r3 += (X16 * -K03) + + smlal r4, r5, r11, r9 @ r4..r5 += (X10 * K02) + smlal r2, r3, r12, r8 @ r2..r3 += (X7 * -K14) + + rsb lr, lr, #0 @ lr = K15 + rsb r11, r11, #0 @ r11 = -K02 + + smlal r4, r5, lr, r6 @ r4..r5 += (X1 * K15) = ct05 + smlal r2, r3, r11, r6 @ r2..r3 += (X1 * -K02) = ct03 + + stmdb sp!, { r2, r3, r4, r5 } @ stack ct05_h, ct05_l, ct03_h, ct03_l + + rsbs r4, r4, #0 + rsc r5, r5, #0 @ r4..r5 = -ct05 + + stmdb sp!, { r4, r5 } @ stack -ct05_h, -ct05_l + + ldr r2, [sp, #48] @ r2 = ct00_l + ldr r3, [sp, #52] @ r3 = ct00_h + + rsb r10, r10, #0 @ r10 = K03 + + rsbs r4, r2, #0 + rsc r5, r3, #0 @ r4..r5 = -ct00 + + @ r2..r3 = ct00 + @ r4..r5 = -ct00 + @ r6 = X1 + @ r7 = X16 + @ r8 = X7 + @ r9 = X10 + @ r10 = K03 + @ r11 = -K02 + @ r12 = -K14 + @ lr = K15 + + smlal r4, r5, r10, r6 @ r4..r5 = -ct00 + (X1 * K03) + smlal r2, r3, r10, r9 @ r2..r3 = ct00 + (X10 * K03) + + smlal r4, r5, r12, r9 @ r4..r5 += (X10 * -K14) + smlal r2, r3, r12, r6 @ r2..r3 += (X1 * -K14) + + smlal r4, r5, r11, r7 @ r4..r5 += (X16 * -K02) + smlal r4, r5, lr, r8 @ r4..r5 += (X7 * K15) = ct07 + + rsb lr, lr, #0 @ lr = -K15 + rsb r11, r11, #0 @ r11 = K02 + + smlal r2, r3, r11, r8 @ r2..r3 += (X7 * K02) + smlal r2, r3, lr, r7 @ r2..r3 += (X16 * -K15) = ct02 + + rsbs r6, r4, #0 + rsc r7, r5, #0 @ r6..r7 = -ct07 + + stmdb sp!, { r2 - r7 } @ stack -ct07_h, -ct07_l, ct07_h, ct07_l, ct02_h, ct02_l + + + @---- + + adr r2, imdct36_long_karray + + +loop: + ldr r12, [r0, #X0] + + ldmia r2!, { r5 - r11 } @ first 7 words from Karray element + + smull r3, r4, r5, r12 @ sum = (Kxx * X0) + ldr r12, [r0, #X2] + ldr r5, [r0, #X3] + smlal r3, r4, r6, r12 @ sum += (Kxx * X2) + ldr r12, [r0, #X5] + ldr r6, [r0, #X6] + smlal r3, r4, r7, r5 @ sum += (Kxx * X3) + smlal r3, r4, r8, r12 @ sum += (Kxx * X5) + ldr r12, [r0, #X8] + ldr r5, [r0, #X9] + smlal r3, r4, r9, r6 @ sum += (Kxx * X6) + smlal r3, r4, r10, r12 @ sum += (Kxx * X8) + smlal r3, r4, r11, r5 @ sum += (Kxx * X9) + + ldmia r2!, { r5 - r10 } @ final 6 words from Karray element + + ldr r11, [r0, #X11] + ldr r12, [r0, #X12] + smlal r3, r4, r5, r11 @ sum += (Kxx * X11) + ldr r11, [r0, #X14] + ldr r5, [r0, #X15] + smlal r3, r4, r6, r12 @ sum += (Kxx * X12) + smlal r3, r4, r7, r11 @ sum += (Kxx * X14) + ldr r11, [r0, #X17] + smlal r3, r4, r8, r5 @ sum += (Kxx * X15) + smlal r3, r4, r9, r11 @ sum += (Kxx * X17) + + add r5, sp, r10, lsr #16 @ create index back into stack for required ctxx + + ldmia r5, { r6, r7 } @ r6..r7 = ctxx + + mov r8, r10, lsl #16 @ push ctxx index off the top end + + adds r3, r3, r6 @ add low words + adc r4, r4, r7 @ add high words, with carry + movs r3, r3, lsr #28 + adc r3, r3, r4, lsl #4 @ r3 = bits[59..28] of r3..r4 + + str r3, [r1, r8, lsr #24] @ push completion flag off the bottom end + + movs r8, r8, lsl #8 @ push result location index off the top end + beq loop @ loop back if completion flag not set + b imdct_l_windowing @ branch to windowing stage if looping finished + +imdct36_long_karray: + + .word K17, -K13, K10, -K06, -K05, K01, -K00, K04, -K07, K11, K12, -K16, 0x00000000 + .word K13, K07, K16, K01, K10, -K05, K04, -K11, K00, -K17, K06, -K12, 0x00200800 + .word K11, K17, K05, K12, -K01, K06, -K07, K00, -K13, K04, -K16, K10, 0x00200c00 + .word K07, K00, -K12, K05, -K16, -K10, K11, -K17, K04, K13, K01, K06, 0x00001400 + .word K05, K10, -K00, -K17, K07, -K13, K12, K06, -K16, K01, -K11, -K04, 0x00181800 + .word K01, K05, -K07, -K11, K13, K17, -K16, -K12, K10, K06, -K04, -K00, 0x00102000 + .word -K16, K12, -K11, K07, K04, -K00, -K01, K05, -K06, K10, K13, -K17, 0x00284800 + .word -K12, K06, K17, -K00, -K11, K04, K05, -K10, K01, K16, -K07, -K13, 0x00085000 + .word -K10, K16, K04, -K13, -K00, K07, K06, -K01, -K12, -K05, K17, K11, 0x00105400 + .word -K06, -K01, K13, K04, K17, -K11, -K10, -K16, -K05, K12, K00, K07, 0x00185c00 + .word -K04, -K11, -K01, K16, K06, K12, K13, -K07, -K17, -K00, -K10, -K05, 0x00006000 + .word -K00, -K04, -K06, -K10, -K12, -K16, -K17, -K13, -K11, -K07, -K05, -K01, 0x00206801 + + + @---- + @------------------------------------------------------------------------- + @---- + +imdct_l_windowing: + + ldr r11, [sp, #80] @ fetch function parameter 3 from out of the stack + ldmia r1!, { r0, r2 - r9 } @ load 9 words from x0, update pointer + + @ r0 = x0 + @ r1 = &x[9] + @ r2 = x1 + @ r3 = x2 + @ r4 = x3 + @ r5 = x4 + @ r6 = x5 + @ r7 = x6 + @ r8 = x7 + @ r9 = x8 + @ r10 = . + @ r11 = window mode: (0 == normal), (1 == start block), (3 == stop block) + @ r12 = . + @ lr = . + + cmp r11, #BLOCK_MODE_STOP @ setup flags + rsb r10, r0, #0 @ r10 = -x0 (DONT change flags !!) + beq stop_block_x0_to_x17 + + + @ start and normal blocks are treated the same for x[0]..x[17] + +normal_block_x0_to_x17: + + ldr r12, =WL9 @ r12 = window_l[9] + + rsb r0, r9, #0 @ r0 = -x8 + rsb r9, r2, #0 @ r9 = -x1 + rsb r2, r8, #0 @ r2 = -x7 + rsb r8, r3, #0 @ r8 = -x2 + rsb r3, r7, #0 @ r3 = -x6 + rsb r7, r4, #0 @ r7 = -x3 + rsb r4, r6, #0 @ r4 = -x5 + rsb r6, r5, #0 @ r6 = -x4 + + @ r0 = -x8 + @ r1 = &x[9] + @ r2 = -x7 + @ r3 = -x6 + @ r4 = -x5 + @ r5 = . + @ r6 = -x4 + @ r7 = -x3 + @ r8 = -x2 + @ r9 = -x1 + @ r10 = -x0 + @ r11 = window mode: (0 == normal), (1 == start block), (3 == stop block) + @ r12 = window_l[9] + @ lr = . + + smull r5, lr, r12, r0 @ r5..lr = (window_l[9] * (x[9] == -x[8])) + ldr r12, =WL10 @ r12 = window_l[10] + movs r5, r5, lsr #28 + adc r0, r5, lr, lsl #4 @ r0 = bits[59..28] of windowed x9 + + smull r5, lr, r12, r2 @ r5..lr = (window_l[10] * (x[10] == -x[7])) + ldr r12, =WL11 @ r12 = window_l[11] + movs r5, r5, lsr #28 + adc r2, r5, lr, lsl #4 @ r2 = bits[59..28] of windowed x10 + + smull r5, lr, r12, r3 @ r5..lr = (window_l[11] * (x[11] == -x[6])) + ldr r12, =WL12 @ r12 = window_l[12] + movs r5, r5, lsr #28 + adc r3, r5, lr, lsl #4 @ r3 = bits[59..28] of windowed x11 + + smull r5, lr, r12, r4 @ r5..lr = (window_l[12] * (x[12] == -x[5])) + ldr r12, =WL13 @ r12 = window_l[13] + movs r5, r5, lsr #28 + adc r4, r5, lr, lsl #4 @ r4 = bits[59..28] of windowed x12 + + smull r5, lr, r12, r6 @ r5..lr = (window_l[13] * (x[13] == -x[4])) + ldr r12, =WL14 @ r12 = window_l[14] + movs r5, r5, lsr #28 + adc r6, r5, lr, lsl #4 @ r6 = bits[59..28] of windowed x13 + + smull r5, lr, r12, r7 @ r5..lr = (window_l[14] * (x[14] == -x[3])) + ldr r12, =WL15 @ r12 = window_l[15] + movs r5, r5, lsr #28 + adc r7, r5, lr, lsl #4 @ r7 = bits[59..28] of windowed x14 + + smull r5, lr, r12, r8 @ r5..lr = (window_l[15] * (x[15] == -x[2])) + ldr r12, =WL16 @ r12 = window_l[16] + movs r5, r5, lsr #28 + adc r8, r5, lr, lsl #4 @ r8 = bits[59..28] of windowed x15 + + smull r5, lr, r12, r9 @ r5..lr = (window_l[16] * (x[16] == -x[1])) + ldr r12, =WL17 @ r12 = window_l[17] + movs r5, r5, lsr #28 + adc r9, r5, lr, lsl #4 @ r9 = bits[59..28] of windowed x16 + + smull r5, lr, r12, r10 @ r5..lr = (window_l[17] * (x[17] == -x[0])) + ldr r12, =WL0 @ r12 = window_l[0] + movs r5, r5, lsr #28 + adc r10, r5, lr, lsl #4 @ r10 = bits[59..28] of windowed x17 + + + stmia r1, { r0, r2 - r4, r6 - r10 } @ store windowed x[9] .. x[17] + ldmdb r1!, { r0, r2 - r9 } @ load 9 words downto (and including) x0 + + + smull r10, lr, r12, r0 @ r10..lr = (window_l[0] * x[0]) + ldr r12, =WL1 @ r12 = window_l[1] + movs r10, r10, lsr #28 + adc r0, r10, lr, lsl #4 @ r0 = bits[59..28] of windowed x0 + + smull r10, lr, r12, r2 @ r10..lr = (window_l[1] * x[1]) + ldr r12, =WL2 @ r12 = window_l[2] + movs r10, r10, lsr #28 + adc r2, r10, lr, lsl #4 @ r2 = bits[59..28] of windowed x1 + + smull r10, lr, r12, r3 @ r10..lr = (window_l[2] * x[2]) + ldr r12, =WL3 @ r12 = window_l[3] + movs r10, r10, lsr #28 + adc r3, r10, lr, lsl #4 @ r3 = bits[59..28] of windowed x2 + + smull r10, lr, r12, r4 @ r10..lr = (window_l[3] * x[3]) + ldr r12, =WL4 @ r12 = window_l[4] + movs r10, r10, lsr #28 + adc r4, r10, lr, lsl #4 @ r4 = bits[59..28] of windowed x3 + + smull r10, lr, r12, r5 @ r10..lr = (window_l[4] * x[4]) + ldr r12, =WL5 @ r12 = window_l[5] + movs r10, r10, lsr #28 + adc r5, r10, lr, lsl #4 @ r5 = bits[59..28] of windowed x4 + + smull r10, lr, r12, r6 @ r10..lr = (window_l[5] * x[5]) + ldr r12, =WL6 @ r12 = window_l[6] + movs r10, r10, lsr #28 + adc r6, r10, lr, lsl #4 @ r6 = bits[59..28] of windowed x5 + + smull r10, lr, r12, r7 @ r10..lr = (window_l[6] * x[6]) + ldr r12, =WL7 @ r12 = window_l[7] + movs r10, r10, lsr #28 + adc r7, r10, lr, lsl #4 @ r7 = bits[59..28] of windowed x6 + + smull r10, lr, r12, r8 @ r10..lr = (window_l[7] * x[7]) + ldr r12, =WL8 @ r12 = window_l[8] + movs r10, r10, lsr #28 + adc r8, r10, lr, lsl #4 @ r8 = bits[59..28] of windowed x7 + + smull r10, lr, r12, r9 @ r10..lr = (window_l[8] * x[8]) + movs r10, r10, lsr #28 + adc r9, r10, lr, lsl #4 @ r9 = bits[59..28] of windowed x8 + + stmia r1, { r0, r2 - r9 } @ store windowed x[0] .. x[8] + + cmp r11, #BLOCK_MODE_START + beq start_block_x18_to_x35 + + + @---- + + +normal_block_x18_to_x35: + + ldr r11, =WL3 @ r11 = window_l[3] + ldr r12, =WL4 @ r12 = window_l[4] + + add r1, r1, #(18*4) @ r1 = &x[18] + + ldmia r1!, { r0, r2 - r4, r6 - r10 } @ load 9 words from x18, update pointer + + @ r0 = x18 + @ r1 = &x[27] + @ r2 = x19 + @ r3 = x20 + @ r4 = x21 + @ r5 = . + @ r6 = x22 + @ r7 = x23 + @ r8 = x24 + @ r9 = x25 + @ r10 = x26 + @ r11 = window_l[3] + @ r12 = window_l[4] + @ lr = . + + smull r5, lr, r12, r6 @ r5..lr = (window_l[4] * (x[22] == x[31])) + movs r5, r5, lsr #28 + adc r5, r5, lr, lsl #4 @ r5 = bits[59..28] of windowed x31 + + smull r6, lr, r11, r4 @ r5..lr = (window_l[3] * (x[21] == x[32])) + ldr r12, =WL5 @ r12 = window_l[5] + movs r6, r6, lsr #28 + adc r6, r6, lr, lsl #4 @ r6 = bits[59..28] of windowed x32 + + smull r4, lr, r12, r7 @ r4..lr = (window_l[5] * (x[23] == x[30])) + ldr r11, =WL1 @ r11 = window_l[1] + ldr r12, =WL2 @ r12 = window_l[2] + movs r4, r4, lsr #28 + adc r4, r4, lr, lsl #4 @ r4 = bits[59..28] of windowed x30 + + smull r7, lr, r12, r3 @ r7..lr = (window_l[2] * (x[20] == x[33])) + ldr r12, =WL6 @ r12 = window_l[6] + movs r7, r7, lsr #28 + adc r7, r7, lr, lsl #4 @ r7 = bits[59..28] of windowed x33 + + smull r3, lr, r12, r8 @ r3..lr = (window_l[6] * (x[24] == x[29])) + movs r3, r3, lsr #28 + adc r3, r3, lr, lsl #4 @ r3 = bits[59..28] of windowed x29 + + smull r8, lr, r11, r2 @ r7..lr = (window_l[1] * (x[19] == x[34])) + ldr r12, =WL7 @ r12 = window_l[7] + ldr r11, =WL8 @ r11 = window_l[8] + movs r8, r8, lsr #28 + adc r8, r8, lr, lsl #4 @ r8 = bits[59..28] of windowed x34 + + smull r2, lr, r12, r9 @ r7..lr = (window_l[7] * (x[25] == x[28])) + ldr r12, =WL0 @ r12 = window_l[0] + movs r2, r2, lsr #28 + adc r2, r2, lr, lsl #4 @ r2 = bits[59..28] of windowed x28 + + smull r9, lr, r12, r0 @ r3..lr = (window_l[0] * (x[18] == x[35])) + movs r9, r9, lsr #28 + adc r9, r9, lr, lsl #4 @ r9 = bits[59..28] of windowed x35 + + smull r0, lr, r11, r10 @ r7..lr = (window_l[8] * (x[26] == x[27])) + ldr r11, =WL16 @ r11 = window_l[16] + ldr r12, =WL17 @ r12 = window_l[17] + movs r0, r0, lsr #28 + adc r0, r0, lr, lsl #4 @ r0 = bits[59..28] of windowed x27 + + + stmia r1, { r0, r2 - r9 } @ store windowed x[27] .. x[35] + ldmdb r1!, { r0, r2 - r9 } @ load 9 words downto (and including) x18 + + + smull r10, lr, r12, r0 @ r10..lr = (window_l[17] * x[18]) + movs r10, r10, lsr #28 + adc r0, r10, lr, lsl #4 @ r0 = bits[59..28] of windowed x0 + + smull r10, lr, r11, r2 @ r10..lr = (window_l[16] * x[19]) + ldr r11, =WL14 @ r11 = window_l[14] + ldr r12, =WL15 @ r12 = window_l[15] + movs r10, r10, lsr #28 + adc r2, r10, lr, lsl #4 @ r2 = bits[59..28] of windowed x1 + + smull r10, lr, r12, r3 @ r10..lr = (window_l[15] * x[20]) + movs r10, r10, lsr #28 + adc r3, r10, lr, lsl #4 @ r3 = bits[59..28] of windowed x2 + + smull r10, lr, r11, r4 @ r10..lr = (window_l[14] * x[21]) + ldr r11, =WL12 @ r11 = window_l[12] + ldr r12, =WL13 @ r12 = window_l[13] + movs r10, r10, lsr #28 + adc r4, r10, lr, lsl #4 @ r4 = bits[59..28] of windowed x3 + + smull r10, lr, r12, r5 @ r10..lr = (window_l[13] * x[22]) + movs r10, r10, lsr #28 + adc r5, r10, lr, lsl #4 @ r5 = bits[59..28] of windowed x4 + + smull r10, lr, r11, r6 @ r10..lr = (window_l[12] * x[23]) + ldr r11, =WL10 @ r12 = window_l[10] + ldr r12, =WL11 @ r12 = window_l[11] + movs r10, r10, lsr #28 + adc r6, r10, lr, lsl #4 @ r6 = bits[59..28] of windowed x5 + + smull r10, lr, r12, r7 @ r10..lr = (window_l[11] * x[24]) + movs r10, r10, lsr #28 + adc r7, r10, lr, lsl #4 @ r7 = bits[59..28] of windowed x6 + + smull r10, lr, r11, r8 @ r10..lr = (window_l[10] * x[25]) + ldr r12, =WL9 @ r12 = window_l[9] + movs r10, r10, lsr #28 + adc r8, r10, lr, lsl #4 @ r8 = bits[59..28] of windowed x7 + + smull r10, lr, r12, r9 @ r10..lr = (window_l[9] * x[26]) + + movs r10, r10, lsr #28 + adc r9, r10, lr, lsl #4 @ r9 = bits[59..28] of windowed x8 + + stmia r1, { r0, r2 - r9 } @ store windowed x[18] .. x[26] + + @---- + @ NB there are 2 possible exits from this function - this is only one of them + @---- + + add sp, sp, #(21*4) @ return stack frame + ldmia sp!, { r4 - r11, pc } @ restore callee saved regs, and return + + @---- + + +stop_block_x0_to_x17: + + @ r0 = x0 + @ r1 = &x[9] + @ r2 = x1 + @ r3 = x2 + @ r4 = x3 + @ r5 = x4 + @ r6 = x5 + @ r7 = x6 + @ r8 = x7 + @ r9 = x8 + @ r10 = -x0 + @ r11 = window mode: (0 == normal), (1 == start block), (3 == stop block) + @ r12 = . + @ lr = . + + rsb r0, r6, #0 @ r0 = -x5 + rsb r6, r2, #0 @ r6 = -x1 + rsb r2, r5, #0 @ r2 = -x4 + rsb r5, r3, #0 @ r5 = -x2 + rsb r3, r4, #0 @ r3 = -x3 + + add r1, r1, #(3*4) @ r1 = &x[12] + stmia r1, { r0, r2, r3, r5, r6, r10 } @ store unchanged x[12] .. x[17] + + ldr r0, =WL1 @ r0 = window_l[1] == window_s[0] + + rsb r10, r9, #0 @ r10 = -x8 + rsb r12, r8, #0 @ r12 = -x7 + rsb lr, r7, #0 @ lr = -x6 + + @ r0 = WL1 + @ r1 = &x[12] + @ r2 = . + @ r3 = . + @ r4 = . + @ r5 = . + @ r6 = . + @ r7 = x6 + @ r8 = x7 + @ r9 = x8 + @ r10 = -x8 + @ r11 = window mode: (0 == normal), (1 == start block), (3 == stop block) + @ r12 = -x7 + @ lr = -x6 + + smull r5, r6, r0, r7 @ r5..r6 = (window_l[1] * x[6]) + ldr r2, =WL4 @ r2 = window_l[4] == window_s[1] + movs r5, r5, lsr #28 + adc r7, r5, r6, lsl #4 @ r7 = bits[59..28] of windowed x6 + + smull r5, r6, r2, r8 @ r5..r6 = (window_l[4] * x[7]) + ldr r3, =WL7 @ r3 = window_l[7] == window_s[2] + movs r5, r5, lsr #28 + adc r8, r5, r6, lsl #4 @ r8 = bits[59..28] of windowed x7 + + smull r5, r6, r3, r9 @ r5..r6 = (window_l[7] * x[8]) + ldr r4, =WL10 @ r4 = window_l[10] == window_s[3] + movs r5, r5, lsr #28 + adc r9, r5, r6, lsl #4 @ r9 = bits[59..28] of windowed x8 + + smull r5, r6, r4, r10 @ r5..r6 = (window_l[10] * (x[9] == -x[8])) + ldr r0, =WL13 @ r0 = window_l[13] == window_s[4] + movs r5, r5, lsr #28 + adc r10, r5, r6, lsl #4 @ r10 = bits[59..28] of windowed x9 + + smull r5, r6, r0, r12 @ r5..r6 = (window_l[13] * (x[10] == -x[7])) + ldr r2, =WL16 @ r2 = window_l[16] == window_s[5] + movs r5, r5, lsr #28 + adc r12, r5, r6, lsl #4 @ r10 = bits[59..28] of windowed x9 + + smull r5, r6, r2, lr @ r5..r6 = (window_l[16] * (x[11] == -x[6])) + + ldr r0, =0x00 + + movs r5, r5, lsr #28 + adc lr, r5, r6, lsl #4 @ r10 = bits[59..28] of windowed x9 + + stmdb r1!, { r7 - r10, r12, lr } @ store windowed x[6] .. x[11] + + ldr r5, =0x00 + ldr r6, =0x00 + ldr r2, =0x00 + ldr r3, =0x00 + ldr r4, =0x00 + + stmdb r1!, { r0, r2 - r6 } @ store windowed x[0] .. x[5] + + b normal_block_x18_to_x35 + + + @---- + + +start_block_x18_to_x35: + + ldr r4, =WL1 @ r0 = window_l[1] == window_s[0] + + add r1, r1, #(24*4) @ r1 = &x[24] + + ldmia r1, { r0, r2, r3 } @ load 3 words from x24, dont update pointer + + @ r0 = x24 + @ r1 = &x[24] + @ r2 = x25 + @ r3 = x26 + @ r4 = WL1 + @ r5 = WL4 + @ r6 = WL7 + @ r7 = WL10 + @ r8 = WL13 + @ r9 = WL16 + @ r10 = . + @ r11 = . + @ r12 = . + @ lr = . + + ldr r5, =WL4 @ r5 = window_l[4] == window_s[1] + + smull r10, r11, r4, r0 @ r10..r11 = (window_l[1] * (x[24] == x[29])) + ldr r6, =WL7 @ r6 = window_l[7] == window_s[2] + movs r10, r10, lsr #28 + adc lr, r10, r11, lsl #4 @ lr = bits[59..28] of windowed x29 + + smull r10, r11, r5, r2 @ r10..r11 = (window_l[4] * (x[25] == x[28])) + ldr r7, =WL10 @ r7 = window_l[10] == window_s[3] + movs r10, r10, lsr #28 + adc r12, r10, r11, lsl #4 @ r12 = bits[59..28] of windowed x28 + + smull r10, r11, r6, r3 @ r10..r11 = (window_l[7] * (x[26] == x[27])) + ldr r8, =WL13 @ r8 = window_l[13] == window_s[4] + movs r10, r10, lsr #28 + adc r4, r10, r11, lsl #4 @ r4 = bits[59..28] of windowed x27 + + smull r10, r11, r7, r3 @ r10..r11 = (window_l[10] * x[26]) + ldr r9, =WL16 @ r9 = window_l[16] == window_s[5] + movs r10, r10, lsr #28 + adc r3, r10, r11, lsl #4 @ r3 = bits[59..28] of windowed x26 + + smull r10, r11, r8, r2 @ r10..r11 = (window_l[13] * x[25]) + ldr r5, =0x00 + movs r10, r10, lsr #28 + adc r2, r10, r11, lsl #4 @ r2 = bits[59..28] of windowed x25 + + smull r10, r11, r9, r0 @ r10..r11 = (window_l[16] * x[24]) + ldr r6, =0x00 + movs r10, r10, lsr #28 + adc r0, r10, r11, lsl #4 @ r0 = bits[59..28] of windowed x24 + + stmia r1!, { r0, r2, r3, r4, r12, lr } @ store windowed x[24] .. x[29] + + ldr r7, =0x00 + ldr r8, =0x00 + ldr r9, =0x00 + ldr r10, =0x00 + + stmia r1!, { r5 - r10 } @ store windowed x[30] .. x[35] + + @---- + @ NB there are 2 possible exits from this function - this is only one of them + @---- + + add sp, sp, #(21*4) @ return stack frame + ldmia sp!, { r4 - r11, pc } @ restore callee saved regs, and return + + @---- + @END + @---- + diff --git a/code/libmad/imdct_s.dat b/code/libmad/imdct_s.dat new file mode 100644 index 00000000..476710ea --- /dev/null +++ b/code/libmad/imdct_s.dat @@ -0,0 +1,62 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: imdct_s.dat,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + + /* 0 */ { MAD_F(0x09bd7ca0) /* 0.608761429 */, + -MAD_F(0x0ec835e8) /* -0.923879533 */, + -MAD_F(0x0216a2a2) /* -0.130526192 */, + MAD_F(0x0fdcf549) /* 0.991444861 */, + -MAD_F(0x061f78aa) /* -0.382683432 */, + -MAD_F(0x0cb19346) /* -0.793353340 */ }, + + /* 6 */ { -MAD_F(0x0cb19346) /* -0.793353340 */, + MAD_F(0x061f78aa) /* 0.382683432 */, + MAD_F(0x0fdcf549) /* 0.991444861 */, + MAD_F(0x0216a2a2) /* 0.130526192 */, + -MAD_F(0x0ec835e8) /* -0.923879533 */, + -MAD_F(0x09bd7ca0) /* -0.608761429 */ }, + + /* 1 */ { MAD_F(0x061f78aa) /* 0.382683432 */, + -MAD_F(0x0ec835e8) /* -0.923879533 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, + -MAD_F(0x061f78aa) /* -0.382683432 */, + -MAD_F(0x061f78aa) /* -0.382683432 */, + MAD_F(0x0ec835e8) /* 0.923879533 */ }, + + /* 7 */ { -MAD_F(0x0ec835e8) /* -0.923879533 */, + -MAD_F(0x061f78aa) /* -0.382683432 */, + MAD_F(0x061f78aa) /* 0.382683432 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, + MAD_F(0x061f78aa) /* 0.382683432 */ }, + + /* 2 */ { MAD_F(0x0216a2a2) /* 0.130526192 */, + -MAD_F(0x061f78aa) /* -0.382683432 */, + MAD_F(0x09bd7ca0) /* 0.608761429 */, + -MAD_F(0x0cb19346) /* -0.793353340 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, + -MAD_F(0x0fdcf549) /* -0.991444861 */ }, + + /* 8 */ { -MAD_F(0x0fdcf549) /* -0.991444861 */, + -MAD_F(0x0ec835e8) /* -0.923879533 */, + -MAD_F(0x0cb19346) /* -0.793353340 */, + -MAD_F(0x09bd7ca0) /* -0.608761429 */, + -MAD_F(0x061f78aa) /* -0.382683432 */, + -MAD_F(0x0216a2a2) /* -0.130526192 */ } diff --git a/code/libmad/layer12.c b/code/libmad/layer12.c new file mode 100644 index 00000000..a334a27e --- /dev/null +++ b/code/libmad/layer12.c @@ -0,0 +1,621 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: layer12.c,v 1.17 2004/02/05 09:02:39 rob Exp $ + */ + +# include "global.h" + +# ifdef HAVE_LIMITS_H +# include +# else +# define CHAR_BIT 8 +# endif + +# include "mad.h" +# include "layer12.h" + +/* + * scalefactor table + * used in both Layer I and Layer II decoding + */ +static +mad_fixed_t const sf_table[64] = { +# include "sf_table.dat" +}; + +/* --- Layer I ------------------------------------------------------------- */ + +/* linear scaling table */ +static +mad_fixed_t const linear_table[14] = { + MAD_F(0x15555555), /* 2^2 / (2^2 - 1) == 1.33333333333333 */ + MAD_F(0x12492492), /* 2^3 / (2^3 - 1) == 1.14285714285714 */ + MAD_F(0x11111111), /* 2^4 / (2^4 - 1) == 1.06666666666667 */ + MAD_F(0x10842108), /* 2^5 / (2^5 - 1) == 1.03225806451613 */ + MAD_F(0x10410410), /* 2^6 / (2^6 - 1) == 1.01587301587302 */ + MAD_F(0x10204081), /* 2^7 / (2^7 - 1) == 1.00787401574803 */ + MAD_F(0x10101010), /* 2^8 / (2^8 - 1) == 1.00392156862745 */ + MAD_F(0x10080402), /* 2^9 / (2^9 - 1) == 1.00195694716243 */ + MAD_F(0x10040100), /* 2^10 / (2^10 - 1) == 1.00097751710655 */ + MAD_F(0x10020040), /* 2^11 / (2^11 - 1) == 1.00048851978505 */ + MAD_F(0x10010010), /* 2^12 / (2^12 - 1) == 1.00024420024420 */ + MAD_F(0x10008004), /* 2^13 / (2^13 - 1) == 1.00012208521548 */ + MAD_F(0x10004001), /* 2^14 / (2^14 - 1) == 1.00006103888177 */ + MAD_F(0x10002000) /* 2^15 / (2^15 - 1) == 1.00003051850948 */ +}; + +/* + * NAME: I_sample() + * DESCRIPTION: decode one requantized Layer I sample from a bitstream + */ +static +mad_fixed_t I_sample(struct mad_bitptr *ptr, unsigned int nb, struct mad_stream *stream) +{ + mad_fixed_t sample; + struct mad_bitptr frameend_ptr; + + mad_bit_init(&frameend_ptr, stream->next_frame); + + if (mad_bit_length(ptr, &frameend_ptr) < nb) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return 0; + } + sample = mad_bit_read(ptr, nb); + + /* invert most significant bit, extend sign, then scale to fixed format */ + + sample ^= 1 << (nb - 1); + sample |= -(sample & (1 << (nb - 1))); + + sample <<= MAD_F_FRACBITS - (nb - 1); + + /* requantize the sample */ + + /* s'' = (2^nb / (2^nb - 1)) * (s''' + 2^(-nb + 1)) */ + + sample += MAD_F_ONE >> (nb - 1); + + return mad_f_mul(sample, linear_table[nb - 2]); + + /* s' = factor * s'' */ + /* (to be performed by caller) */ +} + +/* + * NAME: layer->I() + * DESCRIPTION: decode a single Layer I frame + */ +int mad_layer_I(struct mad_stream *stream, struct mad_frame *frame) +{ + struct mad_header *header = &frame->header; + unsigned int nch, bound, ch, s, sb, nb; + unsigned char allocation[2][32], scalefactor[2][32]; + struct mad_bitptr bufend_ptr, frameend_ptr; + + mad_bit_init(&bufend_ptr, stream->bufend); + mad_bit_init(&frameend_ptr, stream->next_frame); + + nch = MAD_NCHANNELS(header); + + bound = 32; + if (header->mode == MAD_MODE_JOINT_STEREO) { + header->flags |= MAD_FLAG_I_STEREO; + bound = 4 + header->mode_extension * 4; + } + + /* check CRC word */ + + if (header->flags & MAD_FLAG_PROTECTION) { + if (mad_bit_length(&stream->ptr, &bufend_ptr) + < 4 * (bound * nch + (32 - bound))) { + stream->error = MAD_ERROR_BADCRC; + return -1; + } + header->crc_check = + mad_bit_crc(stream->ptr, 4 * (bound * nch + (32 - bound)), + header->crc_check); + + if (header->crc_check != header->crc_target && + !(frame->options & MAD_OPTION_IGNORECRC)) { + stream->error = MAD_ERROR_BADCRC; + return -1; + } + } + + /* decode bit allocations */ + + for (sb = 0; sb < bound; ++sb) { + for (ch = 0; ch < nch; ++ch) { + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 4) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + nb = mad_bit_read(&stream->ptr, 4); + + if (nb == 15) { + stream->error = MAD_ERROR_BADBITALLOC; + return -1; + } + + allocation[ch][sb] = nb ? nb + 1 : 0; + } + } + + for (sb = bound; sb < 32; ++sb) { + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 4) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + nb = mad_bit_read(&stream->ptr, 4); + + if (nb == 15) { + stream->error = MAD_ERROR_BADBITALLOC; + return -1; + } + + allocation[0][sb] = + allocation[1][sb] = nb ? nb + 1 : 0; + } + + /* decode scalefactors */ + + for (sb = 0; sb < 32; ++sb) { + for (ch = 0; ch < nch; ++ch) { + if (allocation[ch][sb]) { + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 6) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + scalefactor[ch][sb] = mad_bit_read(&stream->ptr, 6); + +# if defined(OPT_STRICT) + /* + * Scalefactor index 63 does not appear in Table B.1 of + * ISO/IEC 11172-3. Nonetheless, other implementations accept it, + * so we only reject it if OPT_STRICT is defined. + */ + if (scalefactor[ch][sb] == 63) { + stream->error = MAD_ERROR_BADSCALEFACTOR; + return -1; + } +# endif + } + } + } + + /* decode samples */ + + for (s = 0; s < 12; ++s) { + for (sb = 0; sb < bound; ++sb) { + for (ch = 0; ch < nch; ++ch) { + nb = allocation[ch][sb]; + frame->sbsample[ch][s][sb] = nb ? + mad_f_mul(I_sample(&stream->ptr, nb, stream), + sf_table[scalefactor[ch][sb]]) : 0; + if (stream->error != 0) + return -1; + } + } + + for (sb = bound; sb < 32; ++sb) { + if ((nb = allocation[0][sb])) { + mad_fixed_t sample; + + if (mad_bit_length(&stream->ptr, &frameend_ptr) < nb) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + sample = I_sample(&stream->ptr, nb, stream); + if (stream->error != 0) + return -1; + + for (ch = 0; ch < nch; ++ch) { + frame->sbsample[ch][s][sb] = + mad_f_mul(sample, sf_table[scalefactor[ch][sb]]); + } + } + else { + for (ch = 0; ch < nch; ++ch) + frame->sbsample[ch][s][sb] = 0; + } + } + } + + return 0; +} + +/* --- Layer II ------------------------------------------------------------ */ + +/* possible quantization per subband table */ +static +struct { + unsigned int sblimit; + unsigned char const offsets[30]; +} const sbquant_table[5] = { + /* ISO/IEC 11172-3 Table B.2a */ + { 27, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, /* 0 */ + 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 } }, + /* ISO/IEC 11172-3 Table B.2b */ + { 30, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, /* 1 */ + 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 } }, + /* ISO/IEC 11172-3 Table B.2c */ + { 8, { 5, 5, 2, 2, 2, 2, 2, 2 } }, /* 2 */ + /* ISO/IEC 11172-3 Table B.2d */ + { 12, { 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } }, /* 3 */ + /* ISO/IEC 13818-3 Table B.1 */ + { 30, { 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } } +}; + +/* bit allocation table */ +static +struct { + unsigned short nbal; + unsigned short offset; +} const bitalloc_table[8] = { + { 2, 0 }, /* 0 */ + { 2, 3 }, /* 1 */ + { 3, 3 }, /* 2 */ + { 3, 1 }, /* 3 */ + { 4, 2 }, /* 4 */ + { 4, 3 }, /* 5 */ + { 4, 4 }, /* 6 */ + { 4, 5 } /* 7 */ +}; + +/* offsets into quantization class table */ +static +unsigned char const offset_table[6][15] = { + { 0, 1, 16 }, /* 0 */ + { 0, 1, 2, 3, 4, 5, 16 }, /* 1 */ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, /* 2 */ + { 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* 3 */ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }, /* 4 */ + { 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } /* 5 */ +}; + +/* quantization class table */ +static +struct quantclass { + unsigned short nlevels; + unsigned char group; + unsigned char bits; + mad_fixed_t C; + mad_fixed_t D; +} const qc_table[17] = { +# include "qc_table.dat" +}; + +/* + * NAME: II_samples() + * DESCRIPTION: decode three requantized Layer II samples from a bitstream + */ +static +void II_samples(struct mad_bitptr *ptr, + struct quantclass const *quantclass, + mad_fixed_t output[3], struct mad_stream *stream) +{ + unsigned int nb, s, sample[3]; + struct mad_bitptr frameend_ptr; + + mad_bit_init(&frameend_ptr, stream->next_frame); + + if ((nb = quantclass->group)) { + unsigned int c, nlevels; + + if (mad_bit_length(ptr, &frameend_ptr) < quantclass->bits) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return; + } + /* degrouping */ + c = mad_bit_read(ptr, quantclass->bits); + nlevels = quantclass->nlevels; + + for (s = 0; s < 3; ++s) { + sample[s] = c % nlevels; + c /= nlevels; + } + } + else { + nb = quantclass->bits; + + for (s = 0; s < 3; ++s) { + if (mad_bit_length(ptr, &frameend_ptr) < nb) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return; + } + sample[s] = mad_bit_read(ptr, nb); + } + } + + for (s = 0; s < 3; ++s) { + mad_fixed_t requantized; + + /* invert most significant bit, extend sign, then scale to fixed format */ + + requantized = sample[s] ^ (1 << (nb - 1)); + requantized |= -(requantized & (1 << (nb - 1))); + + requantized <<= MAD_F_FRACBITS - (nb - 1); + + /* requantize the sample */ + + /* s'' = C * (s''' + D) */ + + output[s] = mad_f_mul(requantized + quantclass->D, quantclass->C); + + /* s' = factor * s'' */ + /* (to be performed by caller) */ + } +} + +/* + * NAME: layer->II() + * DESCRIPTION: decode a single Layer II frame + */ +int mad_layer_II(struct mad_stream *stream, struct mad_frame *frame) +{ + struct mad_header *header = &frame->header; + struct mad_bitptr start; + unsigned int index, sblimit, nbal, nch, bound, gr, ch, s, sb; + unsigned char const *offsets; + unsigned char allocation[2][32], scfsi[2][32], scalefactor[2][32][3]; + mad_fixed_t samples[3]; + struct mad_bitptr frameend_ptr; + + mad_bit_init(&frameend_ptr, stream->next_frame); + + nch = MAD_NCHANNELS(header); + + if (header->flags & MAD_FLAG_LSF_EXT) + index = 4; + else if (header->flags & MAD_FLAG_FREEFORMAT) + goto freeformat; + else { + unsigned long bitrate_per_channel; + + bitrate_per_channel = header->bitrate; + if (nch == 2) { + bitrate_per_channel /= 2; + +# if defined(OPT_STRICT) + /* + * ISO/IEC 11172-3 allows only single channel mode for 32, 48, 56, and + * 80 kbps bitrates in Layer II, but some encoders ignore this + * restriction. We enforce it if OPT_STRICT is defined. + */ + if (bitrate_per_channel <= 28000 || bitrate_per_channel == 40000) { + stream->error = MAD_ERROR_BADMODE; + return -1; + } +# endif + } + else { /* nch == 1 */ + if (bitrate_per_channel > 192000) { + /* + * ISO/IEC 11172-3 does not allow single channel mode for 224, 256, + * 320, or 384 kbps bitrates in Layer II. + */ + stream->error = MAD_ERROR_BADMODE; + return -1; + } + } + + if (bitrate_per_channel <= 48000) + index = (header->samplerate == 32000) ? 3 : 2; + else if (bitrate_per_channel <= 80000) + index = 0; + else { + freeformat: + index = (header->samplerate == 48000) ? 0 : 1; + } + } + + sblimit = sbquant_table[index].sblimit; + offsets = sbquant_table[index].offsets; + + bound = 32; + if (header->mode == MAD_MODE_JOINT_STEREO) { + header->flags |= MAD_FLAG_I_STEREO; + bound = 4 + header->mode_extension * 4; + } + + if (bound > sblimit) + bound = sblimit; + + start = stream->ptr; + + /* decode bit allocations */ + + for (sb = 0; sb < bound; ++sb) { + nbal = bitalloc_table[offsets[sb]].nbal; + + for (ch = 0; ch < nch; ++ch) { + if (mad_bit_length(&stream->ptr, &frameend_ptr) < nbal) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + allocation[ch][sb] = mad_bit_read(&stream->ptr, nbal); + } + } + + for (sb = bound; sb < sblimit; ++sb) { + nbal = bitalloc_table[offsets[sb]].nbal; + + if (mad_bit_length(&stream->ptr, &frameend_ptr) < nbal) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + allocation[0][sb] = + allocation[1][sb] = mad_bit_read(&stream->ptr, nbal); + } + + /* decode scalefactor selection info */ + + for (sb = 0; sb < sblimit; ++sb) { + for (ch = 0; ch < nch; ++ch) { + if (allocation[ch][sb]) { + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 2) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + scfsi[ch][sb] = mad_bit_read(&stream->ptr, 2); + } + } + } + + /* check CRC word */ + + if (header->flags & MAD_FLAG_PROTECTION) { + header->crc_check = + mad_bit_crc(start, mad_bit_length(&start, &stream->ptr), + header->crc_check); + + if (header->crc_check != header->crc_target && + !(frame->options & MAD_OPTION_IGNORECRC)) { + stream->error = MAD_ERROR_BADCRC; + return -1; + } + } + + /* decode scalefactors */ + + for (sb = 0; sb < sblimit; ++sb) { + for (ch = 0; ch < nch; ++ch) { + if (allocation[ch][sb]) { + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 6) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + scalefactor[ch][sb][0] = mad_bit_read(&stream->ptr, 6); + + switch (scfsi[ch][sb]) { + case 2: + scalefactor[ch][sb][2] = + scalefactor[ch][sb][1] = + scalefactor[ch][sb][0]; + break; + + case 0: + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 6) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + scalefactor[ch][sb][1] = mad_bit_read(&stream->ptr, 6); + /* fall through */ + + case 1: + case 3: + if (mad_bit_length(&stream->ptr, &frameend_ptr) < 6) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + scalefactor[ch][sb][2] = mad_bit_read(&stream->ptr, 6); + } + + if (scfsi[ch][sb] & 1) + scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1]; + +# if defined(OPT_STRICT) + /* + * Scalefactor index 63 does not appear in Table B.1 of + * ISO/IEC 11172-3. Nonetheless, other implementations accept it, + * so we only reject it if OPT_STRICT is defined. + */ + if (scalefactor[ch][sb][0] == 63 || + scalefactor[ch][sb][1] == 63 || + scalefactor[ch][sb][2] == 63) { + stream->error = MAD_ERROR_BADSCALEFACTOR; + return -1; + } +# endif + } + } + } + + /* decode samples */ + + for (gr = 0; gr < 12; ++gr) { + for (sb = 0; sb < bound; ++sb) { + for (ch = 0; ch < nch; ++ch) { + if ((index = allocation[ch][sb])) { + index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1]; + + II_samples(&stream->ptr, &qc_table[index], samples, stream); + if (stream->error != 0) + return -1; + + for (s = 0; s < 3; ++s) { + frame->sbsample[ch][3 * gr + s][sb] = + mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]); + } + } + else { + for (s = 0; s < 3; ++s) + frame->sbsample[ch][3 * gr + s][sb] = 0; + } + } + } + + for (sb = bound; sb < sblimit; ++sb) { + if ((index = allocation[0][sb])) { + index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1]; + + II_samples(&stream->ptr, &qc_table[index], samples, stream); + if (stream->error != 0) + return -1; + + for (ch = 0; ch < nch; ++ch) { + for (s = 0; s < 3; ++s) { + frame->sbsample[ch][3 * gr + s][sb] = + mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]); + } + } + } + else { + for (ch = 0; ch < nch; ++ch) { + for (s = 0; s < 3; ++s) + frame->sbsample[ch][3 * gr + s][sb] = 0; + } + } + } + + for (ch = 0; ch < nch; ++ch) { + for (s = 0; s < 3; ++s) { + for (sb = sblimit; sb < 32; ++sb) + frame->sbsample[ch][3 * gr + s][sb] = 0; + } + } + } + + return 0; +} diff --git a/code/libmad/layer12.h b/code/libmad/layer12.h new file mode 100644 index 00000000..8caa3f75 --- /dev/null +++ b/code/libmad/layer12.h @@ -0,0 +1,30 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: layer12.h,v 1.10 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBMAD_LAYER12_H +# define LIBMAD_LAYER12_H + +# include "mad.h" + +int mad_layer_I(struct mad_stream *, struct mad_frame *); +int mad_layer_II(struct mad_stream *, struct mad_frame *); + +# endif diff --git a/code/libmad/layer3.c b/code/libmad/layer3.c new file mode 100644 index 00000000..7f18fd72 --- /dev/null +++ b/code/libmad/layer3.c @@ -0,0 +1,2779 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: layer3.c,v 1.43 2004/01/23 09:41:32 rob Exp $ + */ + +# include "global.h" + +# include +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# ifdef HAVE_LIMITS_H +# include +# else +# define CHAR_BIT 8 +# endif + +# include "mad.h" +# include "huffman.h" +# include "layer3.h" + +/* --- Layer III ----------------------------------------------------------- */ + +enum { + count1table_select = 0x01, + scalefac_scale = 0x02, + preflag = 0x04, + mixed_block_flag = 0x08 +}; + +enum { + I_STEREO = 0x1, + MS_STEREO = 0x2 +}; + +struct sideinfo { + unsigned int main_data_begin; + unsigned int private_bits; + + unsigned char scfsi[2]; + + struct granule { + struct channel { + /* from side info */ + unsigned short part2_3_length; + unsigned short big_values; + unsigned short global_gain; + unsigned short scalefac_compress; + + unsigned char flags; + unsigned char block_type; + unsigned char table_select[3]; + unsigned char subblock_gain[3]; + unsigned char region0_count; + unsigned char region1_count; + + /* from main_data */ + unsigned char scalefac[39]; /* scalefac_l and/or scalefac_s */ + } ch[2]; + } gr[2]; +}; + +/* + * scalefactor bit lengths + * derived from section 2.4.2.7 of ISO/IEC 11172-3 + */ +static +struct { + unsigned char slen1; + unsigned char slen2; +} const sflen_table[16] = { + { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 3, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }, + { 2, 1 }, { 2, 2 }, { 2, 3 }, { 3, 1 }, + { 3, 2 }, { 3, 3 }, { 4, 2 }, { 4, 3 } +}; + +/* + * number of LSF scalefactor band values + * derived from section 2.4.3.2 of ISO/IEC 13818-3 + */ +static +unsigned char const nsfb_table[6][3][4] = { + { { 6, 5, 5, 5 }, + { 9, 9, 9, 9 }, + { 6, 9, 9, 9 } }, + + { { 6, 5, 7, 3 }, + { 9, 9, 12, 6 }, + { 6, 9, 12, 6 } }, + + { { 11, 10, 0, 0 }, + { 18, 18, 0, 0 }, + { 15, 18, 0, 0 } }, + + { { 7, 7, 7, 0 }, + { 12, 12, 12, 0 }, + { 6, 15, 12, 0 } }, + + { { 6, 6, 6, 3 }, + { 12, 9, 9, 6 }, + { 6, 12, 9, 6 } }, + + { { 8, 8, 5, 0 }, + { 15, 12, 9, 0 }, + { 6, 18, 9, 0 } } +}; + +/* + * MPEG-1 scalefactor band widths + * derived from Table B.8 of ISO/IEC 11172-3 + */ +static +unsigned char const sfb_48000_long[] = { + 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, + 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192 +}; + +static +unsigned char const sfb_44100_long[] = { + 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, + 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158 +}; + +static +unsigned char const sfb_32000_long[] = { + 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, + 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26 +}; + +static +unsigned char const sfb_48000_short[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 6, 6, 6, 10, 10, 10, 12, 12, 12, 14, 14, + 14, 16, 16, 16, 20, 20, 20, 26, 26, 26, 66, 66, 66 +}; + +static +unsigned char const sfb_44100_short[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 8, 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, + 14, 18, 18, 18, 22, 22, 22, 30, 30, 30, 56, 56, 56 +}; + +static +unsigned char const sfb_32000_short[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 8, 8, 8, 12, 12, 12, 16, 16, 16, 20, 20, + 20, 26, 26, 26, 34, 34, 34, 42, 42, 42, 12, 12, 12 +}; + +static +unsigned char const sfb_48000_mixed[] = { + /* long */ 4, 4, 4, 4, 4, 4, 6, 6, + /* short */ 4, 4, 4, 6, 6, 6, 6, 6, 6, 10, + 10, 10, 12, 12, 12, 14, 14, 14, 16, 16, + 16, 20, 20, 20, 26, 26, 26, 66, 66, 66 +}; + +static +unsigned char const sfb_44100_mixed[] = { + /* long */ 4, 4, 4, 4, 4, 4, 6, 6, + /* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 10, + 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, + 18, 22, 22, 22, 30, 30, 30, 56, 56, 56 +}; + +static +unsigned char const sfb_32000_mixed[] = { + /* long */ 4, 4, 4, 4, 4, 4, 6, 6, + /* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 12, + 12, 12, 16, 16, 16, 20, 20, 20, 26, 26, + 26, 34, 34, 34, 42, 42, 42, 12, 12, 12 +}; + +/* + * MPEG-2 scalefactor band widths + * derived from Table B.2 of ISO/IEC 13818-3 + */ +static +unsigned char const sfb_24000_long[] = { + 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 18, 22, 26, 32, 38, 46, 54, 62, 70, 76, 36 +}; + +static +unsigned char const sfb_22050_long[] = { + 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 +}; + +# define sfb_16000_long sfb_22050_long + +static +unsigned char const sfb_24000_short[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, + 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, + 18, 24, 24, 24, 32, 32, 32, 44, 44, 44, 12, 12, 12 +}; + +static +unsigned char const sfb_22050_short[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, + 6, 6, 8, 8, 8, 10, 10, 10, 14, 14, 14, 18, 18, + 18, 26, 26, 26, 32, 32, 32, 42, 42, 42, 18, 18, 18 +}; + +static +unsigned char const sfb_16000_short[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, + 8, 8, 10, 10, 10, 12, 12, 12, 14, 14, 14, 18, 18, + 18, 24, 24, 24, 30, 30, 30, 40, 40, 40, 18, 18, 18 +}; + +static +unsigned char const sfb_24000_mixed[] = { + /* long */ 6, 6, 6, 6, 6, 6, + /* short */ 6, 6, 6, 8, 8, 8, 10, 10, 10, 12, + 12, 12, 14, 14, 14, 18, 18, 18, 24, 24, + 24, 32, 32, 32, 44, 44, 44, 12, 12, 12 +}; + +static +unsigned char const sfb_22050_mixed[] = { + /* long */ 6, 6, 6, 6, 6, 6, + /* short */ 6, 6, 6, 6, 6, 6, 8, 8, 8, 10, + 10, 10, 14, 14, 14, 18, 18, 18, 26, 26, + 26, 32, 32, 32, 42, 42, 42, 18, 18, 18 +}; + +static +unsigned char const sfb_16000_mixed[] = { + /* long */ 6, 6, 6, 6, 6, 6, + /* short */ 6, 6, 6, 8, 8, 8, 10, 10, 10, 12, + 12, 12, 14, 14, 14, 18, 18, 18, 24, 24, + 24, 30, 30, 30, 40, 40, 40, 18, 18, 18 +}; + +/* + * MPEG 2.5 scalefactor band widths + * derived from public sources + */ +# define sfb_12000_long sfb_16000_long +# define sfb_11025_long sfb_12000_long + +static +unsigned char const sfb_8000_long[] = { + 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, + 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2 +}; + +# define sfb_12000_short sfb_16000_short +# define sfb_11025_short sfb_12000_short + +static +unsigned char const sfb_8000_short[] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 16, + 16, 16, 20, 20, 20, 24, 24, 24, 28, 28, 28, 36, 36, + 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26 +}; + +# define sfb_12000_mixed sfb_16000_mixed +# define sfb_11025_mixed sfb_12000_mixed + +/* the 8000 Hz short block scalefactor bands do not break after + the first 36 frequency lines, so this is probably wrong */ +static +unsigned char const sfb_8000_mixed[] = { + /* long */ 12, 12, 12, + /* short */ 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16, + 20, 20, 20, 24, 24, 24, 28, 28, 28, 36, 36, 36, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26 +}; + +static +struct { + unsigned char const *l; + unsigned char const *s; + unsigned char const *m; +} const sfbwidth_table[9] = { + { sfb_48000_long, sfb_48000_short, sfb_48000_mixed }, + { sfb_44100_long, sfb_44100_short, sfb_44100_mixed }, + { sfb_32000_long, sfb_32000_short, sfb_32000_mixed }, + { sfb_24000_long, sfb_24000_short, sfb_24000_mixed }, + { sfb_22050_long, sfb_22050_short, sfb_22050_mixed }, + { sfb_16000_long, sfb_16000_short, sfb_16000_mixed }, + { sfb_12000_long, sfb_12000_short, sfb_12000_mixed }, + { sfb_11025_long, sfb_11025_short, sfb_11025_mixed }, + { sfb_8000_long, sfb_8000_short, sfb_8000_mixed } +}; + +/* + * scalefactor band preemphasis (used only when preflag is set) + * derived from Table B.6 of ISO/IEC 11172-3 + */ +static +unsigned char const pretab[22] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 +}; + +/* + * table for requantization + * + * rq_table[x].mantissa * 2^(rq_table[x].exponent) = x^(4/3) + */ +static +struct fixedfloat { + unsigned long mantissa : 27; + unsigned short exponent : 5; +} const rq_table[8207] = { +# include "rq_table.dat" +}; + +/* + * fractional powers of two + * used for requantization and joint stereo decoding + * + * root_table[3 + x] = 2^(x/4) + */ +static +mad_fixed_t const root_table[7] = { + MAD_F(0x09837f05) /* 2^(-3/4) == 0.59460355750136 */, + MAD_F(0x0b504f33) /* 2^(-2/4) == 0.70710678118655 */, + MAD_F(0x0d744fcd) /* 2^(-1/4) == 0.84089641525371 */, + MAD_F(0x10000000) /* 2^( 0/4) == 1.00000000000000 */, + MAD_F(0x1306fe0a) /* 2^(+1/4) == 1.18920711500272 */, + MAD_F(0x16a09e66) /* 2^(+2/4) == 1.41421356237310 */, + MAD_F(0x1ae89f99) /* 2^(+3/4) == 1.68179283050743 */ +}; + +/* + * coefficients for aliasing reduction + * derived from Table B.9 of ISO/IEC 11172-3 + * + * c[] = { -0.6, -0.535, -0.33, -0.185, -0.095, -0.041, -0.0142, -0.0037 } + * cs[i] = 1 / sqrt(1 + c[i]^2) + * ca[i] = c[i] / sqrt(1 + c[i]^2) + */ +static +mad_fixed_t const cs[8] = { + +MAD_F(0x0db84a81) /* +0.857492926 */, +MAD_F(0x0e1b9d7f) /* +0.881741997 */, + +MAD_F(0x0f31adcf) /* +0.949628649 */, +MAD_F(0x0fbba815) /* +0.983314592 */, + +MAD_F(0x0feda417) /* +0.995517816 */, +MAD_F(0x0ffc8fc8) /* +0.999160558 */, + +MAD_F(0x0fff964c) /* +0.999899195 */, +MAD_F(0x0ffff8d3) /* +0.999993155 */ +}; + +static +mad_fixed_t const ca[8] = { + -MAD_F(0x083b5fe7) /* -0.514495755 */, -MAD_F(0x078c36d2) /* -0.471731969 */, + -MAD_F(0x05039814) /* -0.313377454 */, -MAD_F(0x02e91dd1) /* -0.181913200 */, + -MAD_F(0x0183603a) /* -0.094574193 */, -MAD_F(0x00a7cb87) /* -0.040965583 */, + -MAD_F(0x003a2847) /* -0.014198569 */, -MAD_F(0x000f27b4) /* -0.003699975 */ +}; + +/* + * IMDCT coefficients for short blocks + * derived from section 2.4.3.4.10.2 of ISO/IEC 11172-3 + * + * imdct_s[i/even][k] = cos((PI / 24) * (2 * (i / 2) + 7) * (2 * k + 1)) + * imdct_s[i /odd][k] = cos((PI / 24) * (2 * (6 + (i-1)/2) + 7) * (2 * k + 1)) + */ +static +mad_fixed_t const imdct_s[6][6] = { +# include "imdct_s.dat" +}; + +# if !defined(ASO_IMDCT) +/* + * windowing coefficients for long blocks + * derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3 + * + * window_l[i] = sin((PI / 36) * (i + 1/2)) + */ +static +mad_fixed_t const window_l[36] = { + MAD_F(0x00b2aa3e) /* 0.043619387 */, MAD_F(0x0216a2a2) /* 0.130526192 */, + MAD_F(0x03768962) /* 0.216439614 */, MAD_F(0x04cfb0e2) /* 0.300705800 */, + MAD_F(0x061f78aa) /* 0.382683432 */, MAD_F(0x07635284) /* 0.461748613 */, + MAD_F(0x0898c779) /* 0.537299608 */, MAD_F(0x09bd7ca0) /* 0.608761429 */, + MAD_F(0x0acf37ad) /* 0.675590208 */, MAD_F(0x0bcbe352) /* 0.737277337 */, + MAD_F(0x0cb19346) /* 0.793353340 */, MAD_F(0x0d7e8807) /* 0.843391446 */, + + MAD_F(0x0e313245) /* 0.887010833 */, MAD_F(0x0ec835e8) /* 0.923879533 */, + MAD_F(0x0f426cb5) /* 0.953716951 */, MAD_F(0x0f9ee890) /* 0.976296007 */, + MAD_F(0x0fdcf549) /* 0.991444861 */, MAD_F(0x0ffc19fd) /* 0.999048222 */, + MAD_F(0x0ffc19fd) /* 0.999048222 */, MAD_F(0x0fdcf549) /* 0.991444861 */, + MAD_F(0x0f9ee890) /* 0.976296007 */, MAD_F(0x0f426cb5) /* 0.953716951 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, MAD_F(0x0e313245) /* 0.887010833 */, + + MAD_F(0x0d7e8807) /* 0.843391446 */, MAD_F(0x0cb19346) /* 0.793353340 */, + MAD_F(0x0bcbe352) /* 0.737277337 */, MAD_F(0x0acf37ad) /* 0.675590208 */, + MAD_F(0x09bd7ca0) /* 0.608761429 */, MAD_F(0x0898c779) /* 0.537299608 */, + MAD_F(0x07635284) /* 0.461748613 */, MAD_F(0x061f78aa) /* 0.382683432 */, + MAD_F(0x04cfb0e2) /* 0.300705800 */, MAD_F(0x03768962) /* 0.216439614 */, + MAD_F(0x0216a2a2) /* 0.130526192 */, MAD_F(0x00b2aa3e) /* 0.043619387 */, +}; +# endif /* ASO_IMDCT */ + +/* + * windowing coefficients for short blocks + * derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3 + * + * window_s[i] = sin((PI / 12) * (i + 1/2)) + */ +static +mad_fixed_t const window_s[12] = { + MAD_F(0x0216a2a2) /* 0.130526192 */, MAD_F(0x061f78aa) /* 0.382683432 */, + MAD_F(0x09bd7ca0) /* 0.608761429 */, MAD_F(0x0cb19346) /* 0.793353340 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, MAD_F(0x0fdcf549) /* 0.991444861 */, + MAD_F(0x0fdcf549) /* 0.991444861 */, MAD_F(0x0ec835e8) /* 0.923879533 */, + MAD_F(0x0cb19346) /* 0.793353340 */, MAD_F(0x09bd7ca0) /* 0.608761429 */, + MAD_F(0x061f78aa) /* 0.382683432 */, MAD_F(0x0216a2a2) /* 0.130526192 */, +}; + +/* + * coefficients for intensity stereo processing + * derived from section 2.4.3.4.9.3 of ISO/IEC 11172-3 + * + * is_ratio[i] = tan(i * (PI / 12)) + * is_table[i] = is_ratio[i] / (1 + is_ratio[i]) + */ +static +mad_fixed_t const is_table[7] = { + MAD_F(0x00000000) /* 0.000000000 */, + MAD_F(0x0361962f) /* 0.211324865 */, + MAD_F(0x05db3d74) /* 0.366025404 */, + MAD_F(0x08000000) /* 0.500000000 */, + MAD_F(0x0a24c28c) /* 0.633974596 */, + MAD_F(0x0c9e69d1) /* 0.788675135 */, + MAD_F(0x10000000) /* 1.000000000 */ +}; + +/* + * coefficients for LSF intensity stereo processing + * derived from section 2.4.3.2 of ISO/IEC 13818-3 + * + * is_lsf_table[0][i] = (1 / sqrt(sqrt(2)))^(i + 1) + * is_lsf_table[1][i] = (1 / sqrt(2)) ^(i + 1) + */ +static +mad_fixed_t const is_lsf_table[2][15] = { + { + MAD_F(0x0d744fcd) /* 0.840896415 */, + MAD_F(0x0b504f33) /* 0.707106781 */, + MAD_F(0x09837f05) /* 0.594603558 */, + MAD_F(0x08000000) /* 0.500000000 */, + MAD_F(0x06ba27e6) /* 0.420448208 */, + MAD_F(0x05a8279a) /* 0.353553391 */, + MAD_F(0x04c1bf83) /* 0.297301779 */, + MAD_F(0x04000000) /* 0.250000000 */, + MAD_F(0x035d13f3) /* 0.210224104 */, + MAD_F(0x02d413cd) /* 0.176776695 */, + MAD_F(0x0260dfc1) /* 0.148650889 */, + MAD_F(0x02000000) /* 0.125000000 */, + MAD_F(0x01ae89fa) /* 0.105112052 */, + MAD_F(0x016a09e6) /* 0.088388348 */, + MAD_F(0x01306fe1) /* 0.074325445 */ + }, { + MAD_F(0x0b504f33) /* 0.707106781 */, + MAD_F(0x08000000) /* 0.500000000 */, + MAD_F(0x05a8279a) /* 0.353553391 */, + MAD_F(0x04000000) /* 0.250000000 */, + MAD_F(0x02d413cd) /* 0.176776695 */, + MAD_F(0x02000000) /* 0.125000000 */, + MAD_F(0x016a09e6) /* 0.088388348 */, + MAD_F(0x01000000) /* 0.062500000 */, + MAD_F(0x00b504f3) /* 0.044194174 */, + MAD_F(0x00800000) /* 0.031250000 */, + MAD_F(0x005a827a) /* 0.022097087 */, + MAD_F(0x00400000) /* 0.015625000 */, + MAD_F(0x002d413d) /* 0.011048543 */, + MAD_F(0x00200000) /* 0.007812500 */, + MAD_F(0x0016a09e) /* 0.005524272 */ + } +}; + +/* + * NAME: III_sideinfo() + * DESCRIPTION: decode frame side information from a bitstream + */ +static +enum mad_error III_sideinfo(struct mad_bitptr *ptr, unsigned int nch, + int lsf, struct sideinfo *si, + unsigned int *data_bitlen, + unsigned int *priv_bitlen) +{ + unsigned int ngr, gr, ch, i; + enum mad_error result = MAD_ERROR_NONE; + + *data_bitlen = 0; + *priv_bitlen = lsf ? ((nch == 1) ? 1 : 2) : ((nch == 1) ? 5 : 3); + + si->main_data_begin = mad_bit_read(ptr, lsf ? 8 : 9); + si->private_bits = mad_bit_read(ptr, *priv_bitlen); + + ngr = 1; + if (!lsf) { + ngr = 2; + + for (ch = 0; ch < nch; ++ch) + si->scfsi[ch] = mad_bit_read(ptr, 4); + } + + for (gr = 0; gr < ngr; ++gr) { + struct granule *granule = &si->gr[gr]; + + for (ch = 0; ch < nch; ++ch) { + struct channel *channel = &granule->ch[ch]; + + channel->part2_3_length = mad_bit_read(ptr, 12); + channel->big_values = mad_bit_read(ptr, 9); + channel->global_gain = mad_bit_read(ptr, 8); + channel->scalefac_compress = mad_bit_read(ptr, lsf ? 9 : 4); + + *data_bitlen += channel->part2_3_length; + + if (channel->big_values > 288 && result == 0) + result = MAD_ERROR_BADBIGVALUES; + + channel->flags = 0; + + /* window_switching_flag */ + if (mad_bit_read(ptr, 1)) { + channel->block_type = mad_bit_read(ptr, 2); + + if (channel->block_type == 0 && result == 0) + result = MAD_ERROR_BADBLOCKTYPE; + + if (!lsf && channel->block_type == 2 && si->scfsi[ch] && result == 0) + result = MAD_ERROR_BADSCFSI; + + channel->region0_count = 7; + channel->region1_count = 36; + + if (mad_bit_read(ptr, 1)) + channel->flags |= mixed_block_flag; + else if (channel->block_type == 2) + channel->region0_count = 8; + + for (i = 0; i < 2; ++i) + channel->table_select[i] = mad_bit_read(ptr, 5); + +# if defined(DEBUG) + channel->table_select[2] = 4; /* not used */ +# endif + + for (i = 0; i < 3; ++i) + channel->subblock_gain[i] = mad_bit_read(ptr, 3); + } + else { + channel->block_type = 0; + + for (i = 0; i < 3; ++i) + channel->table_select[i] = mad_bit_read(ptr, 5); + + channel->region0_count = mad_bit_read(ptr, 4); + channel->region1_count = mad_bit_read(ptr, 3); + } + + /* [preflag,] scalefac_scale, count1table_select */ + channel->flags |= mad_bit_read(ptr, lsf ? 2 : 3); + } + } + + return result; +} + +/* + * NAME: III_scalefactors_lsf() + * DESCRIPTION: decode channel scalefactors for LSF from a bitstream + */ +static +unsigned int III_scalefactors_lsf(struct mad_bitptr *ptr, + struct channel *channel, + struct channel *gr1ch, int mode_extension, + unsigned int bits_left, unsigned int *part2_length) +{ + struct mad_bitptr start; + unsigned int scalefac_compress, index, slen[4], part, n, i; + unsigned char const *nsfb; + + start = *ptr; + + scalefac_compress = channel->scalefac_compress; + index = (channel->block_type == 2) ? + ((channel->flags & mixed_block_flag) ? 2 : 1) : 0; + + if (!((mode_extension & I_STEREO) && gr1ch)) { + if (scalefac_compress < 400) { + slen[0] = (scalefac_compress >> 4) / 5; + slen[1] = (scalefac_compress >> 4) % 5; + slen[2] = (scalefac_compress % 16) >> 2; + slen[3] = scalefac_compress % 4; + + nsfb = nsfb_table[0][index]; + } + else if (scalefac_compress < 500) { + scalefac_compress -= 400; + + slen[0] = (scalefac_compress >> 2) / 5; + slen[1] = (scalefac_compress >> 2) % 5; + slen[2] = scalefac_compress % 4; + slen[3] = 0; + + nsfb = nsfb_table[1][index]; + } + else { + scalefac_compress -= 500; + + slen[0] = scalefac_compress / 3; + slen[1] = scalefac_compress % 3; + slen[2] = 0; + slen[3] = 0; + + channel->flags |= preflag; + + nsfb = nsfb_table[2][index]; + } + + n = 0; + for (part = 0; part < 4; ++part) { + for (i = 0; i < nsfb[part]; ++i) { + if (bits_left < slen[part]) + return MAD_ERROR_BADSCFSI; + channel->scalefac[n++] = mad_bit_read(ptr, slen[part]); + bits_left -= slen[part]; + } + } + + while (n < 39) + channel->scalefac[n++] = 0; + } + else { /* (mode_extension & I_STEREO) && gr1ch (i.e. ch == 1) */ + scalefac_compress >>= 1; + + if (scalefac_compress < 180) { + slen[0] = scalefac_compress / 36; + slen[1] = (scalefac_compress % 36) / 6; + slen[2] = (scalefac_compress % 36) % 6; + slen[3] = 0; + + nsfb = nsfb_table[3][index]; + } + else if (scalefac_compress < 244) { + scalefac_compress -= 180; + + slen[0] = (scalefac_compress % 64) >> 4; + slen[1] = (scalefac_compress % 16) >> 2; + slen[2] = scalefac_compress % 4; + slen[3] = 0; + + nsfb = nsfb_table[4][index]; + } + else { + scalefac_compress -= 244; + + slen[0] = scalefac_compress / 3; + slen[1] = scalefac_compress % 3; + slen[2] = 0; + slen[3] = 0; + + nsfb = nsfb_table[5][index]; + } + + n = 0; + for (part = 0; part < 4; ++part) { + unsigned int max, is_pos; + + max = (1 << slen[part]) - 1; + + for (i = 0; i < nsfb[part]; ++i) { + if (bits_left < slen[part]) + return MAD_ERROR_BADSCFSI; + is_pos = mad_bit_read(ptr, slen[part]); + bits_left -= slen[part]; + + channel->scalefac[n] = is_pos; + gr1ch->scalefac[n++] = (is_pos == max); + } + } + + while (n < 39) { + channel->scalefac[n] = 0; + gr1ch->scalefac[n++] = 0; /* apparently not illegal */ + } + } + + *part2_length = mad_bit_length(&start, ptr); + return MAD_ERROR_NONE; +} + +/* + * NAME: III_scalefactors() + * DESCRIPTION: decode channel scalefactors of one granule from a bitstream + */ +static +unsigned int III_scalefactors(struct mad_bitptr *ptr, struct channel *channel, + struct channel const *gr0ch, unsigned int scfsi, + unsigned int bits_left, unsigned int *part2_length) +{ + struct mad_bitptr start; + unsigned int slen1, slen2, sfbi; + + start = *ptr; + + slen1 = sflen_table[channel->scalefac_compress].slen1; + slen2 = sflen_table[channel->scalefac_compress].slen2; + + if (channel->block_type == 2) { + unsigned int nsfb; + + sfbi = 0; + + nsfb = (channel->flags & mixed_block_flag) ? 8 + 3 * 3 : 6 * 3; + while (nsfb--) { + if (bits_left < slen1) + return MAD_ERROR_BADSCFSI; + channel->scalefac[sfbi++] = mad_bit_read(ptr, slen1); + bits_left -= slen1; + } + + nsfb = 6 * 3; + while (nsfb--) { + if (bits_left < slen2) + return MAD_ERROR_BADSCFSI; + channel->scalefac[sfbi++] = mad_bit_read(ptr, slen2); + bits_left -= slen2; + } + + nsfb = 1 * 3; + while (nsfb--) + channel->scalefac[sfbi++] = 0; + } + else { /* channel->block_type != 2 */ + if (scfsi & 0x8) { + for (sfbi = 0; sfbi < 6; ++sfbi) + channel->scalefac[sfbi] = gr0ch->scalefac[sfbi]; + } + else { + for (sfbi = 0; sfbi < 6; ++sfbi) { + if (bits_left < slen1) + return MAD_ERROR_BADSCFSI; + channel->scalefac[sfbi] = mad_bit_read(ptr, slen1); + bits_left -= slen1; + } + } + + if (scfsi & 0x4) { + for (sfbi = 6; sfbi < 11; ++sfbi) + channel->scalefac[sfbi] = gr0ch->scalefac[sfbi]; + } + else { + for (sfbi = 6; sfbi < 11; ++sfbi) { + if (bits_left < slen1) + return MAD_ERROR_BADSCFSI; + channel->scalefac[sfbi] = mad_bit_read(ptr, slen1); + bits_left -= slen1; + } + } + + if (scfsi & 0x2) { + for (sfbi = 11; sfbi < 16; ++sfbi) + channel->scalefac[sfbi] = gr0ch->scalefac[sfbi]; + } + else { + for (sfbi = 11; sfbi < 16; ++sfbi) { + if (bits_left < slen2) + return MAD_ERROR_BADSCFSI; + channel->scalefac[sfbi] = mad_bit_read(ptr, slen2); + bits_left -= slen2; + } + } + + if (scfsi & 0x1) { + for (sfbi = 16; sfbi < 21; ++sfbi) + channel->scalefac[sfbi] = gr0ch->scalefac[sfbi]; + } + else { + for (sfbi = 16; sfbi < 21; ++sfbi) { + if (bits_left < slen2) + return MAD_ERROR_BADSCFSI; + channel->scalefac[sfbi] = mad_bit_read(ptr, slen2); + bits_left -= slen2; + } + } + + channel->scalefac[21] = 0; + } + + *part2_length = mad_bit_length(&start, ptr); + return MAD_ERROR_NONE; +} + +/* + * The Layer III formula for requantization and scaling is defined by + * section 2.4.3.4.7.1 of ISO/IEC 11172-3, as follows: + * + * long blocks: + * xr[i] = sign(is[i]) * abs(is[i])^(4/3) * + * 2^((1/4) * (global_gain - 210)) * + * 2^-(scalefac_multiplier * + * (scalefac_l[sfb] + preflag * pretab[sfb])) + * + * short blocks: + * xr[i] = sign(is[i]) * abs(is[i])^(4/3) * + * 2^((1/4) * (global_gain - 210 - 8 * subblock_gain[w])) * + * 2^-(scalefac_multiplier * scalefac_s[sfb][w]) + * + * where: + * scalefac_multiplier = (scalefac_scale + 1) / 2 + * + * The routines III_exponents() and III_requantize() facilitate this + * calculation. + */ + +/* + * NAME: III_exponents() + * DESCRIPTION: calculate scalefactor exponents + */ +static +void III_exponents(struct channel const *channel, + unsigned char const *sfbwidth, signed int exponents[39]) +{ + signed int gain; + unsigned int scalefac_multiplier, sfbi; + + gain = (signed int) channel->global_gain - 210; + scalefac_multiplier = (channel->flags & scalefac_scale) ? 2 : 1; + + if (channel->block_type == 2) { + unsigned int l; + signed int gain0, gain1, gain2; + + sfbi = l = 0; + + if (channel->flags & mixed_block_flag) { + unsigned int premask; + + premask = (channel->flags & preflag) ? ~0 : 0; + + /* long block subbands 0-1 */ + + while (l < 36) { + exponents[sfbi] = gain - + (signed int) ((channel->scalefac[sfbi] + (pretab[sfbi] & premask)) << + scalefac_multiplier); + + l += sfbwidth[sfbi++]; + } + } + + /* this is probably wrong for 8000 Hz short/mixed blocks */ + + gain0 = gain - 8 * (signed int) channel->subblock_gain[0]; + gain1 = gain - 8 * (signed int) channel->subblock_gain[1]; + gain2 = gain - 8 * (signed int) channel->subblock_gain[2]; + + while (l < 576) { + exponents[sfbi + 0] = gain0 - + (signed int) (channel->scalefac[sfbi + 0] << scalefac_multiplier); + exponents[sfbi + 1] = gain1 - + (signed int) (channel->scalefac[sfbi + 1] << scalefac_multiplier); + exponents[sfbi + 2] = gain2 - + (signed int) (channel->scalefac[sfbi + 2] << scalefac_multiplier); + + l += 3 * sfbwidth[sfbi]; + sfbi += 3; + } + } + else { /* channel->block_type != 2 */ + if (channel->flags & preflag) { + for (sfbi = 0; sfbi < 22; ++sfbi) { + exponents[sfbi] = gain - + (signed int) ((channel->scalefac[sfbi] + pretab[sfbi]) << + scalefac_multiplier); + } + } + else { + for (sfbi = 0; sfbi < 22; ++sfbi) { + exponents[sfbi] = gain - + (signed int) (channel->scalefac[sfbi] << scalefac_multiplier); + } + } + } +} + +/* + * NAME: III_requantize() + * DESCRIPTION: requantize one (positive) value + */ +static +mad_fixed_t III_requantize(unsigned int value, signed int exp) +{ + mad_fixed_t requantized; + signed int frac; + struct fixedfloat const *power; + + frac = exp % 4; /* assumes sign(frac) == sign(exp) */ + exp /= 4; + + power = &rq_table[value]; + requantized = power->mantissa; + exp += power->exponent; + + if (exp < 0) { + if (-exp >= sizeof(mad_fixed_t) * CHAR_BIT) { + /* underflow */ + requantized = 0; + } + else { + requantized += 1L << (-exp - 1); + requantized >>= -exp; + } + } + else { + if (exp >= 5) { + /* overflow */ +# if defined(DEBUG) + fprintf(stderr, "requantize overflow (%f * 2^%d)\n", + mad_f_todouble(requantized), exp); +# endif + requantized = MAD_F_MAX; + } + else + requantized <<= exp; + } + + return frac ? mad_f_mul(requantized, root_table[3 + frac]) : requantized; +} + +/* we must take care that sz >= bits and sz < sizeof(long) lest bits == 0 */ +# define MASK(cache, sz, bits) \ + (((cache) >> ((sz) - (bits))) & ((1 << (bits)) - 1)) +# define MASK1BIT(cache, sz) \ + ((cache) & (1 << ((sz) - 1))) + +/* + * NAME: III_huffdecode() + * DESCRIPTION: decode Huffman code words of one channel of one granule + */ +static +enum mad_error III_huffdecode(struct mad_bitptr *ptr, mad_fixed_t xr[576], + struct channel *channel, + unsigned char const *sfbwidth, + signed int part3_length) +{ + signed int exponents[39], exp; + signed int const *expptr; + struct mad_bitptr peek; + signed int bits_left, cachesz, fakebits; + register mad_fixed_t *xrptr; + mad_fixed_t const *sfbound; + register unsigned long bitcache; + + bits_left = part3_length; + + III_exponents(channel, sfbwidth, exponents); + + peek = *ptr; + mad_bit_skip(ptr, bits_left); + + /* align bit reads to byte boundaries */ + cachesz = mad_bit_bitsleft(&peek); + cachesz += ((32 - 1 - 24) + (24 - cachesz)) & ~7; + + if (bits_left < cachesz) { + cachesz = bits_left; + } + bitcache = mad_bit_read(&peek, cachesz); + bits_left -= cachesz; + fakebits = 0; + + xrptr = &xr[0]; + + /* big_values */ + { + unsigned int region, rcount; + struct hufftable const *entry; + union huffpair const *table; + unsigned int linbits, startbits, big_values, reqhits; + mad_fixed_t reqcache[16]; + + sfbound = xrptr + *sfbwidth++; + rcount = channel->region0_count + 1; + + entry = &mad_huff_pair_table[channel->table_select[region = 0]]; + table = entry->table; + linbits = entry->linbits; + startbits = entry->startbits; + + if (table == 0) + return MAD_ERROR_BADHUFFTABLE; + + expptr = &exponents[0]; + exp = *expptr++; + reqhits = 0; + + big_values = channel->big_values; + + while (big_values-- && cachesz + bits_left - fakebits > 0) { + union huffpair const *pair; + unsigned int clumpsz, value; + register mad_fixed_t requantized; + + if (xrptr == sfbound) { + sfbound += *sfbwidth++; + + /* change table if region boundary */ + + if (--rcount == 0) { + if (region == 0) + rcount = channel->region1_count + 1; + else + rcount = 0; /* all remaining */ + + entry = &mad_huff_pair_table[channel->table_select[++region]]; + table = entry->table; + linbits = entry->linbits; + startbits = entry->startbits; + + if (table == 0) + return MAD_ERROR_BADHUFFTABLE; + } + + if (exp != *expptr) { + exp = *expptr; + reqhits = 0; + } + + ++expptr; + } + + if (cachesz < 21) { + unsigned int bits; + + bits = ((32 - 1 - 21) + (21 - cachesz)) & ~7; + if (bits_left < bits) { + bits = bits_left; + } + bitcache = (bitcache << bits) | mad_bit_read(&peek, bits); + cachesz += bits; + bits_left -= bits; + } + if (cachesz < 21) { + unsigned int bits = 21 - cachesz; + bitcache <<= bits; + cachesz += bits; + fakebits += bits; + } + + /* hcod (0..19) */ + + clumpsz = startbits; + pair = &table[MASK(bitcache, cachesz, clumpsz)]; + + while (!pair->final) { + cachesz -= clumpsz; + + clumpsz = pair->ptr.bits; + pair = &table[pair->ptr.offset + MASK(bitcache, cachesz, clumpsz)]; + } + + cachesz -= pair->value.hlen; + if (cachesz < fakebits) + return MAD_ERROR_BADHUFFDATA; + + if (linbits) { + /* x (0..14) */ + + value = pair->value.x; + + switch (value) { + case 0: + xrptr[0] = 0; + break; + + case 15: + if (cachesz < linbits + 2) { + unsigned int bits = 16; + if (bits_left < 16) + bits = bits_left; + bitcache = (bitcache << bits) | mad_bit_read(&peek, bits); + cachesz += bits; + bits_left -= bits; + } + if (cachesz - fakebits < linbits) + return MAD_ERROR_BADHUFFDATA; + + value += MASK(bitcache, cachesz, linbits); + cachesz -= linbits; + + requantized = III_requantize(value, exp); + goto x_final; + + default: + if (reqhits & (1 << value)) + requantized = reqcache[value]; + else { + reqhits |= (1 << value); + requantized = reqcache[value] = III_requantize(value, exp); + } + + x_final: + if (cachesz - fakebits < 1) + return MAD_ERROR_BADHUFFDATA; + xrptr[0] = MASK1BIT(bitcache, cachesz--) ? + -requantized : requantized; + } + + /* y (0..14) */ + + value = pair->value.y; + + switch (value) { + case 0: + xrptr[1] = 0; + break; + + case 15: + if (cachesz < linbits + 1) { + unsigned int bits = 16; + if (bits_left < 16) + bits = bits_left; + bitcache = (bitcache << bits) | mad_bit_read(&peek, bits); + cachesz += bits; + bits_left -= bits; + } + if (cachesz - fakebits < linbits) + return MAD_ERROR_BADHUFFDATA; + + value += MASK(bitcache, cachesz, linbits); + cachesz -= linbits; + + requantized = III_requantize(value, exp); + goto y_final; + + default: + if (reqhits & (1 << value)) + requantized = reqcache[value]; + else { + reqhits |= (1 << value); + requantized = reqcache[value] = III_requantize(value, exp); + } + + y_final: + if (cachesz - fakebits < 1) + return MAD_ERROR_BADHUFFDATA; + xrptr[1] = MASK1BIT(bitcache, cachesz--) ? + -requantized : requantized; + } + } + else { + /* x (0..1) */ + + value = pair->value.x; + + if (value == 0) + xrptr[0] = 0; + else { + if (reqhits & (1 << value)) + requantized = reqcache[value]; + else { + reqhits |= (1 << value); + requantized = reqcache[value] = III_requantize(value, exp); + } + + if (cachesz - fakebits < 1) + return MAD_ERROR_BADHUFFDATA; + xrptr[0] = MASK1BIT(bitcache, cachesz--) ? + -requantized : requantized; + } + + /* y (0..1) */ + + value = pair->value.y; + + if (value == 0) + xrptr[1] = 0; + else { + if (reqhits & (1 << value)) + requantized = reqcache[value]; + else { + reqhits |= (1 << value); + requantized = reqcache[value] = III_requantize(value, exp); + } + + if (cachesz - fakebits < 1) + return MAD_ERROR_BADHUFFDATA; + xrptr[1] = MASK1BIT(bitcache, cachesz--) ? + -requantized : requantized; + } + } + + xrptr += 2; + } + } + + /* count1 */ + { + union huffquad const *table; + register mad_fixed_t requantized; + + table = mad_huff_quad_table[channel->flags & count1table_select]; + + requantized = III_requantize(1, exp); + + while (cachesz + bits_left - fakebits > 0 && xrptr <= &xr[572]) { + union huffquad const *quad; + + /* hcod (1..6) */ + + if (cachesz < 10) { + unsigned int bits = 16; + if (bits_left < 16) + bits = bits_left; + bitcache = (bitcache << bits) | mad_bit_read(&peek, bits); + cachesz += bits; + bits_left -= bits; + } + if (cachesz < 10) { + unsigned int bits = 10 - cachesz; + bitcache <<= bits; + cachesz += bits; + fakebits += bits; + } + + quad = &table[MASK(bitcache, cachesz, 4)]; + + /* quad tables guaranteed to have at most one extra lookup */ + if (!quad->final) { + cachesz -= 4; + + quad = &table[quad->ptr.offset + + MASK(bitcache, cachesz, quad->ptr.bits)]; + } + + if (cachesz - fakebits < quad->value.hlen + quad->value.v + + quad->value.w + quad->value.x + quad->value.y) + /* We don't have enough bits to read one more entry, consider them + * stuffing bits. */ + break; + cachesz -= quad->value.hlen; + + if (xrptr == sfbound) { + sfbound += *sfbwidth++; + + if (exp != *expptr) { + exp = *expptr; + requantized = III_requantize(1, exp); + } + + ++expptr; + } + + /* v (0..1) */ + + xrptr[0] = quad->value.v ? + (MASK1BIT(bitcache, cachesz--) ? -requantized : requantized) : 0; + + /* w (0..1) */ + + xrptr[1] = quad->value.w ? + (MASK1BIT(bitcache, cachesz--) ? -requantized : requantized) : 0; + + xrptr += 2; + + if (xrptr == sfbound) { + sfbound += *sfbwidth++; + + if (exp != *expptr) { + exp = *expptr; + requantized = III_requantize(1, exp); + } + + ++expptr; + } + + /* x (0..1) */ + + xrptr[0] = quad->value.x ? + (MASK1BIT(bitcache, cachesz--) ? -requantized : requantized) : 0; + + /* y (0..1) */ + + xrptr[1] = quad->value.y ? + (MASK1BIT(bitcache, cachesz--) ? -requantized : requantized) : 0; + + xrptr += 2; + } + } + +# if 0 && defined(DEBUG) + if (bits_left < 0) + fprintf(stderr, "read %d bits too many\n", -bits_left); + else if (cachesz + bits_left > 0) + fprintf(stderr, "%d stuffing bits\n", cachesz + bits_left); +# endif + + /* rzero */ + while (xrptr < &xr[576]) { + xrptr[0] = 0; + xrptr[1] = 0; + + xrptr += 2; + } + + return MAD_ERROR_NONE; +} + +# undef MASK +# undef MASK1BIT + +/* + * NAME: III_reorder() + * DESCRIPTION: reorder frequency lines of a short block into subband order + */ +static +void III_reorder(mad_fixed_t xr[576], struct channel const *channel, + unsigned char const sfbwidth[39]) +{ + mad_fixed_t tmp[32][3][6]; + unsigned int sb, l, f, w, sbw[3], sw[3]; + + /* this is probably wrong for 8000 Hz mixed blocks */ + + sb = 0; + if (channel->flags & mixed_block_flag) { + sb = 2; + + l = 0; + while (l < 36) + l += *sfbwidth++; + } + + for (w = 0; w < 3; ++w) { + sbw[w] = sb; + sw[w] = 0; + } + + f = *sfbwidth++; + w = 0; + + for (l = 18 * sb; l < 576; ++l) { + if (f-- == 0) { + f = *sfbwidth++ - 1; + w = (w + 1) % 3; + } + + tmp[sbw[w]][w][sw[w]++] = xr[l]; + + if (sw[w] == 6) { + sw[w] = 0; + ++sbw[w]; + } + } + + memcpy(&xr[18 * sb], &tmp[sb], (576 - 18 * sb) * sizeof(mad_fixed_t)); +} + +/* + * NAME: III_stereo() + * DESCRIPTION: perform joint stereo processing on a granule + */ +static +enum mad_error III_stereo(mad_fixed_t xr[2][576], + struct granule const *granule, + struct mad_header *header, + unsigned char const *sfbwidth) +{ + short modes[39]; + unsigned int sfbi, l, n, i; + + if (granule->ch[0].block_type != + granule->ch[1].block_type || + (granule->ch[0].flags & mixed_block_flag) != + (granule->ch[1].flags & mixed_block_flag)) + return MAD_ERROR_BADSTEREO; + + for (i = 0; i < 39; ++i) + modes[i] = header->mode_extension; + + /* intensity stereo */ + + if (header->mode_extension & I_STEREO) { + struct channel const *right_ch = &granule->ch[1]; + mad_fixed_t const *right_xr = xr[1]; + unsigned int is_pos; + + header->flags |= MAD_FLAG_I_STEREO; + + /* first determine which scalefactor bands are to be processed */ + + if (right_ch->block_type == 2) { + unsigned int lower, start, max, bound[3], w; + + lower = start = max = bound[0] = bound[1] = bound[2] = 0; + + sfbi = l = 0; + + if (right_ch->flags & mixed_block_flag) { + while (l < 36) { + n = sfbwidth[sfbi++]; + + for (i = 0; i < n; ++i) { + if (right_xr[i]) { + lower = sfbi; + break; + } + } + + right_xr += n; + l += n; + } + + start = sfbi; + } + + w = 0; + while (l < 576) { + n = sfbwidth[sfbi++]; + + for (i = 0; i < n; ++i) { + if (right_xr[i]) { + max = bound[w] = sfbi; + break; + } + } + + right_xr += n; + l += n; + w = (w + 1) % 3; + } + + if (max) + lower = start; + + /* long blocks */ + + for (i = 0; i < lower; ++i) + modes[i] = header->mode_extension & ~I_STEREO; + + /* short blocks */ + + w = 0; + for (i = start; i < max; ++i) { + if (i < bound[w]) + modes[i] = header->mode_extension & ~I_STEREO; + + w = (w + 1) % 3; + } + } + else { /* right_ch->block_type != 2 */ + unsigned int bound; + + bound = 0; + for (sfbi = l = 0; l < 576; l += n) { + n = sfbwidth[sfbi++]; + + for (i = 0; i < n; ++i) { + if (right_xr[i]) { + bound = sfbi; + break; + } + } + + right_xr += n; + } + + for (i = 0; i < bound; ++i) + modes[i] = header->mode_extension & ~I_STEREO; + } + + /* now do the actual processing */ + + if (header->flags & MAD_FLAG_LSF_EXT) { + unsigned char const *illegal_pos = granule[1].ch[1].scalefac; + mad_fixed_t const *lsf_scale; + + /* intensity_scale */ + lsf_scale = is_lsf_table[right_ch->scalefac_compress & 0x1]; + + for (sfbi = l = 0; l < 576; ++sfbi, l += n) { + n = sfbwidth[sfbi]; + + if (!(modes[sfbi] & I_STEREO)) + continue; + + if (illegal_pos[sfbi]) { + modes[sfbi] &= ~I_STEREO; + continue; + } + + is_pos = right_ch->scalefac[sfbi]; + + for (i = 0; i < n; ++i) { + register mad_fixed_t left; + + left = xr[0][l + i]; + + if (is_pos == 0) + xr[1][l + i] = left; + else { + register mad_fixed_t opposite; + + opposite = mad_f_mul(left, lsf_scale[(is_pos - 1) / 2]); + + if (is_pos & 1) { + xr[0][l + i] = opposite; + xr[1][l + i] = left; + } + else + xr[1][l + i] = opposite; + } + } + } + } + else { /* !(header->flags & MAD_FLAG_LSF_EXT) */ + for (sfbi = l = 0; l < 576; ++sfbi, l += n) { + n = sfbwidth[sfbi]; + + if (!(modes[sfbi] & I_STEREO)) + continue; + + is_pos = right_ch->scalefac[sfbi]; + + if (is_pos >= 7) { /* illegal intensity position */ + modes[sfbi] &= ~I_STEREO; + continue; + } + + for (i = 0; i < n; ++i) { + register mad_fixed_t left; + + left = xr[0][l + i]; + + xr[0][l + i] = mad_f_mul(left, is_table[ is_pos]); + xr[1][l + i] = mad_f_mul(left, is_table[6 - is_pos]); + } + } + } + } + + /* middle/side stereo */ + + if (header->mode_extension & MS_STEREO) { + register mad_fixed_t invsqrt2; + + header->flags |= MAD_FLAG_MS_STEREO; + + invsqrt2 = root_table[3 + -2]; + + for (sfbi = l = 0; l < 576; ++sfbi, l += n) { + n = sfbwidth[sfbi]; + + if (modes[sfbi] != MS_STEREO) + continue; + + for (i = 0; i < n; ++i) { + register mad_fixed_t m, s; + + m = xr[0][l + i]; + s = xr[1][l + i]; + + xr[0][l + i] = mad_f_mul(m + s, invsqrt2); /* l = (m + s) / sqrt(2) */ + xr[1][l + i] = mad_f_mul(m - s, invsqrt2); /* r = (m - s) / sqrt(2) */ + } + } + } + + return MAD_ERROR_NONE; +} + +/* + * NAME: III_aliasreduce() + * DESCRIPTION: perform frequency line alias reduction + */ +static +void III_aliasreduce(mad_fixed_t xr[576], int lines) +{ + mad_fixed_t const *bound; + int i; + + bound = &xr[lines]; + for (xr += 18; xr < bound; xr += 18) { + for (i = 0; i < 8; ++i) { + register mad_fixed_t a, b; + register mad_fixed64hi_t hi; + register mad_fixed64lo_t lo; + + a = xr[-1 - i]; + b = xr[ i]; + +# if defined(ASO_ZEROCHECK) + if (a | b) { +# endif + MAD_F_ML0(hi, lo, a, cs[i]); + MAD_F_MLA(hi, lo, -b, ca[i]); + + xr[-1 - i] = MAD_F_MLZ(hi, lo); + + MAD_F_ML0(hi, lo, b, cs[i]); + MAD_F_MLA(hi, lo, a, ca[i]); + + xr[ i] = MAD_F_MLZ(hi, lo); +# if defined(ASO_ZEROCHECK) + } +# endif + } + } +} + +# if defined(ASO_IMDCT) +void III_imdct_l(mad_fixed_t const [18], mad_fixed_t [36], unsigned int); +# else +# if 1 +static +void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[18]) +{ + mad_fixed_t a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; + mad_fixed_t a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25; + mad_fixed_t m0, m1, m2, m3, m4, m5, m6, m7; + + enum { + c0 = MAD_F(0x1f838b8d), /* 2 * cos( 1 * PI / 18) */ + c1 = MAD_F(0x1bb67ae8), /* 2 * cos( 3 * PI / 18) */ + c2 = MAD_F(0x18836fa3), /* 2 * cos( 4 * PI / 18) */ + c3 = MAD_F(0x1491b752), /* 2 * cos( 5 * PI / 18) */ + c4 = MAD_F(0x0af1d43a), /* 2 * cos( 7 * PI / 18) */ + c5 = MAD_F(0x058e86a0), /* 2 * cos( 8 * PI / 18) */ + c6 = -MAD_F(0x1e11f642) /* 2 * cos(16 * PI / 18) */ + }; + + a0 = x[3] + x[5]; + a1 = x[3] - x[5]; + a2 = x[6] + x[2]; + a3 = x[6] - x[2]; + a4 = x[1] + x[7]; + a5 = x[1] - x[7]; + a6 = x[8] + x[0]; + a7 = x[8] - x[0]; + + a8 = a0 + a2; + a9 = a0 - a2; + a10 = a0 - a6; + a11 = a2 - a6; + a12 = a8 + a6; + a13 = a1 - a3; + a14 = a13 + a7; + a15 = a3 + a7; + a16 = a1 - a7; + a17 = a1 + a3; + + m0 = mad_f_mul(a17, -c3); + m1 = mad_f_mul(a16, -c0); + m2 = mad_f_mul(a15, -c4); + m3 = mad_f_mul(a14, -c1); + m4 = mad_f_mul(a5, -c1); + m5 = mad_f_mul(a11, -c6); + m6 = mad_f_mul(a10, -c5); + m7 = mad_f_mul(a9, -c2); + + a18 = x[4] + a4; + a19 = 2 * x[4] - a4; + a20 = a19 + m5; + a21 = a19 - m5; + a22 = a19 + m6; + a23 = m4 + m2; + a24 = m4 - m2; + a25 = m4 + m1; + + /* output to every other slot for convenience */ + + y[ 0] = a18 + a12; + y[ 2] = m0 - a25; + y[ 4] = m7 - a20; + y[ 6] = m3; + y[ 8] = a21 - m6; + y[10] = a24 - m1; + y[12] = a12 - 2 * a18; + y[14] = a23 + m0; + y[16] = a22 + m7; +} + +static inline +void sdctII(mad_fixed_t const x[18], mad_fixed_t X[18]) +{ + mad_fixed_t tmp[9]; + int i; + + /* scale[i] = 2 * cos(PI * (2 * i + 1) / (2 * 18)) */ + static mad_fixed_t const scale[9] = { + MAD_F(0x1fe0d3b4), MAD_F(0x1ee8dd47), MAD_F(0x1d007930), + MAD_F(0x1a367e59), MAD_F(0x16a09e66), MAD_F(0x125abcf8), + MAD_F(0x0d8616bc), MAD_F(0x08483ee1), MAD_F(0x02c9fad7) + }; + + /* divide the 18-point SDCT-II into two 9-point SDCT-IIs */ + + /* even input butterfly */ + + for (i = 0; i < 9; i += 3) { + tmp[i + 0] = x[i + 0] + x[18 - (i + 0) - 1]; + tmp[i + 1] = x[i + 1] + x[18 - (i + 1) - 1]; + tmp[i + 2] = x[i + 2] + x[18 - (i + 2) - 1]; + } + + fastsdct(tmp, &X[0]); + + /* odd input butterfly and scaling */ + + for (i = 0; i < 9; i += 3) { + tmp[i + 0] = mad_f_mul(x[i + 0] - x[18 - (i + 0) - 1], scale[i + 0]); + tmp[i + 1] = mad_f_mul(x[i + 1] - x[18 - (i + 1) - 1], scale[i + 1]); + tmp[i + 2] = mad_f_mul(x[i + 2] - x[18 - (i + 2) - 1], scale[i + 2]); + } + + fastsdct(tmp, &X[1]); + + /* output accumulation */ + + for (i = 3; i < 18; i += 8) { + X[i + 0] -= X[(i + 0) - 2]; + X[i + 2] -= X[(i + 2) - 2]; + X[i + 4] -= X[(i + 4) - 2]; + X[i + 6] -= X[(i + 6) - 2]; + } +} + +static inline +void dctIV(mad_fixed_t const y[18], mad_fixed_t X[18]) +{ + mad_fixed_t tmp[18]; + int i; + + /* scale[i] = 2 * cos(PI * (2 * i + 1) / (4 * 18)) */ + static mad_fixed_t const scale[18] = { + MAD_F(0x1ff833fa), MAD_F(0x1fb9ea93), MAD_F(0x1f3dd120), + MAD_F(0x1e84d969), MAD_F(0x1d906bcf), MAD_F(0x1c62648b), + MAD_F(0x1afd100f), MAD_F(0x1963268b), MAD_F(0x1797c6a4), + MAD_F(0x159e6f5b), MAD_F(0x137af940), MAD_F(0x11318ef3), + MAD_F(0x0ec6a507), MAD_F(0x0c3ef153), MAD_F(0x099f61c5), + MAD_F(0x06ed12c5), MAD_F(0x042d4544), MAD_F(0x0165547c) + }; + + /* scaling */ + + for (i = 0; i < 18; i += 3) { + tmp[i + 0] = mad_f_mul(y[i + 0], scale[i + 0]); + tmp[i + 1] = mad_f_mul(y[i + 1], scale[i + 1]); + tmp[i + 2] = mad_f_mul(y[i + 2], scale[i + 2]); + } + + /* SDCT-II */ + + sdctII(tmp, X); + + /* scale reduction and output accumulation */ + + X[0] /= 2; + for (i = 1; i < 17; i += 4) { + X[i + 0] = X[i + 0] / 2 - X[(i + 0) - 1]; + X[i + 1] = X[i + 1] / 2 - X[(i + 1) - 1]; + X[i + 2] = X[i + 2] / 2 - X[(i + 2) - 1]; + X[i + 3] = X[i + 3] / 2 - X[(i + 3) - 1]; + } + X[17] = X[17] / 2 - X[16]; +} + +/* + * NAME: imdct36 + * DESCRIPTION: perform X[18]->x[36] IMDCT using Szu-Wei Lee's fast algorithm + */ +static inline +void imdct36(mad_fixed_t const x[18], mad_fixed_t y[36]) +{ + mad_fixed_t tmp[18]; + int i; + + /* DCT-IV */ + + dctIV(x, tmp); + + /* convert 18-point DCT-IV to 36-point IMDCT */ + + for (i = 0; i < 9; i += 3) { + y[i + 0] = tmp[9 + (i + 0)]; + y[i + 1] = tmp[9 + (i + 1)]; + y[i + 2] = tmp[9 + (i + 2)]; + } + for (i = 9; i < 27; i += 3) { + y[i + 0] = -tmp[36 - (9 + (i + 0)) - 1]; + y[i + 1] = -tmp[36 - (9 + (i + 1)) - 1]; + y[i + 2] = -tmp[36 - (9 + (i + 2)) - 1]; + } + for (i = 27; i < 36; i += 3) { + y[i + 0] = -tmp[(i + 0) - 27]; + y[i + 1] = -tmp[(i + 1) - 27]; + y[i + 2] = -tmp[(i + 2) - 27]; + } +} +# else +/* + * NAME: imdct36 + * DESCRIPTION: perform X[18]->x[36] IMDCT + */ +static inline +void imdct36(mad_fixed_t const X[18], mad_fixed_t x[36]) +{ + mad_fixed_t t0, t1, t2, t3, t4, t5, t6, t7; + mad_fixed_t t8, t9, t10, t11, t12, t13, t14, t15; + register mad_fixed64hi_t hi; + register mad_fixed64lo_t lo; + + MAD_F_ML0(hi, lo, X[4], MAD_F(0x0ec835e8)); + MAD_F_MLA(hi, lo, X[13], MAD_F(0x061f78aa)); + + t6 = MAD_F_MLZ(hi, lo); + + MAD_F_MLA(hi, lo, (t14 = X[1] - X[10]), -MAD_F(0x061f78aa)); + MAD_F_MLA(hi, lo, (t15 = X[7] + X[16]), -MAD_F(0x0ec835e8)); + + t0 = MAD_F_MLZ(hi, lo); + + MAD_F_MLA(hi, lo, (t8 = X[0] - X[11] - X[12]), MAD_F(0x0216a2a2)); + MAD_F_MLA(hi, lo, (t9 = X[2] - X[9] - X[14]), MAD_F(0x09bd7ca0)); + MAD_F_MLA(hi, lo, (t10 = X[3] - X[8] - X[15]), -MAD_F(0x0cb19346)); + MAD_F_MLA(hi, lo, (t11 = X[5] - X[6] - X[17]), -MAD_F(0x0fdcf549)); + + x[7] = MAD_F_MLZ(hi, lo); + x[10] = -x[7]; + + MAD_F_ML0(hi, lo, t8, -MAD_F(0x0cb19346)); + MAD_F_MLA(hi, lo, t9, MAD_F(0x0fdcf549)); + MAD_F_MLA(hi, lo, t10, MAD_F(0x0216a2a2)); + MAD_F_MLA(hi, lo, t11, -MAD_F(0x09bd7ca0)); + + x[19] = x[34] = MAD_F_MLZ(hi, lo) - t0; + + t12 = X[0] - X[3] + X[8] - X[11] - X[12] + X[15]; + t13 = X[2] + X[5] - X[6] - X[9] - X[14] - X[17]; + + MAD_F_ML0(hi, lo, t12, -MAD_F(0x0ec835e8)); + MAD_F_MLA(hi, lo, t13, MAD_F(0x061f78aa)); + + x[22] = x[31] = MAD_F_MLZ(hi, lo) + t0; + + MAD_F_ML0(hi, lo, X[1], -MAD_F(0x09bd7ca0)); + MAD_F_MLA(hi, lo, X[7], MAD_F(0x0216a2a2)); + MAD_F_MLA(hi, lo, X[10], -MAD_F(0x0fdcf549)); + MAD_F_MLA(hi, lo, X[16], MAD_F(0x0cb19346)); + + t1 = MAD_F_MLZ(hi, lo) + t6; + + MAD_F_ML0(hi, lo, X[0], MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[3], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[5], -MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[6], MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[8], -MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[9], MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[11], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[15], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x0f9ee890)); + + x[6] = MAD_F_MLZ(hi, lo) + t1; + x[11] = -x[6]; + + MAD_F_ML0(hi, lo, X[0], -MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[2], -MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[3], MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[5], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[6], MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[8], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[9], -MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[15], MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[17], MAD_F(0x04cfb0e2)); + + x[23] = x[30] = MAD_F_MLZ(hi, lo) + t1; + + MAD_F_ML0(hi, lo, X[0], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[3], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[5], MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[6], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[8], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[9], -MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[11], MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[15], MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x0acf37ad)); + + x[18] = x[35] = MAD_F_MLZ(hi, lo) - t1; + + MAD_F_ML0(hi, lo, X[4], MAD_F(0x061f78aa)); + MAD_F_MLA(hi, lo, X[13], -MAD_F(0x0ec835e8)); + + t7 = MAD_F_MLZ(hi, lo); + + MAD_F_MLA(hi, lo, X[1], -MAD_F(0x0cb19346)); + MAD_F_MLA(hi, lo, X[7], MAD_F(0x0fdcf549)); + MAD_F_MLA(hi, lo, X[10], MAD_F(0x0216a2a2)); + MAD_F_MLA(hi, lo, X[16], -MAD_F(0x09bd7ca0)); + + t2 = MAD_F_MLZ(hi, lo); + + MAD_F_MLA(hi, lo, X[0], MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[3], -MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[5], MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[6], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[8], -MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[9], MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[12], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[15], MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[17], MAD_F(0x0f426cb5)); + + x[5] = MAD_F_MLZ(hi, lo); + x[12] = -x[5]; + + MAD_F_ML0(hi, lo, X[0], MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[2], -MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[3], MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[5], -MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[6], -MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[8], MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[9], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[11], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[15], MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x0bcbe352)); + + x[0] = MAD_F_MLZ(hi, lo) + t2; + x[17] = -x[0]; + + MAD_F_ML0(hi, lo, X[0], -MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[2], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[3], -MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[5], MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[6], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[8], MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[9], MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[14], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[15], -MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x03768962)); + + x[24] = x[29] = MAD_F_MLZ(hi, lo) + t2; + + MAD_F_ML0(hi, lo, X[1], -MAD_F(0x0216a2a2)); + MAD_F_MLA(hi, lo, X[7], -MAD_F(0x09bd7ca0)); + MAD_F_MLA(hi, lo, X[10], MAD_F(0x0cb19346)); + MAD_F_MLA(hi, lo, X[16], MAD_F(0x0fdcf549)); + + t3 = MAD_F_MLZ(hi, lo) + t7; + + MAD_F_ML0(hi, lo, X[0], MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[3], -MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[5], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[6], MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[8], MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[9], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[12], MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[15], -MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x0ffc19fd)); + + x[8] = MAD_F_MLZ(hi, lo) + t3; + x[9] = -x[8]; + + MAD_F_ML0(hi, lo, X[0], -MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[3], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[5], -MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[6], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[8], MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[9], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[14], -MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[15], MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[17], MAD_F(0x07635284)); + + x[21] = x[32] = MAD_F_MLZ(hi, lo) + t3; + + MAD_F_ML0(hi, lo, X[0], -MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[3], MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[5], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[6], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[8], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[9], MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[12], MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[15], -MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x0898c779)); + + x[20] = x[33] = MAD_F_MLZ(hi, lo) - t3; + + MAD_F_ML0(hi, lo, t14, -MAD_F(0x0ec835e8)); + MAD_F_MLA(hi, lo, t15, MAD_F(0x061f78aa)); + + t4 = MAD_F_MLZ(hi, lo) - t7; + + MAD_F_ML0(hi, lo, t12, MAD_F(0x061f78aa)); + MAD_F_MLA(hi, lo, t13, MAD_F(0x0ec835e8)); + + x[4] = MAD_F_MLZ(hi, lo) + t4; + x[13] = -x[4]; + + MAD_F_ML0(hi, lo, t8, MAD_F(0x09bd7ca0)); + MAD_F_MLA(hi, lo, t9, -MAD_F(0x0216a2a2)); + MAD_F_MLA(hi, lo, t10, MAD_F(0x0fdcf549)); + MAD_F_MLA(hi, lo, t11, -MAD_F(0x0cb19346)); + + x[1] = MAD_F_MLZ(hi, lo) + t4; + x[16] = -x[1]; + + MAD_F_ML0(hi, lo, t8, -MAD_F(0x0fdcf549)); + MAD_F_MLA(hi, lo, t9, -MAD_F(0x0cb19346)); + MAD_F_MLA(hi, lo, t10, -MAD_F(0x09bd7ca0)); + MAD_F_MLA(hi, lo, t11, -MAD_F(0x0216a2a2)); + + x[25] = x[28] = MAD_F_MLZ(hi, lo) + t4; + + MAD_F_ML0(hi, lo, X[1], -MAD_F(0x0fdcf549)); + MAD_F_MLA(hi, lo, X[7], -MAD_F(0x0cb19346)); + MAD_F_MLA(hi, lo, X[10], -MAD_F(0x09bd7ca0)); + MAD_F_MLA(hi, lo, X[16], -MAD_F(0x0216a2a2)); + + t5 = MAD_F_MLZ(hi, lo) - t6; + + MAD_F_ML0(hi, lo, X[0], MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[3], MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[5], MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[6], MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[8], -MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[9], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[12], MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[14], -MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[15], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x0d7e8807)); + + x[2] = MAD_F_MLZ(hi, lo) + t5; + x[15] = -x[2]; + + MAD_F_ML0(hi, lo, X[0], MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[2], MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[3], MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[5], MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[6], -MAD_F(0x00b2aa3e)); + MAD_F_MLA(hi, lo, X[8], MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[9], -MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[11], MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[14], MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[15], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[17], MAD_F(0x0e313245)); + + x[3] = MAD_F_MLZ(hi, lo) + t5; + x[14] = -x[3]; + + MAD_F_ML0(hi, lo, X[0], -MAD_F(0x0ffc19fd)); + MAD_F_MLA(hi, lo, X[2], -MAD_F(0x0f9ee890)); + MAD_F_MLA(hi, lo, X[3], -MAD_F(0x0f426cb5)); + MAD_F_MLA(hi, lo, X[5], -MAD_F(0x0e313245)); + MAD_F_MLA(hi, lo, X[6], -MAD_F(0x0d7e8807)); + MAD_F_MLA(hi, lo, X[8], -MAD_F(0x0bcbe352)); + MAD_F_MLA(hi, lo, X[9], -MAD_F(0x0acf37ad)); + MAD_F_MLA(hi, lo, X[11], -MAD_F(0x0898c779)); + MAD_F_MLA(hi, lo, X[12], -MAD_F(0x07635284)); + MAD_F_MLA(hi, lo, X[14], -MAD_F(0x04cfb0e2)); + MAD_F_MLA(hi, lo, X[15], -MAD_F(0x03768962)); + MAD_F_MLA(hi, lo, X[17], -MAD_F(0x00b2aa3e)); + + x[26] = x[27] = MAD_F_MLZ(hi, lo) + t5; +} +# endif + +/* + * NAME: III_imdct_l() + * DESCRIPTION: perform IMDCT and windowing for long blocks + */ +static +void III_imdct_l(mad_fixed_t const X[18], mad_fixed_t z[36], + unsigned int block_type) +{ + unsigned int i; + + /* IMDCT */ + + imdct36(X, z); + + /* windowing */ + + switch (block_type) { + case 0: /* normal window */ +# if defined(ASO_INTERLEAVE1) + { + register mad_fixed_t tmp1, tmp2; + + tmp1 = window_l[0]; + tmp2 = window_l[1]; + + for (i = 0; i < 34; i += 2) { + z[i + 0] = mad_f_mul(z[i + 0], tmp1); + tmp1 = window_l[i + 2]; + z[i + 1] = mad_f_mul(z[i + 1], tmp2); + tmp2 = window_l[i + 3]; + } + + z[34] = mad_f_mul(z[34], tmp1); + z[35] = mad_f_mul(z[35], tmp2); + } +# elif defined(ASO_INTERLEAVE2) + { + register mad_fixed_t tmp1, tmp2; + + tmp1 = z[0]; + tmp2 = window_l[0]; + + for (i = 0; i < 35; ++i) { + z[i] = mad_f_mul(tmp1, tmp2); + tmp1 = z[i + 1]; + tmp2 = window_l[i + 1]; + } + + z[35] = mad_f_mul(tmp1, tmp2); + } +# elif 1 + for (i = 0; i < 36; i += 4) { + z[i + 0] = mad_f_mul(z[i + 0], window_l[i + 0]); + z[i + 1] = mad_f_mul(z[i + 1], window_l[i + 1]); + z[i + 2] = mad_f_mul(z[i + 2], window_l[i + 2]); + z[i + 3] = mad_f_mul(z[i + 3], window_l[i + 3]); + } +# else + for (i = 0; i < 36; ++i) z[i] = mad_f_mul(z[i], window_l[i]); +# endif + break; + + case 1: /* start block */ + for (i = 0; i < 18; i += 3) { + z[i + 0] = mad_f_mul(z[i + 0], window_l[i + 0]); + z[i + 1] = mad_f_mul(z[i + 1], window_l[i + 1]); + z[i + 2] = mad_f_mul(z[i + 2], window_l[i + 2]); + } + /* (i = 18; i < 24; ++i) z[i] unchanged */ + for (i = 24; i < 30; ++i) z[i] = mad_f_mul(z[i], window_s[i - 18]); + for (i = 30; i < 36; ++i) z[i] = 0; + break; + + case 3: /* stop block */ + for (i = 0; i < 6; ++i) z[i] = 0; + for (i = 6; i < 12; ++i) z[i] = mad_f_mul(z[i], window_s[i - 6]); + /* (i = 12; i < 18; ++i) z[i] unchanged */ + for (i = 18; i < 36; i += 3) { + z[i + 0] = mad_f_mul(z[i + 0], window_l[i + 0]); + z[i + 1] = mad_f_mul(z[i + 1], window_l[i + 1]); + z[i + 2] = mad_f_mul(z[i + 2], window_l[i + 2]); + } + break; + } +} +# endif /* ASO_IMDCT */ + +/* + * NAME: III_imdct_s() + * DESCRIPTION: perform IMDCT and windowing for short blocks + */ +static +void III_imdct_s(mad_fixed_t const X[18], mad_fixed_t z[36]) +{ + mad_fixed_t y[36], *yptr; + mad_fixed_t const *wptr; + int w, i; + register mad_fixed64hi_t hi; + register mad_fixed64lo_t lo; + + /* IMDCT */ + + yptr = &y[0]; + + for (w = 0; w < 3; ++w) { + register mad_fixed_t const (*s)[6]; + + s = imdct_s; + + for (i = 0; i < 3; ++i) { + MAD_F_ML0(hi, lo, X[0], (*s)[0]); + MAD_F_MLA(hi, lo, X[1], (*s)[1]); + MAD_F_MLA(hi, lo, X[2], (*s)[2]); + MAD_F_MLA(hi, lo, X[3], (*s)[3]); + MAD_F_MLA(hi, lo, X[4], (*s)[4]); + MAD_F_MLA(hi, lo, X[5], (*s)[5]); + + yptr[i + 0] = MAD_F_MLZ(hi, lo); + yptr[5 - i] = -yptr[i + 0]; + + ++s; + + MAD_F_ML0(hi, lo, X[0], (*s)[0]); + MAD_F_MLA(hi, lo, X[1], (*s)[1]); + MAD_F_MLA(hi, lo, X[2], (*s)[2]); + MAD_F_MLA(hi, lo, X[3], (*s)[3]); + MAD_F_MLA(hi, lo, X[4], (*s)[4]); + MAD_F_MLA(hi, lo, X[5], (*s)[5]); + + yptr[ i + 6] = MAD_F_MLZ(hi, lo); + yptr[11 - i] = yptr[i + 6]; + + ++s; + } + + yptr += 12; + X += 6; + } + + /* windowing, overlapping and concatenation */ + + yptr = &y[0]; + wptr = &window_s[0]; + + for (i = 0; i < 6; ++i) { + z[i + 0] = 0; + z[i + 6] = mad_f_mul(yptr[ 0 + 0], wptr[0]); + + MAD_F_ML0(hi, lo, yptr[ 0 + 6], wptr[6]); + MAD_F_MLA(hi, lo, yptr[12 + 0], wptr[0]); + + z[i + 12] = MAD_F_MLZ(hi, lo); + + MAD_F_ML0(hi, lo, yptr[12 + 6], wptr[6]); + MAD_F_MLA(hi, lo, yptr[24 + 0], wptr[0]); + + z[i + 18] = MAD_F_MLZ(hi, lo); + + z[i + 24] = mad_f_mul(yptr[24 + 6], wptr[6]); + z[i + 30] = 0; + + ++yptr; + ++wptr; + } +} + +/* + * NAME: III_overlap() + * DESCRIPTION: perform overlap-add of windowed IMDCT outputs + */ +static +void III_overlap(mad_fixed_t const output[36], mad_fixed_t overlap[18], + mad_fixed_t sample[18][32], unsigned int sb) +{ + unsigned int i; + +# if defined(ASO_INTERLEAVE2) + { + register mad_fixed_t tmp1, tmp2; + + tmp1 = overlap[0]; + tmp2 = overlap[1]; + + for (i = 0; i < 16; i += 2) { + sample[i + 0][sb] = output[i + 0 + 0] + tmp1; + overlap[i + 0] = output[i + 0 + 18]; + tmp1 = overlap[i + 2]; + + sample[i + 1][sb] = output[i + 1 + 0] + tmp2; + overlap[i + 1] = output[i + 1 + 18]; + tmp2 = overlap[i + 3]; + } + + sample[16][sb] = output[16 + 0] + tmp1; + overlap[16] = output[16 + 18]; + sample[17][sb] = output[17 + 0] + tmp2; + overlap[17] = output[17 + 18]; + } +# elif 0 + for (i = 0; i < 18; i += 2) { + sample[i + 0][sb] = output[i + 0 + 0] + overlap[i + 0]; + overlap[i + 0] = output[i + 0 + 18]; + + sample[i + 1][sb] = output[i + 1 + 0] + overlap[i + 1]; + overlap[i + 1] = output[i + 1 + 18]; + } +# else + for (i = 0; i < 18; ++i) { + sample[i][sb] = output[i + 0] + overlap[i]; + overlap[i] = output[i + 18]; + } +# endif +} + +/* + * NAME: III_overlap_z() + * DESCRIPTION: perform "overlap-add" of zero IMDCT outputs + */ +static inline +void III_overlap_z(mad_fixed_t overlap[18], + mad_fixed_t sample[18][32], unsigned int sb) +{ + unsigned int i; + +# if defined(ASO_INTERLEAVE2) + { + register mad_fixed_t tmp1, tmp2; + + tmp1 = overlap[0]; + tmp2 = overlap[1]; + + for (i = 0; i < 16; i += 2) { + sample[i + 0][sb] = tmp1; + overlap[i + 0] = 0; + tmp1 = overlap[i + 2]; + + sample[i + 1][sb] = tmp2; + overlap[i + 1] = 0; + tmp2 = overlap[i + 3]; + } + + sample[16][sb] = tmp1; + overlap[16] = 0; + sample[17][sb] = tmp2; + overlap[17] = 0; + } +# else + for (i = 0; i < 18; ++i) { + sample[i][sb] = overlap[i]; + overlap[i] = 0; + } +# endif +} + +/* + * NAME: III_freqinver() + * DESCRIPTION: perform subband frequency inversion for odd sample lines + */ +static +void III_freqinver(mad_fixed_t sample[18][32], unsigned int sb) +{ + unsigned int i; + +# if 1 || defined(ASO_INTERLEAVE1) || defined(ASO_INTERLEAVE2) + { + register mad_fixed_t tmp1, tmp2; + + tmp1 = sample[1][sb]; + tmp2 = sample[3][sb]; + + for (i = 1; i < 13; i += 4) { + sample[i + 0][sb] = -tmp1; + tmp1 = sample[i + 4][sb]; + sample[i + 2][sb] = -tmp2; + tmp2 = sample[i + 6][sb]; + } + + sample[13][sb] = -tmp1; + tmp1 = sample[17][sb]; + sample[15][sb] = -tmp2; + sample[17][sb] = -tmp1; + } +# else + for (i = 1; i < 18; i += 2) + sample[i][sb] = -sample[i][sb]; +# endif +} + +/* + * NAME: III_decode() + * DESCRIPTION: decode frame main_data + */ +static +enum mad_error III_decode(struct mad_bitptr *ptr, struct mad_frame *frame, + struct sideinfo *si, unsigned int nch, unsigned int md_len) +{ + struct mad_header *header = &frame->header; + unsigned int sfreqi, ngr, gr; + int bits_left = md_len * CHAR_BIT; + + { + unsigned int sfreq; + + sfreq = header->samplerate; + if (header->flags & MAD_FLAG_MPEG_2_5_EXT) + sfreq *= 2; + + /* 48000 => 0, 44100 => 1, 32000 => 2, + 24000 => 3, 22050 => 4, 16000 => 5 */ + sfreqi = ((sfreq >> 7) & 0x000f) + + ((sfreq >> 15) & 0x0001) - 8; + + if (header->flags & MAD_FLAG_MPEG_2_5_EXT) + sfreqi += 3; + } + + /* scalefactors, Huffman decoding, requantization */ + + ngr = (header->flags & MAD_FLAG_LSF_EXT) ? 1 : 2; + + for (gr = 0; gr < ngr; ++gr) { + struct granule *granule = &si->gr[gr]; + unsigned char const *sfbwidth[2]; + mad_fixed_t xr[2][576]; + unsigned int ch; + enum mad_error error; + + for (ch = 0; ch < nch; ++ch) { + struct channel *channel = &granule->ch[ch]; + unsigned int part2_length; + unsigned int part3_length; + + sfbwidth[ch] = sfbwidth_table[sfreqi].l; + if (channel->block_type == 2) { + sfbwidth[ch] = (channel->flags & mixed_block_flag) ? + sfbwidth_table[sfreqi].m : sfbwidth_table[sfreqi].s; + } + + if (header->flags & MAD_FLAG_LSF_EXT) { + error = III_scalefactors_lsf(ptr, channel, + ch == 0 ? 0 : &si->gr[1].ch[1], + header->mode_extension, bits_left, &part2_length); + } + else { + error = III_scalefactors(ptr, channel, &si->gr[0].ch[ch], + gr == 0 ? 0 : si->scfsi[ch], bits_left, &part2_length); + } + if (error) + return error; + + bits_left -= part2_length; + + if (part2_length > channel->part2_3_length) + return MAD_ERROR_BADPART3LEN; + + part3_length = channel->part2_3_length - part2_length; + if (part3_length > bits_left) + return MAD_ERROR_BADPART3LEN; + + error = III_huffdecode(ptr, xr[ch], channel, sfbwidth[ch], part3_length); + if (error) + return error; + bits_left -= part3_length; + } + + /* joint stereo processing */ + + if (header->mode == MAD_MODE_JOINT_STEREO && header->mode_extension) { + error = III_stereo(xr, granule, header, sfbwidth[0]); + if (error) + return error; + } + + /* reordering, alias reduction, IMDCT, overlap-add, frequency inversion */ + + for (ch = 0; ch < nch; ++ch) { + struct channel const *channel = &granule->ch[ch]; + mad_fixed_t (*sample)[32] = &frame->sbsample[ch][18 * gr]; + unsigned int sb, l, i, sblimit; + mad_fixed_t output[36]; + + if (channel->block_type == 2) { + III_reorder(xr[ch], channel, sfbwidth[ch]); + +# if !defined(OPT_STRICT) + /* + * According to ISO/IEC 11172-3, "Alias reduction is not applied for + * granules with block_type == 2 (short block)." However, other + * sources suggest alias reduction should indeed be performed on the + * lower two subbands of mixed blocks. Most other implementations do + * this, so by default we will too. + */ + if (channel->flags & mixed_block_flag) + III_aliasreduce(xr[ch], 36); +# endif + } + else + III_aliasreduce(xr[ch], 576); + + l = 0; + + /* subbands 0-1 */ + + if (channel->block_type != 2 || (channel->flags & mixed_block_flag)) { + unsigned int block_type; + + block_type = channel->block_type; + if (channel->flags & mixed_block_flag) + block_type = 0; + + /* long blocks */ + for (sb = 0; sb < 2; ++sb, l += 18) { + III_imdct_l(&xr[ch][l], output, block_type); + III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + } + } + else { + /* short blocks */ + for (sb = 0; sb < 2; ++sb, l += 18) { + III_imdct_s(&xr[ch][l], output); + III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + } + } + + III_freqinver(sample, 1); + + /* (nonzero) subbands 2-31 */ + + i = 576; + while (i > 36 && xr[ch][i - 1] == 0) + --i; + + sblimit = 32 - (576 - i) / 18; + + if (channel->block_type != 2) { + /* long blocks */ + for (sb = 2; sb < sblimit; ++sb, l += 18) { + III_imdct_l(&xr[ch][l], output, channel->block_type); + III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + + if (sb & 1) + III_freqinver(sample, sb); + } + } + else { + /* short blocks */ + for (sb = 2; sb < sblimit; ++sb, l += 18) { + III_imdct_s(&xr[ch][l], output); + III_overlap(output, (*frame->overlap)[ch][sb], sample, sb); + + if (sb & 1) + III_freqinver(sample, sb); + } + } + + /* remaining (zero) subbands */ + + for (sb = sblimit; sb < 32; ++sb) { + III_overlap_z((*frame->overlap)[ch][sb], sample, sb); + + if (sb & 1) + III_freqinver(sample, sb); + } + } + } + + return MAD_ERROR_NONE; +} + +/* + * NAME: layer->III() + * DESCRIPTION: decode a single Layer III frame + */ +int mad_layer_III(struct mad_stream *stream, struct mad_frame *frame) +{ + struct mad_header *header = &frame->header; + unsigned int nch, priv_bitlen, next_md_begin = 0; + unsigned int si_len, data_bitlen, md_len; + unsigned int frame_space, frame_used, frame_free; + struct mad_bitptr ptr, bufend_ptr; + struct sideinfo si; + enum mad_error error; + int result = 0; + + mad_bit_init(&bufend_ptr, stream->bufend); + + /* allocate Layer III dynamic structures */ + + if (stream->main_data == 0) { + stream->main_data = malloc(MAD_BUFFER_MDLEN); + if (stream->main_data == 0) { + stream->error = MAD_ERROR_NOMEM; + return -1; + } + } + + if (frame->overlap == 0) { + frame->overlap = calloc(2 * 32 * 18, sizeof(mad_fixed_t)); + if (frame->overlap == 0) { + stream->error = MAD_ERROR_NOMEM; + return -1; + } + } + + nch = MAD_NCHANNELS(header); + si_len = (header->flags & MAD_FLAG_LSF_EXT) ? + (nch == 1 ? 9 : 17) : (nch == 1 ? 17 : 32); + + /* check frame sanity */ + + if (stream->next_frame - mad_bit_nextbyte(&stream->ptr) < + (signed int) si_len) { + stream->error = MAD_ERROR_BADFRAMELEN; + stream->md_len = 0; + return -1; + } + + /* check CRC word */ + + if (header->flags & MAD_FLAG_PROTECTION) { + header->crc_check = + mad_bit_crc(stream->ptr, si_len * CHAR_BIT, header->crc_check); + + if (header->crc_check != header->crc_target && + !(frame->options & MAD_OPTION_IGNORECRC)) { + stream->error = MAD_ERROR_BADCRC; + result = -1; + } + } + + /* decode frame side information */ + + error = III_sideinfo(&stream->ptr, nch, header->flags & MAD_FLAG_LSF_EXT, + &si, &data_bitlen, &priv_bitlen); + if (error && result == 0) { + stream->error = error; + result = -1; + } + + header->flags |= priv_bitlen; + header->private_bits |= si.private_bits; + + /* find main_data of next frame */ + + { + struct mad_bitptr peek; + unsigned long header; + + mad_bit_init(&peek, stream->next_frame); + if (mad_bit_length(&peek, &bufend_ptr) >= 57) { + header = mad_bit_read(&peek, 32); + if ((header & 0xffe60000L) /* syncword | layer */ == 0xffe20000L) { + if (!(header & 0x00010000L)) /* protection_bit */ + mad_bit_skip(&peek, 16); /* crc_check */ + + next_md_begin = + mad_bit_read(&peek, (header & 0x00080000L) /* ID */ ? 9 : 8); + } + } + + mad_bit_finish(&peek); + } + + /* find main_data of this frame */ + + frame_space = stream->next_frame - mad_bit_nextbyte(&stream->ptr); + + if (next_md_begin > si.main_data_begin + frame_space) + next_md_begin = 0; + + md_len = si.main_data_begin + frame_space - next_md_begin; + if (md_len + MAD_BUFFER_GUARD > MAD_BUFFER_MDLEN) { + stream->error = MAD_ERROR_LOSTSYNC; + stream->sync = 0; + return -1; + } + + frame_used = 0; + + if (si.main_data_begin == 0) { + ptr = stream->ptr; + stream->md_len = 0; + + frame_used = md_len; + } + else { + if (si.main_data_begin > stream->md_len) { + if (result == 0) { + stream->error = MAD_ERROR_BADDATAPTR; + result = -1; + } + } + else { + memmove(stream->main_data, + *stream->main_data + stream->md_len - si.main_data_begin, + si.main_data_begin); + stream->md_len = si.main_data_begin; + mad_bit_init(&ptr, *stream->main_data); + + if (md_len > si.main_data_begin) { + assert(stream->md_len + md_len - + si.main_data_begin <= MAD_BUFFER_MDLEN); + + memcpy(*stream->main_data + stream->md_len, + mad_bit_nextbyte(&stream->ptr), + frame_used = md_len - si.main_data_begin); + stream->md_len += frame_used; + } + } + } + + frame_free = frame_space - frame_used; + + /* decode main_data */ + + if (result == 0) { + error = III_decode(&ptr, frame, &si, nch, md_len); + if (error) { + stream->error = error; + result = -1; + } + + /* designate ancillary bits */ + + stream->anc_ptr = ptr; + stream->anc_bitlen = md_len * CHAR_BIT - data_bitlen; + } + +# if 0 && defined(DEBUG) + fprintf(stderr, + "main_data_begin:%u, md_len:%u, frame_free:%u, " + "data_bitlen:%u, anc_bitlen: %u\n", + si.main_data_begin, md_len, frame_free, + data_bitlen, stream->anc_bitlen); +# endif + + /* preload main_data buffer with up to 511 bytes for next frame(s) */ + + if (frame_free >= next_md_begin) { + memcpy(*stream->main_data, + stream->next_frame - next_md_begin, next_md_begin); + stream->md_len = next_md_begin; + } + else { + if (md_len < si.main_data_begin) { + unsigned int extra; + + extra = si.main_data_begin - md_len; + if (extra + frame_free > next_md_begin) + extra = next_md_begin - frame_free; + + if (extra < stream->md_len) { + memmove(*stream->main_data, + *stream->main_data + stream->md_len - extra, extra); + stream->md_len = extra; + } + } + else + stream->md_len = 0; + + memcpy(*stream->main_data + stream->md_len, + stream->next_frame - frame_free, frame_free); + stream->md_len += frame_free; + } + + return result; +} diff --git a/code/libmad/layer3.h b/code/libmad/layer3.h new file mode 100644 index 00000000..618951b0 --- /dev/null +++ b/code/libmad/layer3.h @@ -0,0 +1,29 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: layer3.h,v 1.10 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBMAD_LAYER3_H +# define LIBMAD_LAYER3_H + +# include "mad.h" + +int mad_layer_III(struct mad_stream *, struct mad_frame *); + +# endif diff --git a/code/libmad/mad.h.in b/code/libmad/mad.h.in new file mode 100644 index 00000000..0e790d3e --- /dev/null +++ b/code/libmad/mad.h.in @@ -0,0 +1,956 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * If you would like to negotiate alternate licensing terms, you may do + * so by contacting: Underbit Technologies, Inc. + */ + +# ifdef __cplusplus +extern "C" { +# endif + +#cmakedefine FPM_INTEL +#cmakedefine FPM_ARM +#cmakedefine FPM_MIPS +#cmakedefine FPM_SPARC +#cmakedefine FPM_PPC +#cmakedefine FPM_64BIT +#cmakedefine FPM_DEFAULT + +# define SIZEOF_INT @SIZEOF_INT@ + +/* Id: version.h,v 1.26 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_VERSION_H +# define LIBMAD_VERSION_H + +# define MAD_VERSION_MAJOR @CMAKE_PROJECT_VERSION_MAJOR@ +# define MAD_VERSION_MINOR @CMAKE_PROJECT_VERSION_MINOR@ +# define MAD_VERSION_PATCH @CMAKE_PROJECT_VERSION_PATCH@ +# define MAD_VERSION_EXTRA "" + +# define MAD_VERSION_STRINGIZE(str) #str +# define MAD_VERSION_STRING(num) MAD_VERSION_STRINGIZE(num) + +# define MAD_VERSION MAD_VERSION_STRING(MAD_VERSION_MAJOR) "." \ + MAD_VERSION_STRING(MAD_VERSION_MINOR) "." \ + MAD_VERSION_STRING(MAD_VERSION_PATCH) \ + MAD_VERSION_EXTRA + +# define MAD_PUBLISHYEAR "2000-2004" +# define MAD_AUTHOR "Underbit Technologies, Inc." +# define MAD_EMAIL "info@underbit.com" + +extern char const mad_version[]; +extern char const mad_copyright[]; +extern char const mad_author[]; +extern char const mad_build[]; + +# endif + +/* Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp */ + +# ifndef LIBMAD_FIXED_H +# define LIBMAD_FIXED_H + +# include + +# if SIZEOF_INT >= 4 +typedef signed int mad_fixed_t; +typedef signed int mad_fixed64hi_t; +typedef unsigned int mad_fixed64lo_t; +# else +typedef signed long mad_fixed_t; +typedef signed long mad_fixed64hi_t; +typedef unsigned long mad_fixed64lo_t; +# endif + +typedef int64_t mad_fixed64_t; + +# if defined(FPM_FLOAT) +typedef double mad_sample_t; +# else +typedef mad_fixed_t mad_sample_t; +# endif + +/* + * Fixed-point format: 0xABBBBBBB + * A == whole part (sign + 3 bits) + * B == fractional part (28 bits) + * + * Values are signed two's complement, so the effective range is: + * 0x80000000 to 0x7fffffff + * -8.0 to +7.9999999962747097015380859375 + * + * The smallest representable value is: + * 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9) + * + * 28 bits of fractional accuracy represent about + * 8.6 digits of decimal accuracy. + * + * Fixed-point numbers can be added or subtracted as normal + * integers, but multiplication requires shifting the 64-bit result + * from 56 fractional bits back to 28 (and rounding.) + * + * Changing the definition of MAD_F_FRACBITS is only partially + * supported, and must be done with care. + */ + +# define MAD_F_FRACBITS 28 + +# if MAD_F_FRACBITS == 28 +# define MAD_F(x) ((mad_fixed_t) (x##L)) +# else +# if MAD_F_FRACBITS < 28 +# warning "MAD_F_FRACBITS < 28" +# define MAD_F(x) ((mad_fixed_t) \ + (((x##L) + \ + (1L << (28 - MAD_F_FRACBITS - 1))) >> \ + (28 - MAD_F_FRACBITS))) +# elif MAD_F_FRACBITS > 28 +# error "MAD_F_FRACBITS > 28 not currently supported" +# define MAD_F(x) ((mad_fixed_t) \ + ((x##L) << (MAD_F_FRACBITS - 28))) +# endif +# endif + +# define MAD_F_MIN ((mad_fixed_t) -0x80000000L) +# define MAD_F_MAX ((mad_fixed_t) +0x7fffffffL) + +# define MAD_F_ONE MAD_F(0x10000000) + +# define mad_f_tofixed(x) ((mad_fixed_t) \ + ((x) * (double) (1L << MAD_F_FRACBITS) + 0.5)) +# define mad_f_todouble(x) ((double) \ + ((x) / (double) (1L << MAD_F_FRACBITS))) + +# define mad_f_intpart(x) ((x) >> MAD_F_FRACBITS) +# define mad_f_fracpart(x) ((x) & ((1L << MAD_F_FRACBITS) - 1)) + /* (x should be positive) */ + +# define mad_f_fromint(x) ((x) << MAD_F_FRACBITS) + +# define mad_f_add(x, y) ((x) + (y)) +# define mad_f_sub(x, y) ((x) - (y)) + +# if defined(FPM_FLOAT) +# error "FPM_FLOAT not yet supported" + +# undef MAD_F +# define MAD_F(x) mad_f_todouble(x) + +# define mad_f_mul(x, y) ((x) * (y)) +# define mad_f_scale64 + +# undef ASO_ZEROCHECK + +# elif defined(FPM_64BIT) + +/* + * This version should be the most accurate if 64-bit types are supported by + * the compiler, although it may not be the most efficient. + */ +# if defined(OPT_ACCURACY) +# define mad_f_mul(x, y) \ + ((mad_fixed_t) \ + ((((mad_fixed64_t) (x) * (y)) + \ + (1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS)) +# else +# define mad_f_mul(x, y) \ + ((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS)) +# endif + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- Intel --------------------------------------------------------------- */ + +# elif defined(FPM_INTEL) + +# if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4035) /* no return value */ +static __forceinline +mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y) +{ + enum { + fracbits = MAD_F_FRACBITS + }; + + __asm { + mov eax, x + imul y + shrd eax, edx, fracbits + } + + /* implicit return of eax */ +} +# pragma warning(pop) + +# define mad_f_mul mad_f_mul_inline +# define mad_f_scale64 +# else +/* + * This Intel version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("imull %3" \ + : "=a" (lo), "=d" (hi) \ + : "%a" (x), "rm" (y) \ + : "cc") + +# if defined(OPT_ACCURACY) +/* + * This gives best accuracy but is not very fast. + */ +# define MAD_F_MLA(hi, lo, x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + asm ("addl %2,%0\n\t" \ + "adcl %3,%1" \ + : "=rm" (lo), "=rm" (hi) \ + : "r" (__lo), "r" (__hi), "0" (lo), "1" (hi) \ + : "cc"); \ + }) +# endif /* OPT_ACCURACY */ + +# if defined(OPT_ACCURACY) +/* + * Surprisingly, this is faster than SHRD followed by ADC. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed64hi_t __hi_; \ + mad_fixed64lo_t __lo_; \ + mad_fixed_t __result; \ + asm ("addl %4,%2\n\t" \ + "adcl %5,%3" \ + : "=rm" (__lo_), "=rm" (__hi_) \ + : "0" (lo), "1" (hi), \ + "ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0) \ + : "cc"); \ + asm ("shrdl %3,%2,%1" \ + : "=rm" (__result) \ + : "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# elif defined(OPT_INTEL) +/* + * Alternate Intel scaling that may or may not perform better. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrl %3,%1\n\t" \ + "shll %4,%2\n\t" \ + "orl %2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), \ + "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrdl %3,%2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# endif /* OPT_ACCURACY */ + +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* --- ARM ----------------------------------------------------------------- */ + +# elif defined(FPM_ARM) + +/* + * This ARM V4 version is as accurate as FPM_64BIT but much faster. The + * least significant bit is properly rounded at no CPU cycle cost! + */ +# if 1 +/* + * This is faster than the default implementation via MAD_F_MLX() and + * mad_f_scale64(). + */ +# define mad_f_mul(x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + mad_fixed_t __result; \ + asm ("smull %0, %1, %3, %4\n\t" \ + "movs %0, %0, lsr %5\n\t" \ + "adc %2, %0, %1, lsl %6" \ + : "=&r" (__lo), "=&r" (__hi), "=r" (__result) \ + : "%r" (x), "r" (y), \ + "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# endif + +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("smull %0, %1, %2, %3" \ + : "=&r" (lo), "=&r" (hi) \ + : "%r" (x), "r" (y)) + +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("smlal %0, %1, %2, %3" \ + : "+r" (lo), "+r" (hi) \ + : "%r" (x), "r" (y)) + +#ifdef __thumb__ +/* In Thumb-2, the RSB-immediate instruction is only allowed with a zero + operand. If needed this code can also support Thumb-1 + (simply append "s" to the end of the second two instructions). */ +# define MAD_F_MLN(hi, lo) \ + asm ("rsbs %0, %0, #0\n\t" \ + "sbc %1, %1, %1\n\t" \ + "sub %1, %1, %2" \ + : "+&r" (lo), "=&r" (hi) \ + : "r" (hi) \ + : "cc") +#else /* ! __thumb__ */ +# define MAD_F_MLN(hi, lo) \ + asm ("rsbs %0, %2, #0\n\t" \ + "rsc %1, %3, #0" \ + : "=&r" (lo), "=r" (hi) \ + : "0" (lo), "1" (hi) \ + : "cc") +#endif /* __thumb__ */ + +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("movs %0, %1, lsr %3\n\t" \ + "adc %0, %0, %2, lsl %4" \ + : "=&r" (__result) \ + : "r" (lo), "r" (hi), \ + "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- MIPS ---------------------------------------------------------------- */ + +# elif defined(FPM_MIPS) + +/* + * This MIPS version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ + typedef unsigned int u64_di_t __attribute__ ((mode (DI))); +# define MAD_F_MLX(hi, lo, x, y) \ + do { \ + u64_di_t __ll = (u64_di_t) (x) * (y); \ + hi = __ll >> 32; \ + lo = __ll; \ + } while (0) + +# if defined(OPT_SPEED) +# define mad_f_scale64(hi, lo) \ + ((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS))) +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* --- SPARC --------------------------------------------------------------- */ + +# elif defined(FPM_SPARC) + +/* + * This SPARC V8 version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("smul %2, %3, %0\n\t" \ + "rd %%y, %1" \ + : "=r" (lo), "=r" (hi) \ + : "%r" (x), "rI" (y)) + +/* --- PowerPC ------------------------------------------------------------- */ + +# elif defined(FPM_PPC) + +/* + * This PowerPC version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + do { \ + asm ("mullw %0,%1,%2" \ + : "=r" (lo) \ + : "%r" (x), "r" (y)); \ + asm ("mulhw %0,%1,%2" \ + : "=r" (hi) \ + : "%r" (x), "r" (y)); \ + } \ + while (0) + +# if defined(OPT_ACCURACY) +/* + * This gives best accuracy but is not very fast. + */ +# define MAD_F_MLA(hi, lo, x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + asm ("addc %0,%2,%3\n\t" \ + "adde %1,%4,%5" \ + : "=r" (lo), "=r" (hi) \ + : "0" (lo), "r" (__lo), \ + "1" (hi), "r" (__hi) \ + : "xer"); \ + }) +# endif + +# if defined(OPT_ACCURACY) +/* + * This is slower than the truncating version below it. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result, __round; \ + asm ("rotrwi %0,%1,%2" \ + : "=r" (__result) \ + : "r" (lo), "i" (MAD_F_SCALEBITS)); \ + asm ("extrwi %0,%1,1,0" \ + : "=r" (__round) \ + : "r" (__result)); \ + asm ("insrwi %0,%1,%2,0" \ + : "+r" (__result) \ + : "r" (hi), "i" (MAD_F_SCALEBITS)); \ + asm ("add %0,%1,%2" \ + : "=r" (__result) \ + : "%r" (__result), "r" (__round)); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("rotrwi %0,%1,%2" \ + : "=r" (__result) \ + : "r" (lo), "i" (MAD_F_SCALEBITS)); \ + asm ("insrwi %0,%1,%2,0" \ + : "+r" (__result) \ + : "r" (hi), "i" (MAD_F_SCALEBITS)); \ + __result; \ + }) +# endif + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- Default ------------------------------------------------------------- */ + +# elif defined(FPM_DEFAULT) + +/* + * This version is the most portable but it loses significant accuracy. + * Furthermore, accuracy is biased against the second argument, so care + * should be taken when ordering operands. + * + * The scale factors are constant as this is not used with SSO. + * + * Pre-rounding is required to stay within the limits of compliance. + */ +# if defined(OPT_SPEED) +# define mad_f_mul(x, y) (((x) >> 12) * ((y) >> 16)) +# else +# define mad_f_mul(x, y) ((((x) + (1L << 11)) >> 12) * \ + (((y) + (1L << 15)) >> 16)) +# endif + +/* ------------------------------------------------------------------------- */ + +# else +# error "no FPM selected" +# endif + +/* default implementations */ + +# if !defined(mad_f_mul) +# define mad_f_mul(x, y) \ + ({ register mad_fixed64hi_t __hi; \ + register mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + mad_f_scale64(__hi, __lo); \ + }) +# endif + +# if !defined(MAD_F_MLA) +# define MAD_F_ML0(hi, lo, x, y) ((lo) = mad_f_mul((x), (y))) +# define MAD_F_MLA(hi, lo, x, y) ((lo) += mad_f_mul((x), (y))) +# define MAD_F_MLN(hi, lo) ((lo) = -(lo)) +# define MAD_F_MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo)) +# endif + +# if !defined(MAD_F_ML0) +# define MAD_F_ML0(hi, lo, x, y) MAD_F_MLX((hi), (lo), (x), (y)) +# endif + +# if !defined(MAD_F_MLN) +# define MAD_F_MLN(hi, lo) ((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi)) +# endif + +# if !defined(MAD_F_MLZ) +# define MAD_F_MLZ(hi, lo) mad_f_scale64((hi), (lo)) +# endif + +# if !defined(mad_f_scale64) +# if defined(OPT_ACCURACY) +# define mad_f_scale64(hi, lo) \ + ((((mad_fixed_t) \ + (((hi) << (32 - (MAD_F_SCALEBITS - 1))) | \ + ((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1) +# else +# define mad_f_scale64(hi, lo) \ + ((mad_fixed_t) \ + (((hi) << (32 - MAD_F_SCALEBITS)) | \ + ((lo) >> MAD_F_SCALEBITS))) +# endif +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* C routines */ + +mad_fixed_t mad_f_abs(mad_fixed_t); +mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t); + +# endif + +/* Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_BIT_H +# define LIBMAD_BIT_H + +struct mad_bitptr { + unsigned char const *byte; + unsigned short cache; + unsigned short left; +}; + +void mad_bit_init(struct mad_bitptr *, unsigned char const *); + +# define mad_bit_finish(bitptr) /* nothing */ + +unsigned int mad_bit_length(struct mad_bitptr const *, + struct mad_bitptr const *); + +# define mad_bit_bitsleft(bitptr) ((bitptr)->left) +unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *); + +void mad_bit_skip(struct mad_bitptr *, unsigned int); +unsigned long mad_bit_read(struct mad_bitptr *, unsigned int); +void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long); + +unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short); + +# endif + +/* Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_TIMER_H +# define LIBMAD_TIMER_H + +typedef struct { + signed long seconds; /* whole seconds */ + unsigned long fraction; /* 1/MAD_TIMER_RESOLUTION seconds */ +} mad_timer_t; + +extern mad_timer_t const mad_timer_zero; + +# define MAD_TIMER_RESOLUTION 352800000UL + +enum mad_units { + MAD_UNITS_HOURS = -2, + MAD_UNITS_MINUTES = -1, + MAD_UNITS_SECONDS = 0, + + /* metric units */ + + MAD_UNITS_DECISECONDS = 10, + MAD_UNITS_CENTISECONDS = 100, + MAD_UNITS_MILLISECONDS = 1000, + + /* audio sample units */ + + MAD_UNITS_8000_HZ = 8000, + MAD_UNITS_11025_HZ = 11025, + MAD_UNITS_12000_HZ = 12000, + + MAD_UNITS_16000_HZ = 16000, + MAD_UNITS_22050_HZ = 22050, + MAD_UNITS_24000_HZ = 24000, + + MAD_UNITS_32000_HZ = 32000, + MAD_UNITS_44100_HZ = 44100, + MAD_UNITS_48000_HZ = 48000, + + /* video frame/field units */ + + MAD_UNITS_24_FPS = 24, + MAD_UNITS_25_FPS = 25, + MAD_UNITS_30_FPS = 30, + MAD_UNITS_48_FPS = 48, + MAD_UNITS_50_FPS = 50, + MAD_UNITS_60_FPS = 60, + + /* CD audio frames */ + + MAD_UNITS_75_FPS = 75, + + /* video drop-frame units */ + + MAD_UNITS_23_976_FPS = -24, + MAD_UNITS_24_975_FPS = -25, + MAD_UNITS_29_97_FPS = -30, + MAD_UNITS_47_952_FPS = -48, + MAD_UNITS_49_95_FPS = -50, + MAD_UNITS_59_94_FPS = -60 +}; + +# define mad_timer_reset(timer) ((void) (*(timer) = mad_timer_zero)) + +int mad_timer_compare(mad_timer_t, mad_timer_t); + +# define mad_timer_sign(timer) mad_timer_compare((timer), mad_timer_zero) + +void mad_timer_negate(mad_timer_t *); +mad_timer_t mad_timer_abs(mad_timer_t); + +void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long); +void mad_timer_add(mad_timer_t *, mad_timer_t); +void mad_timer_multiply(mad_timer_t *, signed long); + +signed long mad_timer_count(mad_timer_t, enum mad_units); +unsigned long mad_timer_fraction(mad_timer_t, unsigned long); +void mad_timer_string(mad_timer_t, char *, char const *, + enum mad_units, enum mad_units, unsigned long); + +# endif + +/* Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp */ + +# ifndef LIBMAD_STREAM_H +# define LIBMAD_STREAM_H + + +# define MAD_BUFFER_GUARD 8 +# define MAD_BUFFER_MDLEN (511 + 2048 + MAD_BUFFER_GUARD) + +enum mad_error { + MAD_ERROR_NONE = 0x0000, /* no error */ + + MAD_ERROR_BUFLEN = 0x0001, /* input buffer too small (or EOF) */ + MAD_ERROR_BUFPTR = 0x0002, /* invalid (null) buffer pointer */ + + MAD_ERROR_NOMEM = 0x0031, /* not enough memory */ + + MAD_ERROR_LOSTSYNC = 0x0101, /* lost synchronization */ + MAD_ERROR_BADLAYER = 0x0102, /* reserved header layer value */ + MAD_ERROR_BADBITRATE = 0x0103, /* forbidden bitrate value */ + MAD_ERROR_BADSAMPLERATE = 0x0104, /* reserved sample frequency value */ + MAD_ERROR_BADEMPHASIS = 0x0105, /* reserved emphasis value */ + + MAD_ERROR_BADCRC = 0x0201, /* CRC check failed */ + MAD_ERROR_BADBITALLOC = 0x0211, /* forbidden bit allocation value */ + MAD_ERROR_BADSCALEFACTOR = 0x0221, /* bad scalefactor index */ + MAD_ERROR_BADMODE = 0x0222, /* bad bitrate/mode combination */ + MAD_ERROR_BADFRAMELEN = 0x0231, /* bad frame length */ + MAD_ERROR_BADBIGVALUES = 0x0232, /* bad big_values count */ + MAD_ERROR_BADBLOCKTYPE = 0x0233, /* reserved block_type */ + MAD_ERROR_BADSCFSI = 0x0234, /* bad scalefactor selection info */ + MAD_ERROR_BADDATAPTR = 0x0235, /* bad main_data_begin pointer */ + MAD_ERROR_BADPART3LEN = 0x0236, /* bad audio data length */ + MAD_ERROR_BADHUFFTABLE = 0x0237, /* bad Huffman table select */ + MAD_ERROR_BADHUFFDATA = 0x0238, /* Huffman data overrun */ + MAD_ERROR_BADSTEREO = 0x0239 /* incompatible block_type for JS */ +}; + +# define MAD_RECOVERABLE(error) ((error) & 0xff00) + +struct mad_stream { + unsigned char const *buffer; /* input bitstream buffer */ + unsigned char const *bufend; /* end of buffer */ + unsigned long skiplen; /* bytes to skip before next frame */ + + int sync; /* stream sync found */ + unsigned long freerate; /* free bitrate (fixed) */ + + unsigned char const *this_frame; /* start of current frame */ + unsigned char const *next_frame; /* start of next frame */ + struct mad_bitptr ptr; /* current processing bit pointer */ + + struct mad_bitptr anc_ptr; /* ancillary bits pointer */ + unsigned int anc_bitlen; /* number of ancillary bits */ + + unsigned char (*main_data)[MAD_BUFFER_MDLEN]; + /* Layer III main_data() */ + unsigned int md_len; /* bytes in main_data */ + + int options; /* decoding options (see below) */ + enum mad_error error; /* error code (see above) */ +}; + +enum { + MAD_OPTION_IGNORECRC = 0x0001, /* ignore CRC errors */ + MAD_OPTION_HALFSAMPLERATE = 0x0002 /* generate PCM at 1/2 sample rate */ +# if 0 /* not yet implemented */ + MAD_OPTION_LEFTCHANNEL = 0x0010, /* decode left channel only */ + MAD_OPTION_RIGHTCHANNEL = 0x0020, /* decode right channel only */ + MAD_OPTION_SINGLECHANNEL = 0x0030 /* combine channels */ +# endif +}; + +void mad_stream_init(struct mad_stream *); +void mad_stream_finish(struct mad_stream *); + +# define mad_stream_options(stream, opts) \ + ((void) ((stream)->options = (opts))) + +void mad_stream_buffer(struct mad_stream *, + unsigned char const *, unsigned long); +void mad_stream_skip(struct mad_stream *, unsigned long); + +int mad_stream_sync(struct mad_stream *); + +char const *mad_stream_errorstr(struct mad_stream const *); + +# endif + +/* Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_FRAME_H +# define LIBMAD_FRAME_H + + +enum mad_layer { + MAD_LAYER_I = 1, /* Layer I */ + MAD_LAYER_II = 2, /* Layer II */ + MAD_LAYER_III = 3 /* Layer III */ +}; + +enum mad_mode { + MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */ + MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */ + MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */ + MAD_MODE_STEREO = 3 /* normal LR stereo */ +}; + +enum mad_emphasis { + MAD_EMPHASIS_NONE = 0, /* no emphasis */ + MAD_EMPHASIS_50_15_US = 1, /* 50/15 microseconds emphasis */ + MAD_EMPHASIS_CCITT_J_17 = 3, /* CCITT J.17 emphasis */ + MAD_EMPHASIS_RESERVED = 2 /* unknown emphasis */ +}; + +struct mad_header { + enum mad_layer layer; /* audio layer (1, 2, or 3) */ + enum mad_mode mode; /* channel mode (see above) */ + int mode_extension; /* additional mode info */ + enum mad_emphasis emphasis; /* de-emphasis to use (see above) */ + + unsigned long bitrate; /* stream bitrate (bps) */ + unsigned int samplerate; /* sampling frequency (Hz) */ + + unsigned short crc_check; /* frame CRC accumulator */ + unsigned short crc_target; /* final target CRC checksum */ + + int flags; /* flags (see below) */ + int private_bits; /* private bits (see below) */ + + mad_timer_t duration; /* audio playing time of frame */ +}; + +struct mad_frame { + struct mad_header header; /* MPEG audio header */ + + int options; /* decoding options (from stream) */ + + mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */ + mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */ +}; + +# define MAD_NCHANNELS(header) ((header)->mode ? 2 : 1) +# define MAD_NSBSAMPLES(header) \ + ((header)->layer == MAD_LAYER_I ? 12 : \ + (((header)->layer == MAD_LAYER_III && \ + ((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36)) + +enum { + MAD_FLAG_NPRIVATE_III = 0x0007, /* number of Layer III private bits */ + MAD_FLAG_INCOMPLETE = 0x0008, /* header but not data is decoded */ + + MAD_FLAG_PROTECTION = 0x0010, /* frame has CRC protection */ + MAD_FLAG_COPYRIGHT = 0x0020, /* frame is copyright */ + MAD_FLAG_ORIGINAL = 0x0040, /* frame is original (else copy) */ + MAD_FLAG_PADDING = 0x0080, /* frame has additional slot */ + + MAD_FLAG_I_STEREO = 0x0100, /* uses intensity joint stereo */ + MAD_FLAG_MS_STEREO = 0x0200, /* uses middle/side joint stereo */ + MAD_FLAG_FREEFORMAT = 0x0400, /* uses free format bitrate */ + + MAD_FLAG_LSF_EXT = 0x1000, /* lower sampling freq. extension */ + MAD_FLAG_MC_EXT = 0x2000, /* multichannel audio extension */ + MAD_FLAG_MPEG_2_5_EXT = 0x4000 /* MPEG 2.5 (unofficial) extension */ +}; + +enum { + MAD_PRIVATE_HEADER = 0x0100, /* header private bit */ + MAD_PRIVATE_III = 0x001f /* Layer III private bits (up to 5) */ +}; + +void mad_header_init(struct mad_header *); + +# define mad_header_finish(header) /* nothing */ + +int mad_header_decode(struct mad_header *, struct mad_stream *); + +void mad_frame_init(struct mad_frame *); +void mad_frame_finish(struct mad_frame *); + +int mad_frame_decode(struct mad_frame *, struct mad_stream *); + +void mad_frame_mute(struct mad_frame *); + +# endif + +/* Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_SYNTH_H +# define LIBMAD_SYNTH_H + + +struct mad_pcm { + unsigned int samplerate; /* sampling frequency (Hz) */ + unsigned short channels; /* number of channels */ + unsigned short length; /* number of samples per channel */ + mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ +}; + +struct mad_synth { + mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */ + /* [ch][eo][peo][s][v] */ + + unsigned int phase; /* current processing phase */ + + struct mad_pcm pcm; /* PCM output */ +}; + +/* single channel PCM selector */ +enum { + MAD_PCM_CHANNEL_SINGLE = 0 +}; + +/* dual channel PCM selector */ +enum { + MAD_PCM_CHANNEL_DUAL_1 = 0, + MAD_PCM_CHANNEL_DUAL_2 = 1 +}; + +/* stereo PCM selector */ +enum { + MAD_PCM_CHANNEL_STEREO_LEFT = 0, + MAD_PCM_CHANNEL_STEREO_RIGHT = 1 +}; + +void mad_synth_init(struct mad_synth *); + +# define mad_synth_finish(synth) /* nothing */ + +void mad_synth_mute(struct mad_synth *); + +void mad_synth_frame(struct mad_synth *, struct mad_frame const *); + +# endif + +/* Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_DECODER_H +# define LIBMAD_DECODER_H + + +enum mad_decoder_mode { + MAD_DECODER_MODE_SYNC = 0, + MAD_DECODER_MODE_ASYNC +}; + +enum mad_flow { + MAD_FLOW_CONTINUE = 0x0000, /* continue normally */ + MAD_FLOW_STOP = 0x0010, /* stop decoding normally */ + MAD_FLOW_BREAK = 0x0011, /* stop decoding and signal an error */ + MAD_FLOW_IGNORE = 0x0020 /* ignore the current frame */ +}; + +struct mad_decoder { + enum mad_decoder_mode mode; + + int options; + + struct { + long pid; + int in; + int out; + } async; + + struct { + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + } *sync; + + void *cb_data; + + enum mad_flow (*input_func)(void *, struct mad_stream *); + enum mad_flow (*header_func)(void *, struct mad_header const *); + enum mad_flow (*filter_func)(void *, + struct mad_stream const *, struct mad_frame *); + enum mad_flow (*output_func)(void *, + struct mad_header const *, struct mad_pcm *); + enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); + enum mad_flow (*message_func)(void *, void *, unsigned int *); +}; + +void mad_decoder_init(struct mad_decoder *, void *, + enum mad_flow (*)(void *, struct mad_stream *), + enum mad_flow (*)(void *, struct mad_header const *), + enum mad_flow (*)(void *, + struct mad_stream const *, + struct mad_frame *), + enum mad_flow (*)(void *, + struct mad_header const *, + struct mad_pcm *), + enum mad_flow (*)(void *, + struct mad_stream *, + struct mad_frame *), + enum mad_flow (*)(void *, void *, unsigned int *)); +int mad_decoder_finish(struct mad_decoder *); + +# define mad_decoder_options(decoder, opts) \ + ((void) ((decoder)->options = (opts))) + +int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode); +int mad_decoder_message(struct mad_decoder *, void *, unsigned int *); + +# endif + +# ifdef __cplusplus +} +# endif diff --git a/code/libmad/minimad.c b/code/libmad/minimad.c new file mode 100644 index 00000000..ac412ae4 --- /dev/null +++ b/code/libmad/minimad.c @@ -0,0 +1,222 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: minimad.c,v 1.4 2004/01/23 09:41:32 rob Exp $ + */ + +# include +# include +# include +# include + +# include "mad.h" + +/* + * This is perhaps the simplest example use of the MAD high-level API. + * Standard input is mapped into memory via mmap(), then the high-level API + * is invoked with three callbacks: input, output, and error. The output + * callback converts MAD's high-resolution PCM samples to 16 bits, then + * writes them to standard output in little-endian, stereo-interleaved + * format. + */ + +static int decode(unsigned char const *, unsigned long); + +int main(int argc, char *argv[]) +{ + struct stat stat; + void *fdm; + + if (argc != 1) + return 1; + + if (fstat(STDIN_FILENO, &stat) == -1 || + stat.st_size == 0) + return 2; + + fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0); + if (fdm == MAP_FAILED) + return 3; + + decode(fdm, stat.st_size); + + if (munmap(fdm, stat.st_size) == -1) + return 4; + + return 0; +} + +/* + * This is a private message structure. A generic pointer to this structure + * is passed to each of the callback functions. Put here any data you need + * to access from within the callbacks. + */ + +struct buffer { + unsigned char const *start; + unsigned long length; +}; + +/* + * This is the input callback. The purpose of this callback is to (re)fill + * the stream buffer which is to be decoded. In this example, an entire file + * has been mapped into memory, so we just call mad_stream_buffer() with the + * address and length of the mapping. When this callback is called a second + * time, we are finished decoding. + */ + +static +enum mad_flow input(void *data, + struct mad_stream *stream) +{ + struct buffer *buffer = data; + + if (!buffer->length) + return MAD_FLOW_STOP; + + mad_stream_buffer(stream, buffer->start, buffer->length); + + buffer->length = 0; + + return MAD_FLOW_CONTINUE; +} + +/* + * The following utility routine performs simple rounding, clipping, and + * scaling of MAD's high-resolution samples down to 16 bits. It does not + * perform any dithering or noise shaping, which would be recommended to + * obtain any exceptional audio quality. It is therefore not recommended to + * use this routine if high-quality output is desired. + */ + +static inline +signed int scale(mad_fixed_t sample) +{ + /* round */ + sample += (1L << (MAD_F_FRACBITS - 16)); + + /* clip */ + if (sample >= MAD_F_ONE) + sample = MAD_F_ONE - 1; + else if (sample < -MAD_F_ONE) + sample = -MAD_F_ONE; + + /* quantize */ + return sample >> (MAD_F_FRACBITS + 1 - 16); +} + +/* + * This is the output callback function. It is called after each frame of + * MPEG audio data has been completely decoded. The purpose of this callback + * is to output (or play) the decoded PCM audio. + */ + +static +enum mad_flow output(void *data, + struct mad_header const *header, + struct mad_pcm *pcm) +{ + unsigned int nchannels, nsamples; + mad_fixed_t const *left_ch, *right_ch; + + /* pcm->samplerate contains the sampling frequency */ + + nchannels = pcm->channels; + nsamples = pcm->length; + left_ch = pcm->samples[0]; + right_ch = pcm->samples[1]; + + while (nsamples--) { + signed int sample; + + /* output sample(s) in 16-bit signed little-endian PCM */ + + sample = scale(*left_ch++); + putchar((sample >> 0) & 0xff); + putchar((sample >> 8) & 0xff); + + if (nchannels == 2) { + sample = scale(*right_ch++); + putchar((sample >> 0) & 0xff); + putchar((sample >> 8) & 0xff); + } + } + + return MAD_FLOW_CONTINUE; +} + +/* + * This is the error callback function. It is called whenever a decoding + * error occurs. The error is indicated by stream->error; the list of + * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h) + * header file. + */ + +static +enum mad_flow error(void *data, + struct mad_stream *stream, + struct mad_frame *frame) +{ + struct buffer *buffer = data; + + fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n", + stream->error, mad_stream_errorstr(stream), + stream->this_frame - buffer->start); + + /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */ + + return MAD_FLOW_CONTINUE; +} + +/* + * This is the function called by main() above to perform all the decoding. + * It instantiates a decoder object and configures it with the input, + * output, and error callback functions above. A single call to + * mad_decoder_run() continues until a callback function returns + * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and + * signal an error). + */ + +static +int decode(unsigned char const *start, unsigned long length) +{ + struct buffer buffer; + struct mad_decoder decoder; + int result; + + /* initialize our private message structure */ + + buffer.start = start; + buffer.length = length; + + /* configure input, output, and error functions */ + + mad_decoder_init(&decoder, &buffer, + input, 0 /* header */, 0 /* filter */, output, + error, 0 /* message */); + + /* start decoding */ + + result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); + + /* release the decoder */ + + mad_decoder_finish(&decoder); + + return result; +} diff --git a/code/libmad/packaging/mad.pc.in b/code/libmad/packaging/mad.pc.in new file mode 100644 index 00000000..7cb5dbb1 --- /dev/null +++ b/code/libmad/packaging/mad.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=@PKGCONFIG_INCLUDEDIR@ +libdir=@PKGCONFIG_LIBDIR@ + +Name: MAD +Description: MPEG audio decoder library +Version: @CMAKE_PROJECT_VERSION@ +URL: https://codeberg.org/tenacityteam/libmad +Libs: -L${libdir} -lmad +Cflags: -I${includedir} diff --git a/code/libmad/packaging/madConfig.cmake.in b/code/libmad/packaging/madConfig.cmake.in new file mode 100644 index 00000000..2b2e2ce0 --- /dev/null +++ b/code/libmad/packaging/madConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/madTargets.cmake") + +check_required_components(mad) diff --git a/code/libmad/qc_table.dat b/code/libmad/qc_table.dat new file mode 100644 index 00000000..35a22234 --- /dev/null +++ b/code/libmad/qc_table.dat @@ -0,0 +1,77 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: qc_table.dat,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +/* + * These are the Layer II classes of quantization. + * The table is derived from Table B.4 of ISO/IEC 11172-3. + */ + + { 3, 2, 5, + MAD_F(0x15555555) /* 1.33333333333 => 1.33333333209, e 0.00000000124 */, + MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e 0.00000000000 */ }, + { 5, 3, 7, + MAD_F(0x1999999a) /* 1.60000000000 => 1.60000000149, e -0.00000000149 */, + MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e 0.00000000000 */ }, + { 7, 0, 3, + MAD_F(0x12492492) /* 1.14285714286 => 1.14285714179, e 0.00000000107 */, + MAD_F(0x04000000) /* 0.25000000000 => 0.25000000000, e 0.00000000000 */ }, + { 9, 4, 10, + MAD_F(0x1c71c71c) /* 1.77777777777 => 1.77777777612, e 0.00000000165 */, + MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e 0.00000000000 */ }, + { 15, 0, 4, + MAD_F(0x11111111) /* 1.06666666666 => 1.06666666642, e 0.00000000024 */, + MAD_F(0x02000000) /* 0.12500000000 => 0.12500000000, e 0.00000000000 */ }, + { 31, 0, 5, + MAD_F(0x10842108) /* 1.03225806452 => 1.03225806355, e 0.00000000097 */, + MAD_F(0x01000000) /* 0.06250000000 => 0.06250000000, e 0.00000000000 */ }, + { 63, 0, 6, + MAD_F(0x10410410) /* 1.01587301587 => 1.01587301493, e 0.00000000094 */, + MAD_F(0x00800000) /* 0.03125000000 => 0.03125000000, e 0.00000000000 */ }, + { 127, 0, 7, + MAD_F(0x10204081) /* 1.00787401575 => 1.00787401572, e 0.00000000003 */, + MAD_F(0x00400000) /* 0.01562500000 => 0.01562500000, e 0.00000000000 */ }, + { 255, 0, 8, + MAD_F(0x10101010) /* 1.00392156863 => 1.00392156839, e 0.00000000024 */, + MAD_F(0x00200000) /* 0.00781250000 => 0.00781250000, e 0.00000000000 */ }, + { 511, 0, 9, + MAD_F(0x10080402) /* 1.00195694716 => 1.00195694715, e 0.00000000001 */, + MAD_F(0x00100000) /* 0.00390625000 => 0.00390625000, e 0.00000000000 */ }, + { 1023, 0, 10, + MAD_F(0x10040100) /* 1.00097751711 => 1.00097751617, e 0.00000000094 */, + MAD_F(0x00080000) /* 0.00195312500 => 0.00195312500, e 0.00000000000 */ }, + { 2047, 0, 11, + MAD_F(0x10020040) /* 1.00048851979 => 1.00048851967, e 0.00000000012 */, + MAD_F(0x00040000) /* 0.00097656250 => 0.00097656250, e 0.00000000000 */ }, + { 4095, 0, 12, + MAD_F(0x10010010) /* 1.00024420024 => 1.00024420023, e 0.00000000001 */, + MAD_F(0x00020000) /* 0.00048828125 => 0.00048828125, e 0.00000000000 */ }, + { 8191, 0, 13, + MAD_F(0x10008004) /* 1.00012208522 => 1.00012208521, e 0.00000000001 */, + MAD_F(0x00010000) /* 0.00024414063 => 0.00024414062, e 0.00000000000 */ }, + { 16383, 0, 14, + MAD_F(0x10004001) /* 1.00006103888 => 1.00006103888, e -0.00000000000 */, + MAD_F(0x00008000) /* 0.00012207031 => 0.00012207031, e -0.00000000000 */ }, + { 32767, 0, 15, + MAD_F(0x10002000) /* 1.00003051851 => 1.00003051758, e 0.00000000093 */, + MAD_F(0x00004000) /* 0.00006103516 => 0.00006103516, e 0.00000000000 */ }, + { 65535, 0, 16, + MAD_F(0x10001000) /* 1.00001525902 => 1.00001525879, e 0.00000000023 */, + MAD_F(0x00002000) /* 0.00003051758 => 0.00003051758, e 0.00000000000 */ } diff --git a/code/libmad/rq_table.dat b/code/libmad/rq_table.dat new file mode 100644 index 00000000..059c4f31 --- /dev/null +++ b/code/libmad/rq_table.dat @@ -0,0 +1,8747 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: rq_table.dat,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +/* + * This is the lookup table used to compute x^(4/3) for Layer III + * requantization. To maintain the best possible accuracy, the value is + * stored as a normalized mantissa with exponent. The requantization + * algorithm recombines these parts with appropriate scaling. + */ + + /* 0 */ { MAD_F(0x00000000) /* 0.000000000 */, 0 }, + /* 1 */ { MAD_F(0x04000000) /* 0.250000000 */, 2 }, + /* 2 */ { MAD_F(0x050a28be) /* 0.314980262 */, 3 }, + /* 3 */ { MAD_F(0x0453a5cd) /* 0.270421794 */, 4 }, + /* 4 */ { MAD_F(0x06597fa9) /* 0.396850263 */, 4 }, + /* 5 */ { MAD_F(0x04466275) /* 0.267183742 */, 5 }, + /* 6 */ { MAD_F(0x05738c72) /* 0.340710111 */, 5 }, + /* 7 */ { MAD_F(0x06b1fc81) /* 0.418453696 */, 5 }, + /* 8 */ { MAD_F(0x04000000) /* 0.250000000 */, 6 }, + /* 9 */ { MAD_F(0x04ae20d7) /* 0.292511788 */, 6 }, + /* 10 */ { MAD_F(0x0562d694) /* 0.336630420 */, 6 }, + /* 11 */ { MAD_F(0x061dae96) /* 0.382246578 */, 6 }, + /* 12 */ { MAD_F(0x06de47f4) /* 0.429267841 */, 6 }, + /* 13 */ { MAD_F(0x07a44f7a) /* 0.477614858 */, 6 }, + /* 14 */ { MAD_F(0x0437be65) /* 0.263609310 */, 7 }, + /* 15 */ { MAD_F(0x049fc824) /* 0.289009227 */, 7 }, + + /* 16 */ { MAD_F(0x050a28be) /* 0.314980262 */, 7 }, + /* 17 */ { MAD_F(0x0576c6f5) /* 0.341498336 */, 7 }, + /* 18 */ { MAD_F(0x05e58c0b) /* 0.368541759 */, 7 }, + /* 19 */ { MAD_F(0x06566361) /* 0.396090870 */, 7 }, + /* 20 */ { MAD_F(0x06c93a2e) /* 0.424127753 */, 7 }, + /* 21 */ { MAD_F(0x073dff3e) /* 0.452635998 */, 7 }, + /* 22 */ { MAD_F(0x07b4a2bc) /* 0.481600510 */, 7 }, + /* 23 */ { MAD_F(0x04168b05) /* 0.255503674 */, 8 }, + /* 24 */ { MAD_F(0x0453a5cd) /* 0.270421794 */, 8 }, + /* 25 */ { MAD_F(0x04919b6a) /* 0.285548607 */, 8 }, + /* 26 */ { MAD_F(0x04d065fb) /* 0.300878507 */, 8 }, + /* 27 */ { MAD_F(0x05100000) /* 0.316406250 */, 8 }, + /* 28 */ { MAD_F(0x05506451) /* 0.332126919 */, 8 }, + /* 29 */ { MAD_F(0x05918e15) /* 0.348035890 */, 8 }, + /* 30 */ { MAD_F(0x05d378bb) /* 0.364128809 */, 8 }, + /* 31 */ { MAD_F(0x06161ff3) /* 0.380401563 */, 8 }, + + /* 32 */ { MAD_F(0x06597fa9) /* 0.396850263 */, 8 }, + /* 33 */ { MAD_F(0x069d9400) /* 0.413471222 */, 8 }, + /* 34 */ { MAD_F(0x06e2594c) /* 0.430260942 */, 8 }, + /* 35 */ { MAD_F(0x0727cc11) /* 0.447216097 */, 8 }, + /* 36 */ { MAD_F(0x076de8fc) /* 0.464333519 */, 8 }, + /* 37 */ { MAD_F(0x07b4ace3) /* 0.481610189 */, 8 }, + /* 38 */ { MAD_F(0x07fc14bf) /* 0.499043224 */, 8 }, + /* 39 */ { MAD_F(0x04220ed7) /* 0.258314934 */, 9 }, + /* 40 */ { MAD_F(0x04466275) /* 0.267183742 */, 9 }, + /* 41 */ { MAD_F(0x046b03e7) /* 0.276126771 */, 9 }, + /* 42 */ { MAD_F(0x048ff1e8) /* 0.285142811 */, 9 }, + /* 43 */ { MAD_F(0x04b52b3f) /* 0.294230696 */, 9 }, + /* 44 */ { MAD_F(0x04daaec0) /* 0.303389310 */, 9 }, + /* 45 */ { MAD_F(0x05007b49) /* 0.312617576 */, 9 }, + /* 46 */ { MAD_F(0x05268fc6) /* 0.321914457 */, 9 }, + /* 47 */ { MAD_F(0x054ceb2a) /* 0.331278957 */, 9 }, + + /* 48 */ { MAD_F(0x05738c72) /* 0.340710111 */, 9 }, + /* 49 */ { MAD_F(0x059a72a5) /* 0.350206992 */, 9 }, + /* 50 */ { MAD_F(0x05c19cd3) /* 0.359768701 */, 9 }, + /* 51 */ { MAD_F(0x05e90a12) /* 0.369394372 */, 9 }, + /* 52 */ { MAD_F(0x0610b982) /* 0.379083164 */, 9 }, + /* 53 */ { MAD_F(0x0638aa48) /* 0.388834268 */, 9 }, + /* 54 */ { MAD_F(0x0660db91) /* 0.398646895 */, 9 }, + /* 55 */ { MAD_F(0x06894c90) /* 0.408520284 */, 9 }, + /* 56 */ { MAD_F(0x06b1fc81) /* 0.418453696 */, 9 }, + /* 57 */ { MAD_F(0x06daeaa1) /* 0.428446415 */, 9 }, + /* 58 */ { MAD_F(0x07041636) /* 0.438497744 */, 9 }, + /* 59 */ { MAD_F(0x072d7e8b) /* 0.448607009 */, 9 }, + /* 60 */ { MAD_F(0x075722ef) /* 0.458773552 */, 9 }, + /* 61 */ { MAD_F(0x078102b8) /* 0.468996735 */, 9 }, + /* 62 */ { MAD_F(0x07ab1d3e) /* 0.479275937 */, 9 }, + /* 63 */ { MAD_F(0x07d571e0) /* 0.489610555 */, 9 }, + + /* 64 */ { MAD_F(0x04000000) /* 0.250000000 */, 10 }, + /* 65 */ { MAD_F(0x04156381) /* 0.255221850 */, 10 }, + /* 66 */ { MAD_F(0x042ae32a) /* 0.260470548 */, 10 }, + /* 67 */ { MAD_F(0x04407eb1) /* 0.265745823 */, 10 }, + /* 68 */ { MAD_F(0x045635cf) /* 0.271047409 */, 10 }, + /* 69 */ { MAD_F(0x046c083e) /* 0.276375048 */, 10 }, + /* 70 */ { MAD_F(0x0481f5bb) /* 0.281728487 */, 10 }, + /* 71 */ { MAD_F(0x0497fe03) /* 0.287107481 */, 10 }, + /* 72 */ { MAD_F(0x04ae20d7) /* 0.292511788 */, 10 }, + /* 73 */ { MAD_F(0x04c45df6) /* 0.297941173 */, 10 }, + /* 74 */ { MAD_F(0x04dab524) /* 0.303395408 */, 10 }, + /* 75 */ { MAD_F(0x04f12624) /* 0.308874267 */, 10 }, + /* 76 */ { MAD_F(0x0507b0bc) /* 0.314377532 */, 10 }, + /* 77 */ { MAD_F(0x051e54b1) /* 0.319904987 */, 10 }, + /* 78 */ { MAD_F(0x053511cb) /* 0.325456423 */, 10 }, + /* 79 */ { MAD_F(0x054be7d4) /* 0.331031635 */, 10 }, + + /* 80 */ { MAD_F(0x0562d694) /* 0.336630420 */, 10 }, + /* 81 */ { MAD_F(0x0579ddd8) /* 0.342252584 */, 10 }, + /* 82 */ { MAD_F(0x0590fd6c) /* 0.347897931 */, 10 }, + /* 83 */ { MAD_F(0x05a8351c) /* 0.353566275 */, 10 }, + /* 84 */ { MAD_F(0x05bf84b8) /* 0.359257429 */, 10 }, + /* 85 */ { MAD_F(0x05d6ec0e) /* 0.364971213 */, 10 }, + /* 86 */ { MAD_F(0x05ee6aef) /* 0.370707448 */, 10 }, + /* 87 */ { MAD_F(0x0606012b) /* 0.376465960 */, 10 }, + /* 88 */ { MAD_F(0x061dae96) /* 0.382246578 */, 10 }, + /* 89 */ { MAD_F(0x06357302) /* 0.388049134 */, 10 }, + /* 90 */ { MAD_F(0x064d4e43) /* 0.393873464 */, 10 }, + /* 91 */ { MAD_F(0x0665402d) /* 0.399719406 */, 10 }, + /* 92 */ { MAD_F(0x067d4896) /* 0.405586801 */, 10 }, + /* 93 */ { MAD_F(0x06956753) /* 0.411475493 */, 10 }, + /* 94 */ { MAD_F(0x06ad9c3d) /* 0.417385331 */, 10 }, + /* 95 */ { MAD_F(0x06c5e72b) /* 0.423316162 */, 10 }, + + /* 96 */ { MAD_F(0x06de47f4) /* 0.429267841 */, 10 }, + /* 97 */ { MAD_F(0x06f6be73) /* 0.435240221 */, 10 }, + /* 98 */ { MAD_F(0x070f4a80) /* 0.441233161 */, 10 }, + /* 99 */ { MAD_F(0x0727ebf7) /* 0.447246519 */, 10 }, + /* 100 */ { MAD_F(0x0740a2b2) /* 0.453280160 */, 10 }, + /* 101 */ { MAD_F(0x07596e8d) /* 0.459333946 */, 10 }, + /* 102 */ { MAD_F(0x07724f64) /* 0.465407744 */, 10 }, + /* 103 */ { MAD_F(0x078b4514) /* 0.471501425 */, 10 }, + /* 104 */ { MAD_F(0x07a44f7a) /* 0.477614858 */, 10 }, + /* 105 */ { MAD_F(0x07bd6e75) /* 0.483747918 */, 10 }, + /* 106 */ { MAD_F(0x07d6a1e2) /* 0.489900479 */, 10 }, + /* 107 */ { MAD_F(0x07efe9a1) /* 0.496072418 */, 10 }, + /* 108 */ { MAD_F(0x0404a2c9) /* 0.251131807 */, 11 }, + /* 109 */ { MAD_F(0x04115aca) /* 0.254236974 */, 11 }, + /* 110 */ { MAD_F(0x041e1cc4) /* 0.257351652 */, 11 }, + /* 111 */ { MAD_F(0x042ae8a7) /* 0.260475783 */, 11 }, + + /* 112 */ { MAD_F(0x0437be65) /* 0.263609310 */, 11 }, + /* 113 */ { MAD_F(0x04449dee) /* 0.266752177 */, 11 }, + /* 114 */ { MAD_F(0x04518733) /* 0.269904329 */, 11 }, + /* 115 */ { MAD_F(0x045e7a26) /* 0.273065710 */, 11 }, + /* 116 */ { MAD_F(0x046b76b9) /* 0.276236269 */, 11 }, + /* 117 */ { MAD_F(0x04787cdc) /* 0.279415952 */, 11 }, + /* 118 */ { MAD_F(0x04858c83) /* 0.282604707 */, 11 }, + /* 119 */ { MAD_F(0x0492a59f) /* 0.285802482 */, 11 }, + /* 120 */ { MAD_F(0x049fc824) /* 0.289009227 */, 11 }, + /* 121 */ { MAD_F(0x04acf402) /* 0.292224893 */, 11 }, + /* 122 */ { MAD_F(0x04ba292e) /* 0.295449429 */, 11 }, + /* 123 */ { MAD_F(0x04c7679a) /* 0.298682788 */, 11 }, + /* 124 */ { MAD_F(0x04d4af3a) /* 0.301924921 */, 11 }, + /* 125 */ { MAD_F(0x04e20000) /* 0.305175781 */, 11 }, + /* 126 */ { MAD_F(0x04ef59e0) /* 0.308435322 */, 11 }, + /* 127 */ { MAD_F(0x04fcbcce) /* 0.311703498 */, 11 }, + + /* 128 */ { MAD_F(0x050a28be) /* 0.314980262 */, 11 }, + /* 129 */ { MAD_F(0x05179da4) /* 0.318265572 */, 11 }, + /* 130 */ { MAD_F(0x05251b73) /* 0.321559381 */, 11 }, + /* 131 */ { MAD_F(0x0532a220) /* 0.324861647 */, 11 }, + /* 132 */ { MAD_F(0x054031a0) /* 0.328172327 */, 11 }, + /* 133 */ { MAD_F(0x054dc9e7) /* 0.331491377 */, 11 }, + /* 134 */ { MAD_F(0x055b6ae9) /* 0.334818756 */, 11 }, + /* 135 */ { MAD_F(0x0569149c) /* 0.338154423 */, 11 }, + /* 136 */ { MAD_F(0x0576c6f5) /* 0.341498336 */, 11 }, + /* 137 */ { MAD_F(0x058481e9) /* 0.344850455 */, 11 }, + /* 138 */ { MAD_F(0x0592456d) /* 0.348210741 */, 11 }, + /* 139 */ { MAD_F(0x05a01176) /* 0.351579152 */, 11 }, + /* 140 */ { MAD_F(0x05ade5fa) /* 0.354955651 */, 11 }, + /* 141 */ { MAD_F(0x05bbc2ef) /* 0.358340200 */, 11 }, + /* 142 */ { MAD_F(0x05c9a84a) /* 0.361732758 */, 11 }, + /* 143 */ { MAD_F(0x05d79601) /* 0.365133291 */, 11 }, + + /* 144 */ { MAD_F(0x05e58c0b) /* 0.368541759 */, 11 }, + /* 145 */ { MAD_F(0x05f38a5d) /* 0.371958126 */, 11 }, + /* 146 */ { MAD_F(0x060190ee) /* 0.375382356 */, 11 }, + /* 147 */ { MAD_F(0x060f9fb3) /* 0.378814413 */, 11 }, + /* 148 */ { MAD_F(0x061db6a5) /* 0.382254261 */, 11 }, + /* 149 */ { MAD_F(0x062bd5b8) /* 0.385701865 */, 11 }, + /* 150 */ { MAD_F(0x0639fce4) /* 0.389157191 */, 11 }, + /* 151 */ { MAD_F(0x06482c1f) /* 0.392620204 */, 11 }, + /* 152 */ { MAD_F(0x06566361) /* 0.396090870 */, 11 }, + /* 153 */ { MAD_F(0x0664a2a0) /* 0.399569155 */, 11 }, + /* 154 */ { MAD_F(0x0672e9d4) /* 0.403055027 */, 11 }, + /* 155 */ { MAD_F(0x068138f3) /* 0.406548452 */, 11 }, + /* 156 */ { MAD_F(0x068f8ff5) /* 0.410049398 */, 11 }, + /* 157 */ { MAD_F(0x069deed1) /* 0.413557833 */, 11 }, + /* 158 */ { MAD_F(0x06ac557f) /* 0.417073724 */, 11 }, + /* 159 */ { MAD_F(0x06bac3f6) /* 0.420597041 */, 11 }, + + /* 160 */ { MAD_F(0x06c93a2e) /* 0.424127753 */, 11 }, + /* 161 */ { MAD_F(0x06d7b81f) /* 0.427665827 */, 11 }, + /* 162 */ { MAD_F(0x06e63dc0) /* 0.431211234 */, 11 }, + /* 163 */ { MAD_F(0x06f4cb09) /* 0.434763944 */, 11 }, + /* 164 */ { MAD_F(0x07035ff3) /* 0.438323927 */, 11 }, + /* 165 */ { MAD_F(0x0711fc75) /* 0.441891153 */, 11 }, + /* 166 */ { MAD_F(0x0720a087) /* 0.445465593 */, 11 }, + /* 167 */ { MAD_F(0x072f4c22) /* 0.449047217 */, 11 }, + /* 168 */ { MAD_F(0x073dff3e) /* 0.452635998 */, 11 }, + /* 169 */ { MAD_F(0x074cb9d3) /* 0.456231906 */, 11 }, + /* 170 */ { MAD_F(0x075b7bdb) /* 0.459834914 */, 11 }, + /* 171 */ { MAD_F(0x076a454c) /* 0.463444993 */, 11 }, + /* 172 */ { MAD_F(0x07791620) /* 0.467062117 */, 11 }, + /* 173 */ { MAD_F(0x0787ee50) /* 0.470686258 */, 11 }, + /* 174 */ { MAD_F(0x0796cdd4) /* 0.474317388 */, 11 }, + /* 175 */ { MAD_F(0x07a5b4a5) /* 0.477955481 */, 11 }, + + /* 176 */ { MAD_F(0x07b4a2bc) /* 0.481600510 */, 11 }, + /* 177 */ { MAD_F(0x07c39812) /* 0.485252449 */, 11 }, + /* 178 */ { MAD_F(0x07d294a0) /* 0.488911273 */, 11 }, + /* 179 */ { MAD_F(0x07e1985f) /* 0.492576954 */, 11 }, + /* 180 */ { MAD_F(0x07f0a348) /* 0.496249468 */, 11 }, + /* 181 */ { MAD_F(0x07ffb554) /* 0.499928790 */, 11 }, + /* 182 */ { MAD_F(0x0407673f) /* 0.251807447 */, 12 }, + /* 183 */ { MAD_F(0x040ef75e) /* 0.253653877 */, 12 }, + /* 184 */ { MAD_F(0x04168b05) /* 0.255503674 */, 12 }, + /* 185 */ { MAD_F(0x041e2230) /* 0.257356825 */, 12 }, + /* 186 */ { MAD_F(0x0425bcdd) /* 0.259213318 */, 12 }, + /* 187 */ { MAD_F(0x042d5b07) /* 0.261073141 */, 12 }, + /* 188 */ { MAD_F(0x0434fcad) /* 0.262936282 */, 12 }, + /* 189 */ { MAD_F(0x043ca1c9) /* 0.264802730 */, 12 }, + /* 190 */ { MAD_F(0x04444a5a) /* 0.266672472 */, 12 }, + /* 191 */ { MAD_F(0x044bf65d) /* 0.268545497 */, 12 }, + + /* 192 */ { MAD_F(0x0453a5cd) /* 0.270421794 */, 12 }, + /* 193 */ { MAD_F(0x045b58a9) /* 0.272301352 */, 12 }, + /* 194 */ { MAD_F(0x04630eed) /* 0.274184158 */, 12 }, + /* 195 */ { MAD_F(0x046ac896) /* 0.276070203 */, 12 }, + /* 196 */ { MAD_F(0x047285a2) /* 0.277959474 */, 12 }, + /* 197 */ { MAD_F(0x047a460c) /* 0.279851960 */, 12 }, + /* 198 */ { MAD_F(0x048209d3) /* 0.281747652 */, 12 }, + /* 199 */ { MAD_F(0x0489d0f4) /* 0.283646538 */, 12 }, + /* 200 */ { MAD_F(0x04919b6a) /* 0.285548607 */, 12 }, + /* 201 */ { MAD_F(0x04996935) /* 0.287453849 */, 12 }, + /* 202 */ { MAD_F(0x04a13a50) /* 0.289362253 */, 12 }, + /* 203 */ { MAD_F(0x04a90eba) /* 0.291273810 */, 12 }, + /* 204 */ { MAD_F(0x04b0e66e) /* 0.293188507 */, 12 }, + /* 205 */ { MAD_F(0x04b8c16c) /* 0.295106336 */, 12 }, + /* 206 */ { MAD_F(0x04c09faf) /* 0.297027285 */, 12 }, + /* 207 */ { MAD_F(0x04c88135) /* 0.298951346 */, 12 }, + + /* 208 */ { MAD_F(0x04d065fb) /* 0.300878507 */, 12 }, + /* 209 */ { MAD_F(0x04d84dff) /* 0.302808759 */, 12 }, + /* 210 */ { MAD_F(0x04e0393e) /* 0.304742092 */, 12 }, + /* 211 */ { MAD_F(0x04e827b6) /* 0.306678497 */, 12 }, + /* 212 */ { MAD_F(0x04f01963) /* 0.308617963 */, 12 }, + /* 213 */ { MAD_F(0x04f80e44) /* 0.310560480 */, 12 }, + /* 214 */ { MAD_F(0x05000655) /* 0.312506041 */, 12 }, + /* 215 */ { MAD_F(0x05080195) /* 0.314454634 */, 12 }, + /* 216 */ { MAD_F(0x05100000) /* 0.316406250 */, 12 }, + /* 217 */ { MAD_F(0x05180194) /* 0.318360880 */, 12 }, + /* 218 */ { MAD_F(0x0520064f) /* 0.320318516 */, 12 }, + /* 219 */ { MAD_F(0x05280e2d) /* 0.322279147 */, 12 }, + /* 220 */ { MAD_F(0x0530192e) /* 0.324242764 */, 12 }, + /* 221 */ { MAD_F(0x0538274e) /* 0.326209359 */, 12 }, + /* 222 */ { MAD_F(0x0540388a) /* 0.328178922 */, 12 }, + /* 223 */ { MAD_F(0x05484ce2) /* 0.330151445 */, 12 }, + + /* 224 */ { MAD_F(0x05506451) /* 0.332126919 */, 12 }, + /* 225 */ { MAD_F(0x05587ed5) /* 0.334105334 */, 12 }, + /* 226 */ { MAD_F(0x05609c6e) /* 0.336086683 */, 12 }, + /* 227 */ { MAD_F(0x0568bd17) /* 0.338070956 */, 12 }, + /* 228 */ { MAD_F(0x0570e0cf) /* 0.340058145 */, 12 }, + /* 229 */ { MAD_F(0x05790793) /* 0.342048241 */, 12 }, + /* 230 */ { MAD_F(0x05813162) /* 0.344041237 */, 12 }, + /* 231 */ { MAD_F(0x05895e39) /* 0.346037122 */, 12 }, + /* 232 */ { MAD_F(0x05918e15) /* 0.348035890 */, 12 }, + /* 233 */ { MAD_F(0x0599c0f4) /* 0.350037532 */, 12 }, + /* 234 */ { MAD_F(0x05a1f6d5) /* 0.352042040 */, 12 }, + /* 235 */ { MAD_F(0x05aa2fb5) /* 0.354049405 */, 12 }, + /* 236 */ { MAD_F(0x05b26b92) /* 0.356059619 */, 12 }, + /* 237 */ { MAD_F(0x05baaa69) /* 0.358072674 */, 12 }, + /* 238 */ { MAD_F(0x05c2ec39) /* 0.360088563 */, 12 }, + /* 239 */ { MAD_F(0x05cb3100) /* 0.362107278 */, 12 }, + + /* 240 */ { MAD_F(0x05d378bb) /* 0.364128809 */, 12 }, + /* 241 */ { MAD_F(0x05dbc368) /* 0.366153151 */, 12 }, + /* 242 */ { MAD_F(0x05e41105) /* 0.368180294 */, 12 }, + /* 243 */ { MAD_F(0x05ec6190) /* 0.370210231 */, 12 }, + /* 244 */ { MAD_F(0x05f4b507) /* 0.372242955 */, 12 }, + /* 245 */ { MAD_F(0x05fd0b68) /* 0.374278458 */, 12 }, + /* 246 */ { MAD_F(0x060564b1) /* 0.376316732 */, 12 }, + /* 247 */ { MAD_F(0x060dc0e0) /* 0.378357769 */, 12 }, + /* 248 */ { MAD_F(0x06161ff3) /* 0.380401563 */, 12 }, + /* 249 */ { MAD_F(0x061e81e8) /* 0.382448106 */, 12 }, + /* 250 */ { MAD_F(0x0626e6bc) /* 0.384497391 */, 12 }, + /* 251 */ { MAD_F(0x062f4e6f) /* 0.386549409 */, 12 }, + /* 252 */ { MAD_F(0x0637b8fd) /* 0.388604155 */, 12 }, + /* 253 */ { MAD_F(0x06402666) /* 0.390661620 */, 12 }, + /* 254 */ { MAD_F(0x064896a7) /* 0.392721798 */, 12 }, + /* 255 */ { MAD_F(0x065109be) /* 0.394784681 */, 12 }, + + /* 256 */ { MAD_F(0x06597fa9) /* 0.396850263 */, 12 }, + /* 257 */ { MAD_F(0x0661f867) /* 0.398918536 */, 12 }, + /* 258 */ { MAD_F(0x066a73f5) /* 0.400989493 */, 12 }, + /* 259 */ { MAD_F(0x0672f252) /* 0.403063128 */, 12 }, + /* 260 */ { MAD_F(0x067b737c) /* 0.405139433 */, 12 }, + /* 261 */ { MAD_F(0x0683f771) /* 0.407218402 */, 12 }, + /* 262 */ { MAD_F(0x068c7e2f) /* 0.409300027 */, 12 }, + /* 263 */ { MAD_F(0x069507b5) /* 0.411384303 */, 12 }, + /* 264 */ { MAD_F(0x069d9400) /* 0.413471222 */, 12 }, + /* 265 */ { MAD_F(0x06a6230f) /* 0.415560778 */, 12 }, + /* 266 */ { MAD_F(0x06aeb4e0) /* 0.417652964 */, 12 }, + /* 267 */ { MAD_F(0x06b74971) /* 0.419747773 */, 12 }, + /* 268 */ { MAD_F(0x06bfe0c0) /* 0.421845199 */, 12 }, + /* 269 */ { MAD_F(0x06c87acc) /* 0.423945235 */, 12 }, + /* 270 */ { MAD_F(0x06d11794) /* 0.426047876 */, 12 }, + /* 271 */ { MAD_F(0x06d9b714) /* 0.428153114 */, 12 }, + + /* 272 */ { MAD_F(0x06e2594c) /* 0.430260942 */, 12 }, + /* 273 */ { MAD_F(0x06eafe3a) /* 0.432371356 */, 12 }, + /* 274 */ { MAD_F(0x06f3a5dc) /* 0.434484348 */, 12 }, + /* 275 */ { MAD_F(0x06fc5030) /* 0.436599912 */, 12 }, + /* 276 */ { MAD_F(0x0704fd35) /* 0.438718042 */, 12 }, + /* 277 */ { MAD_F(0x070dacea) /* 0.440838732 */, 12 }, + /* 278 */ { MAD_F(0x07165f4b) /* 0.442961975 */, 12 }, + /* 279 */ { MAD_F(0x071f1459) /* 0.445087765 */, 12 }, + /* 280 */ { MAD_F(0x0727cc11) /* 0.447216097 */, 12 }, + /* 281 */ { MAD_F(0x07308671) /* 0.449346964 */, 12 }, + /* 282 */ { MAD_F(0x07394378) /* 0.451480360 */, 12 }, + /* 283 */ { MAD_F(0x07420325) /* 0.453616280 */, 12 }, + /* 284 */ { MAD_F(0x074ac575) /* 0.455754717 */, 12 }, + /* 285 */ { MAD_F(0x07538a67) /* 0.457895665 */, 12 }, + /* 286 */ { MAD_F(0x075c51fa) /* 0.460039119 */, 12 }, + /* 287 */ { MAD_F(0x07651c2c) /* 0.462185072 */, 12 }, + + /* 288 */ { MAD_F(0x076de8fc) /* 0.464333519 */, 12 }, + /* 289 */ { MAD_F(0x0776b867) /* 0.466484455 */, 12 }, + /* 290 */ { MAD_F(0x077f8a6d) /* 0.468637872 */, 12 }, + /* 291 */ { MAD_F(0x07885f0b) /* 0.470793767 */, 12 }, + /* 292 */ { MAD_F(0x07913641) /* 0.472952132 */, 12 }, + /* 293 */ { MAD_F(0x079a100c) /* 0.475112962 */, 12 }, + /* 294 */ { MAD_F(0x07a2ec6c) /* 0.477276252 */, 12 }, + /* 295 */ { MAD_F(0x07abcb5f) /* 0.479441997 */, 12 }, + /* 296 */ { MAD_F(0x07b4ace3) /* 0.481610189 */, 12 }, + /* 297 */ { MAD_F(0x07bd90f6) /* 0.483780825 */, 12 }, + /* 298 */ { MAD_F(0x07c67798) /* 0.485953899 */, 12 }, + /* 299 */ { MAD_F(0x07cf60c7) /* 0.488129404 */, 12 }, + /* 300 */ { MAD_F(0x07d84c81) /* 0.490307336 */, 12 }, + /* 301 */ { MAD_F(0x07e13ac5) /* 0.492487690 */, 12 }, + /* 302 */ { MAD_F(0x07ea2b92) /* 0.494670459 */, 12 }, + /* 303 */ { MAD_F(0x07f31ee6) /* 0.496855639 */, 12 }, + + /* 304 */ { MAD_F(0x07fc14bf) /* 0.499043224 */, 12 }, + /* 305 */ { MAD_F(0x0402868e) /* 0.250616605 */, 13 }, + /* 306 */ { MAD_F(0x040703ff) /* 0.251712795 */, 13 }, + /* 307 */ { MAD_F(0x040b82b0) /* 0.252810180 */, 13 }, + /* 308 */ { MAD_F(0x041002a1) /* 0.253908756 */, 13 }, + /* 309 */ { MAD_F(0x041483d1) /* 0.255008523 */, 13 }, + /* 310 */ { MAD_F(0x04190640) /* 0.256109476 */, 13 }, + /* 311 */ { MAD_F(0x041d89ed) /* 0.257211614 */, 13 }, + /* 312 */ { MAD_F(0x04220ed7) /* 0.258314934 */, 13 }, + /* 313 */ { MAD_F(0x042694fe) /* 0.259419433 */, 13 }, + /* 314 */ { MAD_F(0x042b1c60) /* 0.260525110 */, 13 }, + /* 315 */ { MAD_F(0x042fa4fe) /* 0.261631960 */, 13 }, + /* 316 */ { MAD_F(0x04342ed7) /* 0.262739982 */, 13 }, + /* 317 */ { MAD_F(0x0438b9e9) /* 0.263849174 */, 13 }, + /* 318 */ { MAD_F(0x043d4635) /* 0.264959533 */, 13 }, + /* 319 */ { MAD_F(0x0441d3b9) /* 0.266071056 */, 13 }, + + /* 320 */ { MAD_F(0x04466275) /* 0.267183742 */, 13 }, + /* 321 */ { MAD_F(0x044af269) /* 0.268297587 */, 13 }, + /* 322 */ { MAD_F(0x044f8393) /* 0.269412589 */, 13 }, + /* 323 */ { MAD_F(0x045415f3) /* 0.270528746 */, 13 }, + /* 324 */ { MAD_F(0x0458a989) /* 0.271646056 */, 13 }, + /* 325 */ { MAD_F(0x045d3e53) /* 0.272764515 */, 13 }, + /* 326 */ { MAD_F(0x0461d451) /* 0.273884123 */, 13 }, + /* 327 */ { MAD_F(0x04666b83) /* 0.275004875 */, 13 }, + /* 328 */ { MAD_F(0x046b03e7) /* 0.276126771 */, 13 }, + /* 329 */ { MAD_F(0x046f9d7e) /* 0.277249808 */, 13 }, + /* 330 */ { MAD_F(0x04743847) /* 0.278373983 */, 13 }, + /* 331 */ { MAD_F(0x0478d440) /* 0.279499294 */, 13 }, + /* 332 */ { MAD_F(0x047d716a) /* 0.280625739 */, 13 }, + /* 333 */ { MAD_F(0x04820fc3) /* 0.281753315 */, 13 }, + /* 334 */ { MAD_F(0x0486af4c) /* 0.282882021 */, 13 }, + /* 335 */ { MAD_F(0x048b5003) /* 0.284011853 */, 13 }, + + /* 336 */ { MAD_F(0x048ff1e8) /* 0.285142811 */, 13 }, + /* 337 */ { MAD_F(0x049494fb) /* 0.286274891 */, 13 }, + /* 338 */ { MAD_F(0x0499393a) /* 0.287408091 */, 13 }, + /* 339 */ { MAD_F(0x049ddea5) /* 0.288542409 */, 13 }, + /* 340 */ { MAD_F(0x04a2853c) /* 0.289677844 */, 13 }, + /* 341 */ { MAD_F(0x04a72cfe) /* 0.290814392 */, 13 }, + /* 342 */ { MAD_F(0x04abd5ea) /* 0.291952051 */, 13 }, + /* 343 */ { MAD_F(0x04b08000) /* 0.293090820 */, 13 }, + /* 344 */ { MAD_F(0x04b52b3f) /* 0.294230696 */, 13 }, + /* 345 */ { MAD_F(0x04b9d7a7) /* 0.295371678 */, 13 }, + /* 346 */ { MAD_F(0x04be8537) /* 0.296513762 */, 13 }, + /* 347 */ { MAD_F(0x04c333ee) /* 0.297656947 */, 13 }, + /* 348 */ { MAD_F(0x04c7e3cc) /* 0.298801231 */, 13 }, + /* 349 */ { MAD_F(0x04cc94d1) /* 0.299946611 */, 13 }, + /* 350 */ { MAD_F(0x04d146fb) /* 0.301093085 */, 13 }, + /* 351 */ { MAD_F(0x04d5fa4b) /* 0.302240653 */, 13 }, + + /* 352 */ { MAD_F(0x04daaec0) /* 0.303389310 */, 13 }, + /* 353 */ { MAD_F(0x04df6458) /* 0.304539056 */, 13 }, + /* 354 */ { MAD_F(0x04e41b14) /* 0.305689888 */, 13 }, + /* 355 */ { MAD_F(0x04e8d2f3) /* 0.306841804 */, 13 }, + /* 356 */ { MAD_F(0x04ed8bf5) /* 0.307994802 */, 13 }, + /* 357 */ { MAD_F(0x04f24618) /* 0.309148880 */, 13 }, + /* 358 */ { MAD_F(0x04f7015d) /* 0.310304037 */, 13 }, + /* 359 */ { MAD_F(0x04fbbdc3) /* 0.311460269 */, 13 }, + /* 360 */ { MAD_F(0x05007b49) /* 0.312617576 */, 13 }, + /* 361 */ { MAD_F(0x050539ef) /* 0.313775954 */, 13 }, + /* 362 */ { MAD_F(0x0509f9b4) /* 0.314935403 */, 13 }, + /* 363 */ { MAD_F(0x050eba98) /* 0.316095920 */, 13 }, + /* 364 */ { MAD_F(0x05137c9a) /* 0.317257503 */, 13 }, + /* 365 */ { MAD_F(0x05183fba) /* 0.318420150 */, 13 }, + /* 366 */ { MAD_F(0x051d03f7) /* 0.319583859 */, 13 }, + /* 367 */ { MAD_F(0x0521c950) /* 0.320748629 */, 13 }, + + /* 368 */ { MAD_F(0x05268fc6) /* 0.321914457 */, 13 }, + /* 369 */ { MAD_F(0x052b5757) /* 0.323081342 */, 13 }, + /* 370 */ { MAD_F(0x05302003) /* 0.324249281 */, 13 }, + /* 371 */ { MAD_F(0x0534e9ca) /* 0.325418273 */, 13 }, + /* 372 */ { MAD_F(0x0539b4ab) /* 0.326588316 */, 13 }, + /* 373 */ { MAD_F(0x053e80a6) /* 0.327759407 */, 13 }, + /* 374 */ { MAD_F(0x05434db9) /* 0.328931546 */, 13 }, + /* 375 */ { MAD_F(0x05481be5) /* 0.330104730 */, 13 }, + /* 376 */ { MAD_F(0x054ceb2a) /* 0.331278957 */, 13 }, + /* 377 */ { MAD_F(0x0551bb85) /* 0.332454225 */, 13 }, + /* 378 */ { MAD_F(0x05568cf8) /* 0.333630533 */, 13 }, + /* 379 */ { MAD_F(0x055b5f81) /* 0.334807879 */, 13 }, + /* 380 */ { MAD_F(0x05603321) /* 0.335986261 */, 13 }, + /* 381 */ { MAD_F(0x056507d6) /* 0.337165677 */, 13 }, + /* 382 */ { MAD_F(0x0569dda0) /* 0.338346125 */, 13 }, + /* 383 */ { MAD_F(0x056eb47f) /* 0.339527604 */, 13 }, + + /* 384 */ { MAD_F(0x05738c72) /* 0.340710111 */, 13 }, + /* 385 */ { MAD_F(0x05786578) /* 0.341893646 */, 13 }, + /* 386 */ { MAD_F(0x057d3f92) /* 0.343078205 */, 13 }, + /* 387 */ { MAD_F(0x05821abf) /* 0.344263788 */, 13 }, + /* 388 */ { MAD_F(0x0586f6fd) /* 0.345450393 */, 13 }, + /* 389 */ { MAD_F(0x058bd44e) /* 0.346638017 */, 13 }, + /* 390 */ { MAD_F(0x0590b2b0) /* 0.347826659 */, 13 }, + /* 391 */ { MAD_F(0x05959222) /* 0.349016318 */, 13 }, + /* 392 */ { MAD_F(0x059a72a5) /* 0.350206992 */, 13 }, + /* 393 */ { MAD_F(0x059f5438) /* 0.351398678 */, 13 }, + /* 394 */ { MAD_F(0x05a436da) /* 0.352591376 */, 13 }, + /* 395 */ { MAD_F(0x05a91a8c) /* 0.353785083 */, 13 }, + /* 396 */ { MAD_F(0x05adff4c) /* 0.354979798 */, 13 }, + /* 397 */ { MAD_F(0x05b2e51a) /* 0.356175519 */, 13 }, + /* 398 */ { MAD_F(0x05b7cbf5) /* 0.357372244 */, 13 }, + /* 399 */ { MAD_F(0x05bcb3de) /* 0.358569972 */, 13 }, + + /* 400 */ { MAD_F(0x05c19cd3) /* 0.359768701 */, 13 }, + /* 401 */ { MAD_F(0x05c686d5) /* 0.360968429 */, 13 }, + /* 402 */ { MAD_F(0x05cb71e2) /* 0.362169156 */, 13 }, + /* 403 */ { MAD_F(0x05d05dfb) /* 0.363370878 */, 13 }, + /* 404 */ { MAD_F(0x05d54b1f) /* 0.364573594 */, 13 }, + /* 405 */ { MAD_F(0x05da394d) /* 0.365777304 */, 13 }, + /* 406 */ { MAD_F(0x05df2885) /* 0.366982004 */, 13 }, + /* 407 */ { MAD_F(0x05e418c7) /* 0.368187694 */, 13 }, + /* 408 */ { MAD_F(0x05e90a12) /* 0.369394372 */, 13 }, + /* 409 */ { MAD_F(0x05edfc66) /* 0.370602036 */, 13 }, + /* 410 */ { MAD_F(0x05f2efc2) /* 0.371810684 */, 13 }, + /* 411 */ { MAD_F(0x05f7e426) /* 0.373020316 */, 13 }, + /* 412 */ { MAD_F(0x05fcd992) /* 0.374230929 */, 13 }, + /* 413 */ { MAD_F(0x0601d004) /* 0.375442522 */, 13 }, + /* 414 */ { MAD_F(0x0606c77d) /* 0.376655093 */, 13 }, + /* 415 */ { MAD_F(0x060bbffd) /* 0.377868641 */, 13 }, + + /* 416 */ { MAD_F(0x0610b982) /* 0.379083164 */, 13 }, + /* 417 */ { MAD_F(0x0615b40c) /* 0.380298661 */, 13 }, + /* 418 */ { MAD_F(0x061aaf9c) /* 0.381515130 */, 13 }, + /* 419 */ { MAD_F(0x061fac2f) /* 0.382732569 */, 13 }, + /* 420 */ { MAD_F(0x0624a9c7) /* 0.383950977 */, 13 }, + /* 421 */ { MAD_F(0x0629a863) /* 0.385170352 */, 13 }, + /* 422 */ { MAD_F(0x062ea802) /* 0.386390694 */, 13 }, + /* 423 */ { MAD_F(0x0633a8a3) /* 0.387611999 */, 13 }, + /* 424 */ { MAD_F(0x0638aa48) /* 0.388834268 */, 13 }, + /* 425 */ { MAD_F(0x063dacee) /* 0.390057497 */, 13 }, + /* 426 */ { MAD_F(0x0642b096) /* 0.391281687 */, 13 }, + /* 427 */ { MAD_F(0x0647b53f) /* 0.392506834 */, 13 }, + /* 428 */ { MAD_F(0x064cbae9) /* 0.393732939 */, 13 }, + /* 429 */ { MAD_F(0x0651c193) /* 0.394959999 */, 13 }, + /* 430 */ { MAD_F(0x0656c93d) /* 0.396188012 */, 13 }, + /* 431 */ { MAD_F(0x065bd1e7) /* 0.397416978 */, 13 }, + + /* 432 */ { MAD_F(0x0660db91) /* 0.398646895 */, 13 }, + /* 433 */ { MAD_F(0x0665e639) /* 0.399877761 */, 13 }, + /* 434 */ { MAD_F(0x066af1df) /* 0.401109575 */, 13 }, + /* 435 */ { MAD_F(0x066ffe84) /* 0.402342335 */, 13 }, + /* 436 */ { MAD_F(0x06750c26) /* 0.403576041 */, 13 }, + /* 437 */ { MAD_F(0x067a1ac6) /* 0.404810690 */, 13 }, + /* 438 */ { MAD_F(0x067f2a62) /* 0.406046281 */, 13 }, + /* 439 */ { MAD_F(0x06843afb) /* 0.407282813 */, 13 }, + /* 440 */ { MAD_F(0x06894c90) /* 0.408520284 */, 13 }, + /* 441 */ { MAD_F(0x068e5f21) /* 0.409758693 */, 13 }, + /* 442 */ { MAD_F(0x069372ae) /* 0.410998038 */, 13 }, + /* 443 */ { MAD_F(0x06988735) /* 0.412238319 */, 13 }, + /* 444 */ { MAD_F(0x069d9cb7) /* 0.413479532 */, 13 }, + /* 445 */ { MAD_F(0x06a2b333) /* 0.414721679 */, 13 }, + /* 446 */ { MAD_F(0x06a7caa9) /* 0.415964756 */, 13 }, + /* 447 */ { MAD_F(0x06ace318) /* 0.417208762 */, 13 }, + + /* 448 */ { MAD_F(0x06b1fc81) /* 0.418453696 */, 13 }, + /* 449 */ { MAD_F(0x06b716e2) /* 0.419699557 */, 13 }, + /* 450 */ { MAD_F(0x06bc323b) /* 0.420946343 */, 13 }, + /* 451 */ { MAD_F(0x06c14e8d) /* 0.422194054 */, 13 }, + /* 452 */ { MAD_F(0x06c66bd6) /* 0.423442686 */, 13 }, + /* 453 */ { MAD_F(0x06cb8a17) /* 0.424692240 */, 13 }, + /* 454 */ { MAD_F(0x06d0a94e) /* 0.425942714 */, 13 }, + /* 455 */ { MAD_F(0x06d5c97c) /* 0.427194106 */, 13 }, + /* 456 */ { MAD_F(0x06daeaa1) /* 0.428446415 */, 13 }, + /* 457 */ { MAD_F(0x06e00cbb) /* 0.429699640 */, 13 }, + /* 458 */ { MAD_F(0x06e52fca) /* 0.430953779 */, 13 }, + /* 459 */ { MAD_F(0x06ea53cf) /* 0.432208832 */, 13 }, + /* 460 */ { MAD_F(0x06ef78c8) /* 0.433464796 */, 13 }, + /* 461 */ { MAD_F(0x06f49eb6) /* 0.434721671 */, 13 }, + /* 462 */ { MAD_F(0x06f9c597) /* 0.435979455 */, 13 }, + /* 463 */ { MAD_F(0x06feed6d) /* 0.437238146 */, 13 }, + + /* 464 */ { MAD_F(0x07041636) /* 0.438497744 */, 13 }, + /* 465 */ { MAD_F(0x07093ff2) /* 0.439758248 */, 13 }, + /* 466 */ { MAD_F(0x070e6aa0) /* 0.441019655 */, 13 }, + /* 467 */ { MAD_F(0x07139641) /* 0.442281965 */, 13 }, + /* 468 */ { MAD_F(0x0718c2d3) /* 0.443545176 */, 13 }, + /* 469 */ { MAD_F(0x071df058) /* 0.444809288 */, 13 }, + /* 470 */ { MAD_F(0x07231ecd) /* 0.446074298 */, 13 }, + /* 471 */ { MAD_F(0x07284e34) /* 0.447340205 */, 13 }, + /* 472 */ { MAD_F(0x072d7e8b) /* 0.448607009 */, 13 }, + /* 473 */ { MAD_F(0x0732afd2) /* 0.449874708 */, 13 }, + /* 474 */ { MAD_F(0x0737e209) /* 0.451143300 */, 13 }, + /* 475 */ { MAD_F(0x073d1530) /* 0.452412785 */, 13 }, + /* 476 */ { MAD_F(0x07424946) /* 0.453683161 */, 13 }, + /* 477 */ { MAD_F(0x07477e4b) /* 0.454954427 */, 13 }, + /* 478 */ { MAD_F(0x074cb43e) /* 0.456226581 */, 13 }, + /* 479 */ { MAD_F(0x0751eb20) /* 0.457499623 */, 13 }, + + /* 480 */ { MAD_F(0x075722ef) /* 0.458773552 */, 13 }, + /* 481 */ { MAD_F(0x075c5bac) /* 0.460048365 */, 13 }, + /* 482 */ { MAD_F(0x07619557) /* 0.461324062 */, 13 }, + /* 483 */ { MAD_F(0x0766cfee) /* 0.462600642 */, 13 }, + /* 484 */ { MAD_F(0x076c0b72) /* 0.463878102 */, 13 }, + /* 485 */ { MAD_F(0x077147e2) /* 0.465156443 */, 13 }, + /* 486 */ { MAD_F(0x0776853e) /* 0.466435663 */, 13 }, + /* 487 */ { MAD_F(0x077bc385) /* 0.467715761 */, 13 }, + /* 488 */ { MAD_F(0x078102b8) /* 0.468996735 */, 13 }, + /* 489 */ { MAD_F(0x078642d6) /* 0.470278584 */, 13 }, + /* 490 */ { MAD_F(0x078b83de) /* 0.471561307 */, 13 }, + /* 491 */ { MAD_F(0x0790c5d1) /* 0.472844904 */, 13 }, + /* 492 */ { MAD_F(0x079608ae) /* 0.474129372 */, 13 }, + /* 493 */ { MAD_F(0x079b4c74) /* 0.475414710 */, 13 }, + /* 494 */ { MAD_F(0x07a09124) /* 0.476700918 */, 13 }, + /* 495 */ { MAD_F(0x07a5d6bd) /* 0.477987994 */, 13 }, + + /* 496 */ { MAD_F(0x07ab1d3e) /* 0.479275937 */, 13 }, + /* 497 */ { MAD_F(0x07b064a8) /* 0.480564746 */, 13 }, + /* 498 */ { MAD_F(0x07b5acfb) /* 0.481854420 */, 13 }, + /* 499 */ { MAD_F(0x07baf635) /* 0.483144957 */, 13 }, + /* 500 */ { MAD_F(0x07c04056) /* 0.484436356 */, 13 }, + /* 501 */ { MAD_F(0x07c58b5f) /* 0.485728617 */, 13 }, + /* 502 */ { MAD_F(0x07cad74e) /* 0.487021738 */, 13 }, + /* 503 */ { MAD_F(0x07d02424) /* 0.488315717 */, 13 }, + /* 504 */ { MAD_F(0x07d571e0) /* 0.489610555 */, 13 }, + /* 505 */ { MAD_F(0x07dac083) /* 0.490906249 */, 13 }, + /* 506 */ { MAD_F(0x07e0100a) /* 0.492202799 */, 13 }, + /* 507 */ { MAD_F(0x07e56078) /* 0.493500203 */, 13 }, + /* 508 */ { MAD_F(0x07eab1ca) /* 0.494798460 */, 13 }, + /* 509 */ { MAD_F(0x07f00401) /* 0.496097570 */, 13 }, + /* 510 */ { MAD_F(0x07f5571d) /* 0.497397530 */, 13 }, + /* 511 */ { MAD_F(0x07faab1c) /* 0.498698341 */, 13 }, + + /* 512 */ { MAD_F(0x04000000) /* 0.250000000 */, 14 }, + /* 513 */ { MAD_F(0x0402aae3) /* 0.250651254 */, 14 }, + /* 514 */ { MAD_F(0x04055638) /* 0.251302930 */, 14 }, + /* 515 */ { MAD_F(0x040801ff) /* 0.251955030 */, 14 }, + /* 516 */ { MAD_F(0x040aae37) /* 0.252607552 */, 14 }, + /* 517 */ { MAD_F(0x040d5ae0) /* 0.253260495 */, 14 }, + /* 518 */ { MAD_F(0x041007fa) /* 0.253913860 */, 14 }, + /* 519 */ { MAD_F(0x0412b586) /* 0.254567645 */, 14 }, + /* 520 */ { MAD_F(0x04156381) /* 0.255221850 */, 14 }, + /* 521 */ { MAD_F(0x041811ee) /* 0.255876475 */, 14 }, + /* 522 */ { MAD_F(0x041ac0cb) /* 0.256531518 */, 14 }, + /* 523 */ { MAD_F(0x041d7018) /* 0.257186980 */, 14 }, + /* 524 */ { MAD_F(0x04201fd5) /* 0.257842860 */, 14 }, + /* 525 */ { MAD_F(0x0422d003) /* 0.258499157 */, 14 }, + /* 526 */ { MAD_F(0x042580a0) /* 0.259155872 */, 14 }, + /* 527 */ { MAD_F(0x042831ad) /* 0.259813002 */, 14 }, + + /* 528 */ { MAD_F(0x042ae32a) /* 0.260470548 */, 14 }, + /* 529 */ { MAD_F(0x042d9516) /* 0.261128510 */, 14 }, + /* 530 */ { MAD_F(0x04304772) /* 0.261786886 */, 14 }, + /* 531 */ { MAD_F(0x0432fa3d) /* 0.262445676 */, 14 }, + /* 532 */ { MAD_F(0x0435ad76) /* 0.263104880 */, 14 }, + /* 533 */ { MAD_F(0x0438611f) /* 0.263764497 */, 14 }, + /* 534 */ { MAD_F(0x043b1536) /* 0.264424527 */, 14 }, + /* 535 */ { MAD_F(0x043dc9bc) /* 0.265084969 */, 14 }, + /* 536 */ { MAD_F(0x04407eb1) /* 0.265745823 */, 14 }, + /* 537 */ { MAD_F(0x04433414) /* 0.266407088 */, 14 }, + /* 538 */ { MAD_F(0x0445e9e5) /* 0.267068763 */, 14 }, + /* 539 */ { MAD_F(0x0448a024) /* 0.267730848 */, 14 }, + /* 540 */ { MAD_F(0x044b56d1) /* 0.268393343 */, 14 }, + /* 541 */ { MAD_F(0x044e0dec) /* 0.269056248 */, 14 }, + /* 542 */ { MAD_F(0x0450c575) /* 0.269719560 */, 14 }, + /* 543 */ { MAD_F(0x04537d6b) /* 0.270383281 */, 14 }, + + /* 544 */ { MAD_F(0x045635cf) /* 0.271047409 */, 14 }, + /* 545 */ { MAD_F(0x0458ee9f) /* 0.271711944 */, 14 }, + /* 546 */ { MAD_F(0x045ba7dd) /* 0.272376886 */, 14 }, + /* 547 */ { MAD_F(0x045e6188) /* 0.273042234 */, 14 }, + /* 548 */ { MAD_F(0x04611ba0) /* 0.273707988 */, 14 }, + /* 549 */ { MAD_F(0x0463d625) /* 0.274374147 */, 14 }, + /* 550 */ { MAD_F(0x04669116) /* 0.275040710 */, 14 }, + /* 551 */ { MAD_F(0x04694c74) /* 0.275707677 */, 14 }, + /* 552 */ { MAD_F(0x046c083e) /* 0.276375048 */, 14 }, + /* 553 */ { MAD_F(0x046ec474) /* 0.277042822 */, 14 }, + /* 554 */ { MAD_F(0x04718116) /* 0.277710999 */, 14 }, + /* 555 */ { MAD_F(0x04743e25) /* 0.278379578 */, 14 }, + /* 556 */ { MAD_F(0x0476fb9f) /* 0.279048558 */, 14 }, + /* 557 */ { MAD_F(0x0479b984) /* 0.279717940 */, 14 }, + /* 558 */ { MAD_F(0x047c77d6) /* 0.280387722 */, 14 }, + /* 559 */ { MAD_F(0x047f3693) /* 0.281057905 */, 14 }, + + /* 560 */ { MAD_F(0x0481f5bb) /* 0.281728487 */, 14 }, + /* 561 */ { MAD_F(0x0484b54e) /* 0.282399469 */, 14 }, + /* 562 */ { MAD_F(0x0487754c) /* 0.283070849 */, 14 }, + /* 563 */ { MAD_F(0x048a35b6) /* 0.283742628 */, 14 }, + /* 564 */ { MAD_F(0x048cf68a) /* 0.284414805 */, 14 }, + /* 565 */ { MAD_F(0x048fb7c8) /* 0.285087379 */, 14 }, + /* 566 */ { MAD_F(0x04927972) /* 0.285760350 */, 14 }, + /* 567 */ { MAD_F(0x04953b85) /* 0.286433717 */, 14 }, + /* 568 */ { MAD_F(0x0497fe03) /* 0.287107481 */, 14 }, + /* 569 */ { MAD_F(0x049ac0eb) /* 0.287781640 */, 14 }, + /* 570 */ { MAD_F(0x049d843e) /* 0.288456194 */, 14 }, + /* 571 */ { MAD_F(0x04a047fa) /* 0.289131142 */, 14 }, + /* 572 */ { MAD_F(0x04a30c20) /* 0.289806485 */, 14 }, + /* 573 */ { MAD_F(0x04a5d0af) /* 0.290482221 */, 14 }, + /* 574 */ { MAD_F(0x04a895a8) /* 0.291158351 */, 14 }, + /* 575 */ { MAD_F(0x04ab5b0b) /* 0.291834873 */, 14 }, + + /* 576 */ { MAD_F(0x04ae20d7) /* 0.292511788 */, 14 }, + /* 577 */ { MAD_F(0x04b0e70c) /* 0.293189094 */, 14 }, + /* 578 */ { MAD_F(0x04b3adaa) /* 0.293866792 */, 14 }, + /* 579 */ { MAD_F(0x04b674b1) /* 0.294544881 */, 14 }, + /* 580 */ { MAD_F(0x04b93c21) /* 0.295223360 */, 14 }, + /* 581 */ { MAD_F(0x04bc03fa) /* 0.295902229 */, 14 }, + /* 582 */ { MAD_F(0x04becc3b) /* 0.296581488 */, 14 }, + /* 583 */ { MAD_F(0x04c194e4) /* 0.297261136 */, 14 }, + /* 584 */ { MAD_F(0x04c45df6) /* 0.297941173 */, 14 }, + /* 585 */ { MAD_F(0x04c72771) /* 0.298621598 */, 14 }, + /* 586 */ { MAD_F(0x04c9f153) /* 0.299302411 */, 14 }, + /* 587 */ { MAD_F(0x04ccbb9d) /* 0.299983611 */, 14 }, + /* 588 */ { MAD_F(0x04cf864f) /* 0.300665198 */, 14 }, + /* 589 */ { MAD_F(0x04d25169) /* 0.301347172 */, 14 }, + /* 590 */ { MAD_F(0x04d51ceb) /* 0.302029532 */, 14 }, + /* 591 */ { MAD_F(0x04d7e8d4) /* 0.302712277 */, 14 }, + + /* 592 */ { MAD_F(0x04dab524) /* 0.303395408 */, 14 }, + /* 593 */ { MAD_F(0x04dd81dc) /* 0.304078923 */, 14 }, + /* 594 */ { MAD_F(0x04e04efb) /* 0.304762823 */, 14 }, + /* 595 */ { MAD_F(0x04e31c81) /* 0.305447106 */, 14 }, + /* 596 */ { MAD_F(0x04e5ea6e) /* 0.306131773 */, 14 }, + /* 597 */ { MAD_F(0x04e8b8c2) /* 0.306816823 */, 14 }, + /* 598 */ { MAD_F(0x04eb877c) /* 0.307502256 */, 14 }, + /* 599 */ { MAD_F(0x04ee569d) /* 0.308188071 */, 14 }, + /* 600 */ { MAD_F(0x04f12624) /* 0.308874267 */, 14 }, + /* 601 */ { MAD_F(0x04f3f612) /* 0.309560845 */, 14 }, + /* 602 */ { MAD_F(0x04f6c666) /* 0.310247804 */, 14 }, + /* 603 */ { MAD_F(0x04f99721) /* 0.310935143 */, 14 }, + /* 604 */ { MAD_F(0x04fc6841) /* 0.311622862 */, 14 }, + /* 605 */ { MAD_F(0x04ff39c7) /* 0.312310961 */, 14 }, + /* 606 */ { MAD_F(0x05020bb3) /* 0.312999439 */, 14 }, + /* 607 */ { MAD_F(0x0504de05) /* 0.313688296 */, 14 }, + + /* 608 */ { MAD_F(0x0507b0bc) /* 0.314377532 */, 14 }, + /* 609 */ { MAD_F(0x050a83d8) /* 0.315067145 */, 14 }, + /* 610 */ { MAD_F(0x050d575b) /* 0.315757136 */, 14 }, + /* 611 */ { MAD_F(0x05102b42) /* 0.316447504 */, 14 }, + /* 612 */ { MAD_F(0x0512ff8e) /* 0.317138249 */, 14 }, + /* 613 */ { MAD_F(0x0515d440) /* 0.317829370 */, 14 }, + /* 614 */ { MAD_F(0x0518a956) /* 0.318520867 */, 14 }, + /* 615 */ { MAD_F(0x051b7ed1) /* 0.319212739 */, 14 }, + /* 616 */ { MAD_F(0x051e54b1) /* 0.319904987 */, 14 }, + /* 617 */ { MAD_F(0x05212af5) /* 0.320597609 */, 14 }, + /* 618 */ { MAD_F(0x0524019e) /* 0.321290606 */, 14 }, + /* 619 */ { MAD_F(0x0526d8ab) /* 0.321983976 */, 14 }, + /* 620 */ { MAD_F(0x0529b01d) /* 0.322677720 */, 14 }, + /* 621 */ { MAD_F(0x052c87f2) /* 0.323371837 */, 14 }, + /* 622 */ { MAD_F(0x052f602c) /* 0.324066327 */, 14 }, + /* 623 */ { MAD_F(0x053238ca) /* 0.324761189 */, 14 }, + + /* 624 */ { MAD_F(0x053511cb) /* 0.325456423 */, 14 }, + /* 625 */ { MAD_F(0x0537eb30) /* 0.326152028 */, 14 }, + /* 626 */ { MAD_F(0x053ac4f9) /* 0.326848005 */, 14 }, + /* 627 */ { MAD_F(0x053d9f25) /* 0.327544352 */, 14 }, + /* 628 */ { MAD_F(0x054079b5) /* 0.328241070 */, 14 }, + /* 629 */ { MAD_F(0x054354a8) /* 0.328938157 */, 14 }, + /* 630 */ { MAD_F(0x05462ffe) /* 0.329635614 */, 14 }, + /* 631 */ { MAD_F(0x05490bb7) /* 0.330333440 */, 14 }, + /* 632 */ { MAD_F(0x054be7d4) /* 0.331031635 */, 14 }, + /* 633 */ { MAD_F(0x054ec453) /* 0.331730198 */, 14 }, + /* 634 */ { MAD_F(0x0551a134) /* 0.332429129 */, 14 }, + /* 635 */ { MAD_F(0x05547e79) /* 0.333128427 */, 14 }, + /* 636 */ { MAD_F(0x05575c20) /* 0.333828093 */, 14 }, + /* 637 */ { MAD_F(0x055a3a2a) /* 0.334528126 */, 14 }, + /* 638 */ { MAD_F(0x055d1896) /* 0.335228525 */, 14 }, + /* 639 */ { MAD_F(0x055ff764) /* 0.335929290 */, 14 }, + + /* 640 */ { MAD_F(0x0562d694) /* 0.336630420 */, 14 }, + /* 641 */ { MAD_F(0x0565b627) /* 0.337331916 */, 14 }, + /* 642 */ { MAD_F(0x0568961b) /* 0.338033777 */, 14 }, + /* 643 */ { MAD_F(0x056b7671) /* 0.338736002 */, 14 }, + /* 644 */ { MAD_F(0x056e5729) /* 0.339438592 */, 14 }, + /* 645 */ { MAD_F(0x05713843) /* 0.340141545 */, 14 }, + /* 646 */ { MAD_F(0x057419be) /* 0.340844862 */, 14 }, + /* 647 */ { MAD_F(0x0576fb9a) /* 0.341548541 */, 14 }, + /* 648 */ { MAD_F(0x0579ddd8) /* 0.342252584 */, 14 }, + /* 649 */ { MAD_F(0x057cc077) /* 0.342956988 */, 14 }, + /* 650 */ { MAD_F(0x057fa378) /* 0.343661754 */, 14 }, + /* 651 */ { MAD_F(0x058286d9) /* 0.344366882 */, 14 }, + /* 652 */ { MAD_F(0x05856a9b) /* 0.345072371 */, 14 }, + /* 653 */ { MAD_F(0x05884ebe) /* 0.345778221 */, 14 }, + /* 654 */ { MAD_F(0x058b3342) /* 0.346484431 */, 14 }, + /* 655 */ { MAD_F(0x058e1827) /* 0.347191002 */, 14 }, + + /* 656 */ { MAD_F(0x0590fd6c) /* 0.347897931 */, 14 }, + /* 657 */ { MAD_F(0x0593e311) /* 0.348605221 */, 14 }, + /* 658 */ { MAD_F(0x0596c917) /* 0.349312869 */, 14 }, + /* 659 */ { MAD_F(0x0599af7d) /* 0.350020876 */, 14 }, + /* 660 */ { MAD_F(0x059c9643) /* 0.350729240 */, 14 }, + /* 661 */ { MAD_F(0x059f7d6a) /* 0.351437963 */, 14 }, + /* 662 */ { MAD_F(0x05a264f0) /* 0.352147044 */, 14 }, + /* 663 */ { MAD_F(0x05a54cd6) /* 0.352856481 */, 14 }, + /* 664 */ { MAD_F(0x05a8351c) /* 0.353566275 */, 14 }, + /* 665 */ { MAD_F(0x05ab1dc2) /* 0.354276426 */, 14 }, + /* 666 */ { MAD_F(0x05ae06c7) /* 0.354986932 */, 14 }, + /* 667 */ { MAD_F(0x05b0f02b) /* 0.355697795 */, 14 }, + /* 668 */ { MAD_F(0x05b3d9f0) /* 0.356409012 */, 14 }, + /* 669 */ { MAD_F(0x05b6c413) /* 0.357120585 */, 14 }, + /* 670 */ { MAD_F(0x05b9ae95) /* 0.357832512 */, 14 }, + /* 671 */ { MAD_F(0x05bc9977) /* 0.358544794 */, 14 }, + + /* 672 */ { MAD_F(0x05bf84b8) /* 0.359257429 */, 14 }, + /* 673 */ { MAD_F(0x05c27057) /* 0.359970419 */, 14 }, + /* 674 */ { MAD_F(0x05c55c56) /* 0.360683761 */, 14 }, + /* 675 */ { MAD_F(0x05c848b3) /* 0.361397456 */, 14 }, + /* 676 */ { MAD_F(0x05cb356e) /* 0.362111504 */, 14 }, + /* 677 */ { MAD_F(0x05ce2289) /* 0.362825904 */, 14 }, + /* 678 */ { MAD_F(0x05d11001) /* 0.363540655 */, 14 }, + /* 679 */ { MAD_F(0x05d3fdd8) /* 0.364255759 */, 14 }, + /* 680 */ { MAD_F(0x05d6ec0e) /* 0.364971213 */, 14 }, + /* 681 */ { MAD_F(0x05d9daa1) /* 0.365687018 */, 14 }, + /* 682 */ { MAD_F(0x05dcc993) /* 0.366403174 */, 14 }, + /* 683 */ { MAD_F(0x05dfb8e2) /* 0.367119680 */, 14 }, + /* 684 */ { MAD_F(0x05e2a890) /* 0.367836535 */, 14 }, + /* 685 */ { MAD_F(0x05e5989b) /* 0.368553740 */, 14 }, + /* 686 */ { MAD_F(0x05e88904) /* 0.369271294 */, 14 }, + /* 687 */ { MAD_F(0x05eb79cb) /* 0.369989197 */, 14 }, + + /* 688 */ { MAD_F(0x05ee6aef) /* 0.370707448 */, 14 }, + /* 689 */ { MAD_F(0x05f15c70) /* 0.371426047 */, 14 }, + /* 690 */ { MAD_F(0x05f44e4f) /* 0.372144994 */, 14 }, + /* 691 */ { MAD_F(0x05f7408b) /* 0.372864289 */, 14 }, + /* 692 */ { MAD_F(0x05fa3324) /* 0.373583930 */, 14 }, + /* 693 */ { MAD_F(0x05fd261b) /* 0.374303918 */, 14 }, + /* 694 */ { MAD_F(0x0600196e) /* 0.375024253 */, 14 }, + /* 695 */ { MAD_F(0x06030d1e) /* 0.375744934 */, 14 }, + /* 696 */ { MAD_F(0x0606012b) /* 0.376465960 */, 14 }, + /* 697 */ { MAD_F(0x0608f595) /* 0.377187332 */, 14 }, + /* 698 */ { MAD_F(0x060bea5c) /* 0.377909049 */, 14 }, + /* 699 */ { MAD_F(0x060edf7f) /* 0.378631110 */, 14 }, + /* 700 */ { MAD_F(0x0611d4fe) /* 0.379353516 */, 14 }, + /* 701 */ { MAD_F(0x0614cada) /* 0.380076266 */, 14 }, + /* 702 */ { MAD_F(0x0617c112) /* 0.380799360 */, 14 }, + /* 703 */ { MAD_F(0x061ab7a6) /* 0.381522798 */, 14 }, + + /* 704 */ { MAD_F(0x061dae96) /* 0.382246578 */, 14 }, + /* 705 */ { MAD_F(0x0620a5e3) /* 0.382970701 */, 14 }, + /* 706 */ { MAD_F(0x06239d8b) /* 0.383695167 */, 14 }, + /* 707 */ { MAD_F(0x0626958f) /* 0.384419975 */, 14 }, + /* 708 */ { MAD_F(0x06298def) /* 0.385145124 */, 14 }, + /* 709 */ { MAD_F(0x062c86aa) /* 0.385870615 */, 14 }, + /* 710 */ { MAD_F(0x062f7fc1) /* 0.386596448 */, 14 }, + /* 711 */ { MAD_F(0x06327934) /* 0.387322621 */, 14 }, + /* 712 */ { MAD_F(0x06357302) /* 0.388049134 */, 14 }, + /* 713 */ { MAD_F(0x06386d2b) /* 0.388775988 */, 14 }, + /* 714 */ { MAD_F(0x063b67b0) /* 0.389503182 */, 14 }, + /* 715 */ { MAD_F(0x063e6290) /* 0.390230715 */, 14 }, + /* 716 */ { MAD_F(0x06415dcb) /* 0.390958588 */, 14 }, + /* 717 */ { MAD_F(0x06445960) /* 0.391686799 */, 14 }, + /* 718 */ { MAD_F(0x06475551) /* 0.392415349 */, 14 }, + /* 719 */ { MAD_F(0x064a519c) /* 0.393144238 */, 14 }, + + /* 720 */ { MAD_F(0x064d4e43) /* 0.393873464 */, 14 }, + /* 721 */ { MAD_F(0x06504b44) /* 0.394603028 */, 14 }, + /* 722 */ { MAD_F(0x0653489f) /* 0.395332930 */, 14 }, + /* 723 */ { MAD_F(0x06564655) /* 0.396063168 */, 14 }, + /* 724 */ { MAD_F(0x06594465) /* 0.396793743 */, 14 }, + /* 725 */ { MAD_F(0x065c42d0) /* 0.397524655 */, 14 }, + /* 726 */ { MAD_F(0x065f4195) /* 0.398255903 */, 14 }, + /* 727 */ { MAD_F(0x066240b4) /* 0.398987487 */, 14 }, + /* 728 */ { MAD_F(0x0665402d) /* 0.399719406 */, 14 }, + /* 729 */ { MAD_F(0x06684000) /* 0.400451660 */, 14 }, + /* 730 */ { MAD_F(0x066b402d) /* 0.401184249 */, 14 }, + /* 731 */ { MAD_F(0x066e40b3) /* 0.401917173 */, 14 }, + /* 732 */ { MAD_F(0x06714194) /* 0.402650431 */, 14 }, + /* 733 */ { MAD_F(0x067442ce) /* 0.403384024 */, 14 }, + /* 734 */ { MAD_F(0x06774462) /* 0.404117949 */, 14 }, + /* 735 */ { MAD_F(0x067a464f) /* 0.404852209 */, 14 }, + + /* 736 */ { MAD_F(0x067d4896) /* 0.405586801 */, 14 }, + /* 737 */ { MAD_F(0x06804b36) /* 0.406321726 */, 14 }, + /* 738 */ { MAD_F(0x06834e2f) /* 0.407056983 */, 14 }, + /* 739 */ { MAD_F(0x06865181) /* 0.407792573 */, 14 }, + /* 740 */ { MAD_F(0x0689552c) /* 0.408528495 */, 14 }, + /* 741 */ { MAD_F(0x068c5931) /* 0.409264748 */, 14 }, + /* 742 */ { MAD_F(0x068f5d8e) /* 0.410001332 */, 14 }, + /* 743 */ { MAD_F(0x06926245) /* 0.410738247 */, 14 }, + /* 744 */ { MAD_F(0x06956753) /* 0.411475493 */, 14 }, + /* 745 */ { MAD_F(0x06986cbb) /* 0.412213070 */, 14 }, + /* 746 */ { MAD_F(0x069b727b) /* 0.412950976 */, 14 }, + /* 747 */ { MAD_F(0x069e7894) /* 0.413689213 */, 14 }, + /* 748 */ { MAD_F(0x06a17f05) /* 0.414427779 */, 14 }, + /* 749 */ { MAD_F(0x06a485cf) /* 0.415166674 */, 14 }, + /* 750 */ { MAD_F(0x06a78cf1) /* 0.415905897 */, 14 }, + /* 751 */ { MAD_F(0x06aa946b) /* 0.416645450 */, 14 }, + + /* 752 */ { MAD_F(0x06ad9c3d) /* 0.417385331 */, 14 }, + /* 753 */ { MAD_F(0x06b0a468) /* 0.418125540 */, 14 }, + /* 754 */ { MAD_F(0x06b3acea) /* 0.418866076 */, 14 }, + /* 755 */ { MAD_F(0x06b6b5c4) /* 0.419606940 */, 14 }, + /* 756 */ { MAD_F(0x06b9bef6) /* 0.420348132 */, 14 }, + /* 757 */ { MAD_F(0x06bcc880) /* 0.421089650 */, 14 }, + /* 758 */ { MAD_F(0x06bfd261) /* 0.421831494 */, 14 }, + /* 759 */ { MAD_F(0x06c2dc9a) /* 0.422573665 */, 14 }, + /* 760 */ { MAD_F(0x06c5e72b) /* 0.423316162 */, 14 }, + /* 761 */ { MAD_F(0x06c8f213) /* 0.424058985 */, 14 }, + /* 762 */ { MAD_F(0x06cbfd52) /* 0.424802133 */, 14 }, + /* 763 */ { MAD_F(0x06cf08e9) /* 0.425545607 */, 14 }, + /* 764 */ { MAD_F(0x06d214d7) /* 0.426289405 */, 14 }, + /* 765 */ { MAD_F(0x06d5211c) /* 0.427033528 */, 14 }, + /* 766 */ { MAD_F(0x06d82db8) /* 0.427777975 */, 14 }, + /* 767 */ { MAD_F(0x06db3aaa) /* 0.428522746 */, 14 }, + + /* 768 */ { MAD_F(0x06de47f4) /* 0.429267841 */, 14 }, + /* 769 */ { MAD_F(0x06e15595) /* 0.430013259 */, 14 }, + /* 770 */ { MAD_F(0x06e4638d) /* 0.430759001 */, 14 }, + /* 771 */ { MAD_F(0x06e771db) /* 0.431505065 */, 14 }, + /* 772 */ { MAD_F(0x06ea807f) /* 0.432251452 */, 14 }, + /* 773 */ { MAD_F(0x06ed8f7b) /* 0.432998162 */, 14 }, + /* 774 */ { MAD_F(0x06f09ecc) /* 0.433745193 */, 14 }, + /* 775 */ { MAD_F(0x06f3ae75) /* 0.434492546 */, 14 }, + /* 776 */ { MAD_F(0x06f6be73) /* 0.435240221 */, 14 }, + /* 777 */ { MAD_F(0x06f9cec8) /* 0.435988217 */, 14 }, + /* 778 */ { MAD_F(0x06fcdf72) /* 0.436736534 */, 14 }, + /* 779 */ { MAD_F(0x06fff073) /* 0.437485172 */, 14 }, + /* 780 */ { MAD_F(0x070301ca) /* 0.438234130 */, 14 }, + /* 781 */ { MAD_F(0x07061377) /* 0.438983408 */, 14 }, + /* 782 */ { MAD_F(0x0709257a) /* 0.439733006 */, 14 }, + /* 783 */ { MAD_F(0x070c37d2) /* 0.440482924 */, 14 }, + + /* 784 */ { MAD_F(0x070f4a80) /* 0.441233161 */, 14 }, + /* 785 */ { MAD_F(0x07125d84) /* 0.441983717 */, 14 }, + /* 786 */ { MAD_F(0x071570de) /* 0.442734592 */, 14 }, + /* 787 */ { MAD_F(0x0718848d) /* 0.443485785 */, 14 }, + /* 788 */ { MAD_F(0x071b9891) /* 0.444237296 */, 14 }, + /* 789 */ { MAD_F(0x071eaceb) /* 0.444989126 */, 14 }, + /* 790 */ { MAD_F(0x0721c19a) /* 0.445741273 */, 14 }, + /* 791 */ { MAD_F(0x0724d69e) /* 0.446493738 */, 14 }, + /* 792 */ { MAD_F(0x0727ebf7) /* 0.447246519 */, 14 }, + /* 793 */ { MAD_F(0x072b01a6) /* 0.447999618 */, 14 }, + /* 794 */ { MAD_F(0x072e17a9) /* 0.448753033 */, 14 }, + /* 795 */ { MAD_F(0x07312e01) /* 0.449506765 */, 14 }, + /* 796 */ { MAD_F(0x073444ae) /* 0.450260813 */, 14 }, + /* 797 */ { MAD_F(0x07375bb0) /* 0.451015176 */, 14 }, + /* 798 */ { MAD_F(0x073a7307) /* 0.451769856 */, 14 }, + /* 799 */ { MAD_F(0x073d8ab2) /* 0.452524850 */, 14 }, + + /* 800 */ { MAD_F(0x0740a2b2) /* 0.453280160 */, 14 }, + /* 801 */ { MAD_F(0x0743bb06) /* 0.454035784 */, 14 }, + /* 802 */ { MAD_F(0x0746d3af) /* 0.454791723 */, 14 }, + /* 803 */ { MAD_F(0x0749ecac) /* 0.455547976 */, 14 }, + /* 804 */ { MAD_F(0x074d05fe) /* 0.456304543 */, 14 }, + /* 805 */ { MAD_F(0x07501fa3) /* 0.457061423 */, 14 }, + /* 806 */ { MAD_F(0x0753399d) /* 0.457818618 */, 14 }, + /* 807 */ { MAD_F(0x075653eb) /* 0.458576125 */, 14 }, + /* 808 */ { MAD_F(0x07596e8d) /* 0.459333946 */, 14 }, + /* 809 */ { MAD_F(0x075c8983) /* 0.460092079 */, 14 }, + /* 810 */ { MAD_F(0x075fa4cc) /* 0.460850524 */, 14 }, + /* 811 */ { MAD_F(0x0762c06a) /* 0.461609282 */, 14 }, + /* 812 */ { MAD_F(0x0765dc5b) /* 0.462368352 */, 14 }, + /* 813 */ { MAD_F(0x0768f8a0) /* 0.463127733 */, 14 }, + /* 814 */ { MAD_F(0x076c1538) /* 0.463887426 */, 14 }, + /* 815 */ { MAD_F(0x076f3224) /* 0.464647430 */, 14 }, + + /* 816 */ { MAD_F(0x07724f64) /* 0.465407744 */, 14 }, + /* 817 */ { MAD_F(0x07756cf7) /* 0.466168370 */, 14 }, + /* 818 */ { MAD_F(0x07788add) /* 0.466929306 */, 14 }, + /* 819 */ { MAD_F(0x077ba916) /* 0.467690552 */, 14 }, + /* 820 */ { MAD_F(0x077ec7a3) /* 0.468452108 */, 14 }, + /* 821 */ { MAD_F(0x0781e683) /* 0.469213973 */, 14 }, + /* 822 */ { MAD_F(0x078505b5) /* 0.469976148 */, 14 }, + /* 823 */ { MAD_F(0x0788253b) /* 0.470738632 */, 14 }, + /* 824 */ { MAD_F(0x078b4514) /* 0.471501425 */, 14 }, + /* 825 */ { MAD_F(0x078e653f) /* 0.472264527 */, 14 }, + /* 826 */ { MAD_F(0x079185be) /* 0.473027937 */, 14 }, + /* 827 */ { MAD_F(0x0794a68f) /* 0.473791655 */, 14 }, + /* 828 */ { MAD_F(0x0797c7b2) /* 0.474555681 */, 14 }, + /* 829 */ { MAD_F(0x079ae929) /* 0.475320014 */, 14 }, + /* 830 */ { MAD_F(0x079e0af1) /* 0.476084655 */, 14 }, + /* 831 */ { MAD_F(0x07a12d0c) /* 0.476849603 */, 14 }, + + /* 832 */ { MAD_F(0x07a44f7a) /* 0.477614858 */, 14 }, + /* 833 */ { MAD_F(0x07a7723a) /* 0.478380420 */, 14 }, + /* 834 */ { MAD_F(0x07aa954c) /* 0.479146288 */, 14 }, + /* 835 */ { MAD_F(0x07adb8b0) /* 0.479912463 */, 14 }, + /* 836 */ { MAD_F(0x07b0dc67) /* 0.480678943 */, 14 }, + /* 837 */ { MAD_F(0x07b4006f) /* 0.481445729 */, 14 }, + /* 838 */ { MAD_F(0x07b724ca) /* 0.482212820 */, 14 }, + /* 839 */ { MAD_F(0x07ba4976) /* 0.482980216 */, 14 }, + /* 840 */ { MAD_F(0x07bd6e75) /* 0.483747918 */, 14 }, + /* 841 */ { MAD_F(0x07c093c5) /* 0.484515924 */, 14 }, + /* 842 */ { MAD_F(0x07c3b967) /* 0.485284235 */, 14 }, + /* 843 */ { MAD_F(0x07c6df5a) /* 0.486052849 */, 14 }, + /* 844 */ { MAD_F(0x07ca059f) /* 0.486821768 */, 14 }, + /* 845 */ { MAD_F(0x07cd2c36) /* 0.487590991 */, 14 }, + /* 846 */ { MAD_F(0x07d0531e) /* 0.488360517 */, 14 }, + /* 847 */ { MAD_F(0x07d37a57) /* 0.489130346 */, 14 }, + + /* 848 */ { MAD_F(0x07d6a1e2) /* 0.489900479 */, 14 }, + /* 849 */ { MAD_F(0x07d9c9be) /* 0.490670914 */, 14 }, + /* 850 */ { MAD_F(0x07dcf1ec) /* 0.491441651 */, 14 }, + /* 851 */ { MAD_F(0x07e01a6a) /* 0.492212691 */, 14 }, + /* 852 */ { MAD_F(0x07e3433a) /* 0.492984033 */, 14 }, + /* 853 */ { MAD_F(0x07e66c5a) /* 0.493755677 */, 14 }, + /* 854 */ { MAD_F(0x07e995cc) /* 0.494527623 */, 14 }, + /* 855 */ { MAD_F(0x07ecbf8e) /* 0.495299870 */, 14 }, + /* 856 */ { MAD_F(0x07efe9a1) /* 0.496072418 */, 14 }, + /* 857 */ { MAD_F(0x07f31405) /* 0.496845266 */, 14 }, + /* 858 */ { MAD_F(0x07f63eba) /* 0.497618416 */, 14 }, + /* 859 */ { MAD_F(0x07f969c0) /* 0.498391866 */, 14 }, + /* 860 */ { MAD_F(0x07fc9516) /* 0.499165616 */, 14 }, + /* 861 */ { MAD_F(0x07ffc0bc) /* 0.499939666 */, 14 }, + /* 862 */ { MAD_F(0x04017659) /* 0.250357008 */, 15 }, + /* 863 */ { MAD_F(0x04030c7d) /* 0.250744333 */, 15 }, + + /* 864 */ { MAD_F(0x0404a2c9) /* 0.251131807 */, 15 }, + /* 865 */ { MAD_F(0x0406393d) /* 0.251519431 */, 15 }, + /* 866 */ { MAD_F(0x0407cfd9) /* 0.251907204 */, 15 }, + /* 867 */ { MAD_F(0x0409669d) /* 0.252295127 */, 15 }, + /* 868 */ { MAD_F(0x040afd89) /* 0.252683198 */, 15 }, + /* 869 */ { MAD_F(0x040c949e) /* 0.253071419 */, 15 }, + /* 870 */ { MAD_F(0x040e2bda) /* 0.253459789 */, 15 }, + /* 871 */ { MAD_F(0x040fc33e) /* 0.253848307 */, 15 }, + /* 872 */ { MAD_F(0x04115aca) /* 0.254236974 */, 15 }, + /* 873 */ { MAD_F(0x0412f27e) /* 0.254625790 */, 15 }, + /* 874 */ { MAD_F(0x04148a5a) /* 0.255014755 */, 15 }, + /* 875 */ { MAD_F(0x0416225d) /* 0.255403867 */, 15 }, + /* 876 */ { MAD_F(0x0417ba89) /* 0.255793128 */, 15 }, + /* 877 */ { MAD_F(0x041952dc) /* 0.256182537 */, 15 }, + /* 878 */ { MAD_F(0x041aeb57) /* 0.256572095 */, 15 }, + /* 879 */ { MAD_F(0x041c83fa) /* 0.256961800 */, 15 }, + + /* 880 */ { MAD_F(0x041e1cc4) /* 0.257351652 */, 15 }, + /* 881 */ { MAD_F(0x041fb5b6) /* 0.257741653 */, 15 }, + /* 882 */ { MAD_F(0x04214ed0) /* 0.258131801 */, 15 }, + /* 883 */ { MAD_F(0x0422e811) /* 0.258522097 */, 15 }, + /* 884 */ { MAD_F(0x04248179) /* 0.258912540 */, 15 }, + /* 885 */ { MAD_F(0x04261b0a) /* 0.259303130 */, 15 }, + /* 886 */ { MAD_F(0x0427b4c2) /* 0.259693868 */, 15 }, + /* 887 */ { MAD_F(0x04294ea1) /* 0.260084752 */, 15 }, + /* 888 */ { MAD_F(0x042ae8a7) /* 0.260475783 */, 15 }, + /* 889 */ { MAD_F(0x042c82d6) /* 0.260866961 */, 15 }, + /* 890 */ { MAD_F(0x042e1d2b) /* 0.261258286 */, 15 }, + /* 891 */ { MAD_F(0x042fb7a8) /* 0.261649758 */, 15 }, + /* 892 */ { MAD_F(0x0431524c) /* 0.262041376 */, 15 }, + /* 893 */ { MAD_F(0x0432ed17) /* 0.262433140 */, 15 }, + /* 894 */ { MAD_F(0x0434880a) /* 0.262825051 */, 15 }, + /* 895 */ { MAD_F(0x04362324) /* 0.263217107 */, 15 }, + + /* 896 */ { MAD_F(0x0437be65) /* 0.263609310 */, 15 }, + /* 897 */ { MAD_F(0x043959cd) /* 0.264001659 */, 15 }, + /* 898 */ { MAD_F(0x043af55d) /* 0.264394153 */, 15 }, + /* 899 */ { MAD_F(0x043c9113) /* 0.264786794 */, 15 }, + /* 900 */ { MAD_F(0x043e2cf1) /* 0.265179580 */, 15 }, + /* 901 */ { MAD_F(0x043fc8f6) /* 0.265572511 */, 15 }, + /* 902 */ { MAD_F(0x04416522) /* 0.265965588 */, 15 }, + /* 903 */ { MAD_F(0x04430174) /* 0.266358810 */, 15 }, + /* 904 */ { MAD_F(0x04449dee) /* 0.266752177 */, 15 }, + /* 905 */ { MAD_F(0x04463a8f) /* 0.267145689 */, 15 }, + /* 906 */ { MAD_F(0x0447d756) /* 0.267539347 */, 15 }, + /* 907 */ { MAD_F(0x04497445) /* 0.267933149 */, 15 }, + /* 908 */ { MAD_F(0x044b115a) /* 0.268327096 */, 15 }, + /* 909 */ { MAD_F(0x044cae96) /* 0.268721187 */, 15 }, + /* 910 */ { MAD_F(0x044e4bf9) /* 0.269115423 */, 15 }, + /* 911 */ { MAD_F(0x044fe983) /* 0.269509804 */, 15 }, + + /* 912 */ { MAD_F(0x04518733) /* 0.269904329 */, 15 }, + /* 913 */ { MAD_F(0x0453250a) /* 0.270298998 */, 15 }, + /* 914 */ { MAD_F(0x0454c308) /* 0.270693811 */, 15 }, + /* 915 */ { MAD_F(0x0456612d) /* 0.271088768 */, 15 }, + /* 916 */ { MAD_F(0x0457ff78) /* 0.271483869 */, 15 }, + /* 917 */ { MAD_F(0x04599dea) /* 0.271879114 */, 15 }, + /* 918 */ { MAD_F(0x045b3c82) /* 0.272274503 */, 15 }, + /* 919 */ { MAD_F(0x045cdb41) /* 0.272670035 */, 15 }, + /* 920 */ { MAD_F(0x045e7a26) /* 0.273065710 */, 15 }, + /* 921 */ { MAD_F(0x04601932) /* 0.273461530 */, 15 }, + /* 922 */ { MAD_F(0x0461b864) /* 0.273857492 */, 15 }, + /* 923 */ { MAD_F(0x046357bd) /* 0.274253597 */, 15 }, + /* 924 */ { MAD_F(0x0464f73c) /* 0.274649846 */, 15 }, + /* 925 */ { MAD_F(0x046696e2) /* 0.275046238 */, 15 }, + /* 926 */ { MAD_F(0x046836ae) /* 0.275442772 */, 15 }, + /* 927 */ { MAD_F(0x0469d6a0) /* 0.275839449 */, 15 }, + + /* 928 */ { MAD_F(0x046b76b9) /* 0.276236269 */, 15 }, + /* 929 */ { MAD_F(0x046d16f7) /* 0.276633232 */, 15 }, + /* 930 */ { MAD_F(0x046eb75c) /* 0.277030337 */, 15 }, + /* 931 */ { MAD_F(0x047057e8) /* 0.277427584 */, 15 }, + /* 932 */ { MAD_F(0x0471f899) /* 0.277824973 */, 15 }, + /* 933 */ { MAD_F(0x04739971) /* 0.278222505 */, 15 }, + /* 934 */ { MAD_F(0x04753a6f) /* 0.278620179 */, 15 }, + /* 935 */ { MAD_F(0x0476db92) /* 0.279017995 */, 15 }, + /* 936 */ { MAD_F(0x04787cdc) /* 0.279415952 */, 15 }, + /* 937 */ { MAD_F(0x047a1e4c) /* 0.279814051 */, 15 }, + /* 938 */ { MAD_F(0x047bbfe2) /* 0.280212292 */, 15 }, + /* 939 */ { MAD_F(0x047d619e) /* 0.280610675 */, 15 }, + /* 940 */ { MAD_F(0x047f0380) /* 0.281009199 */, 15 }, + /* 941 */ { MAD_F(0x0480a588) /* 0.281407864 */, 15 }, + /* 942 */ { MAD_F(0x048247b6) /* 0.281806670 */, 15 }, + /* 943 */ { MAD_F(0x0483ea0a) /* 0.282205618 */, 15 }, + + /* 944 */ { MAD_F(0x04858c83) /* 0.282604707 */, 15 }, + /* 945 */ { MAD_F(0x04872f22) /* 0.283003936 */, 15 }, + /* 946 */ { MAD_F(0x0488d1e8) /* 0.283403307 */, 15 }, + /* 947 */ { MAD_F(0x048a74d3) /* 0.283802818 */, 15 }, + /* 948 */ { MAD_F(0x048c17e3) /* 0.284202470 */, 15 }, + /* 949 */ { MAD_F(0x048dbb1a) /* 0.284602263 */, 15 }, + /* 950 */ { MAD_F(0x048f5e76) /* 0.285002195 */, 15 }, + /* 951 */ { MAD_F(0x049101f8) /* 0.285402269 */, 15 }, + /* 952 */ { MAD_F(0x0492a59f) /* 0.285802482 */, 15 }, + /* 953 */ { MAD_F(0x0494496c) /* 0.286202836 */, 15 }, + /* 954 */ { MAD_F(0x0495ed5f) /* 0.286603329 */, 15 }, + /* 955 */ { MAD_F(0x04979177) /* 0.287003963 */, 15 }, + /* 956 */ { MAD_F(0x049935b5) /* 0.287404737 */, 15 }, + /* 957 */ { MAD_F(0x049ada19) /* 0.287805650 */, 15 }, + /* 958 */ { MAD_F(0x049c7ea1) /* 0.288206703 */, 15 }, + /* 959 */ { MAD_F(0x049e2350) /* 0.288607895 */, 15 }, + + /* 960 */ { MAD_F(0x049fc824) /* 0.289009227 */, 15 }, + /* 961 */ { MAD_F(0x04a16d1d) /* 0.289410699 */, 15 }, + /* 962 */ { MAD_F(0x04a3123b) /* 0.289812309 */, 15 }, + /* 963 */ { MAD_F(0x04a4b77f) /* 0.290214059 */, 15 }, + /* 964 */ { MAD_F(0x04a65ce8) /* 0.290615948 */, 15 }, + /* 965 */ { MAD_F(0x04a80277) /* 0.291017976 */, 15 }, + /* 966 */ { MAD_F(0x04a9a82b) /* 0.291420143 */, 15 }, + /* 967 */ { MAD_F(0x04ab4e04) /* 0.291822449 */, 15 }, + /* 968 */ { MAD_F(0x04acf402) /* 0.292224893 */, 15 }, + /* 969 */ { MAD_F(0x04ae9a26) /* 0.292627476 */, 15 }, + /* 970 */ { MAD_F(0x04b0406e) /* 0.293030197 */, 15 }, + /* 971 */ { MAD_F(0x04b1e6dc) /* 0.293433057 */, 15 }, + /* 972 */ { MAD_F(0x04b38d6f) /* 0.293836055 */, 15 }, + /* 973 */ { MAD_F(0x04b53427) /* 0.294239192 */, 15 }, + /* 974 */ { MAD_F(0x04b6db05) /* 0.294642466 */, 15 }, + /* 975 */ { MAD_F(0x04b88207) /* 0.295045879 */, 15 }, + + /* 976 */ { MAD_F(0x04ba292e) /* 0.295449429 */, 15 }, + /* 977 */ { MAD_F(0x04bbd07a) /* 0.295853118 */, 15 }, + /* 978 */ { MAD_F(0x04bd77ec) /* 0.296256944 */, 15 }, + /* 979 */ { MAD_F(0x04bf1f82) /* 0.296660907 */, 15 }, + /* 980 */ { MAD_F(0x04c0c73d) /* 0.297065009 */, 15 }, + /* 981 */ { MAD_F(0x04c26f1d) /* 0.297469248 */, 15 }, + /* 982 */ { MAD_F(0x04c41722) /* 0.297873624 */, 15 }, + /* 983 */ { MAD_F(0x04c5bf4c) /* 0.298278137 */, 15 }, + /* 984 */ { MAD_F(0x04c7679a) /* 0.298682788 */, 15 }, + /* 985 */ { MAD_F(0x04c9100d) /* 0.299087576 */, 15 }, + /* 986 */ { MAD_F(0x04cab8a6) /* 0.299492500 */, 15 }, + /* 987 */ { MAD_F(0x04cc6163) /* 0.299897562 */, 15 }, + /* 988 */ { MAD_F(0x04ce0a44) /* 0.300302761 */, 15 }, + /* 989 */ { MAD_F(0x04cfb34b) /* 0.300708096 */, 15 }, + /* 990 */ { MAD_F(0x04d15c76) /* 0.301113568 */, 15 }, + /* 991 */ { MAD_F(0x04d305c5) /* 0.301519176 */, 15 }, + + /* 992 */ { MAD_F(0x04d4af3a) /* 0.301924921 */, 15 }, + /* 993 */ { MAD_F(0x04d658d2) /* 0.302330802 */, 15 }, + /* 994 */ { MAD_F(0x04d80290) /* 0.302736820 */, 15 }, + /* 995 */ { MAD_F(0x04d9ac72) /* 0.303142973 */, 15 }, + /* 996 */ { MAD_F(0x04db5679) /* 0.303549263 */, 15 }, + /* 997 */ { MAD_F(0x04dd00a4) /* 0.303955689 */, 15 }, + /* 998 */ { MAD_F(0x04deaaf3) /* 0.304362251 */, 15 }, + /* 999 */ { MAD_F(0x04e05567) /* 0.304768948 */, 15 }, + /* 1000 */ { MAD_F(0x04e20000) /* 0.305175781 */, 15 }, + /* 1001 */ { MAD_F(0x04e3aabd) /* 0.305582750 */, 15 }, + /* 1002 */ { MAD_F(0x04e5559e) /* 0.305989854 */, 15 }, + /* 1003 */ { MAD_F(0x04e700a3) /* 0.306397094 */, 15 }, + /* 1004 */ { MAD_F(0x04e8abcd) /* 0.306804470 */, 15 }, + /* 1005 */ { MAD_F(0x04ea571c) /* 0.307211980 */, 15 }, + /* 1006 */ { MAD_F(0x04ec028e) /* 0.307619626 */, 15 }, + /* 1007 */ { MAD_F(0x04edae25) /* 0.308027406 */, 15 }, + + /* 1008 */ { MAD_F(0x04ef59e0) /* 0.308435322 */, 15 }, + /* 1009 */ { MAD_F(0x04f105bf) /* 0.308843373 */, 15 }, + /* 1010 */ { MAD_F(0x04f2b1c3) /* 0.309251558 */, 15 }, + /* 1011 */ { MAD_F(0x04f45dea) /* 0.309659879 */, 15 }, + /* 1012 */ { MAD_F(0x04f60a36) /* 0.310068333 */, 15 }, + /* 1013 */ { MAD_F(0x04f7b6a6) /* 0.310476923 */, 15 }, + /* 1014 */ { MAD_F(0x04f9633a) /* 0.310885647 */, 15 }, + /* 1015 */ { MAD_F(0x04fb0ff2) /* 0.311294505 */, 15 }, + /* 1016 */ { MAD_F(0x04fcbcce) /* 0.311703498 */, 15 }, + /* 1017 */ { MAD_F(0x04fe69ce) /* 0.312112625 */, 15 }, + /* 1018 */ { MAD_F(0x050016f3) /* 0.312521885 */, 15 }, + /* 1019 */ { MAD_F(0x0501c43b) /* 0.312931280 */, 15 }, + /* 1020 */ { MAD_F(0x050371a7) /* 0.313340809 */, 15 }, + /* 1021 */ { MAD_F(0x05051f37) /* 0.313750472 */, 15 }, + /* 1022 */ { MAD_F(0x0506cceb) /* 0.314160269 */, 15 }, + /* 1023 */ { MAD_F(0x05087ac2) /* 0.314570199 */, 15 }, + + /* 1024 */ { MAD_F(0x050a28be) /* 0.314980262 */, 15 }, + /* 1025 */ { MAD_F(0x050bd6de) /* 0.315390460 */, 15 }, + /* 1026 */ { MAD_F(0x050d8521) /* 0.315800790 */, 15 }, + /* 1027 */ { MAD_F(0x050f3388) /* 0.316211255 */, 15 }, + /* 1028 */ { MAD_F(0x0510e213) /* 0.316621852 */, 15 }, + /* 1029 */ { MAD_F(0x051290c2) /* 0.317032582 */, 15 }, + /* 1030 */ { MAD_F(0x05143f94) /* 0.317443446 */, 15 }, + /* 1031 */ { MAD_F(0x0515ee8a) /* 0.317854442 */, 15 }, + /* 1032 */ { MAD_F(0x05179da4) /* 0.318265572 */, 15 }, + /* 1033 */ { MAD_F(0x05194ce1) /* 0.318676834 */, 15 }, + /* 1034 */ { MAD_F(0x051afc42) /* 0.319088229 */, 15 }, + /* 1035 */ { MAD_F(0x051cabc7) /* 0.319499756 */, 15 }, + /* 1036 */ { MAD_F(0x051e5b6f) /* 0.319911417 */, 15 }, + /* 1037 */ { MAD_F(0x05200b3a) /* 0.320323209 */, 15 }, + /* 1038 */ { MAD_F(0x0521bb2a) /* 0.320735134 */, 15 }, + /* 1039 */ { MAD_F(0x05236b3d) /* 0.321147192 */, 15 }, + + /* 1040 */ { MAD_F(0x05251b73) /* 0.321559381 */, 15 }, + /* 1041 */ { MAD_F(0x0526cbcd) /* 0.321971703 */, 15 }, + /* 1042 */ { MAD_F(0x05287c4a) /* 0.322384156 */, 15 }, + /* 1043 */ { MAD_F(0x052a2cea) /* 0.322796742 */, 15 }, + /* 1044 */ { MAD_F(0x052bddae) /* 0.323209460 */, 15 }, + /* 1045 */ { MAD_F(0x052d8e96) /* 0.323622309 */, 15 }, + /* 1046 */ { MAD_F(0x052f3fa1) /* 0.324035290 */, 15 }, + /* 1047 */ { MAD_F(0x0530f0cf) /* 0.324448403 */, 15 }, + /* 1048 */ { MAD_F(0x0532a220) /* 0.324861647 */, 15 }, + /* 1049 */ { MAD_F(0x05345395) /* 0.325275023 */, 15 }, + /* 1050 */ { MAD_F(0x0536052d) /* 0.325688530 */, 15 }, + /* 1051 */ { MAD_F(0x0537b6e8) /* 0.326102168 */, 15 }, + /* 1052 */ { MAD_F(0x053968c6) /* 0.326515938 */, 15 }, + /* 1053 */ { MAD_F(0x053b1ac8) /* 0.326929839 */, 15 }, + /* 1054 */ { MAD_F(0x053ccced) /* 0.327343870 */, 15 }, + /* 1055 */ { MAD_F(0x053e7f35) /* 0.327758033 */, 15 }, + + /* 1056 */ { MAD_F(0x054031a0) /* 0.328172327 */, 15 }, + /* 1057 */ { MAD_F(0x0541e42e) /* 0.328586751 */, 15 }, + /* 1058 */ { MAD_F(0x054396df) /* 0.329001306 */, 15 }, + /* 1059 */ { MAD_F(0x054549b4) /* 0.329415992 */, 15 }, + /* 1060 */ { MAD_F(0x0546fcab) /* 0.329830808 */, 15 }, + /* 1061 */ { MAD_F(0x0548afc6) /* 0.330245755 */, 15 }, + /* 1062 */ { MAD_F(0x054a6303) /* 0.330660832 */, 15 }, + /* 1063 */ { MAD_F(0x054c1663) /* 0.331076039 */, 15 }, + /* 1064 */ { MAD_F(0x054dc9e7) /* 0.331491377 */, 15 }, + /* 1065 */ { MAD_F(0x054f7d8d) /* 0.331906845 */, 15 }, + /* 1066 */ { MAD_F(0x05513156) /* 0.332322443 */, 15 }, + /* 1067 */ { MAD_F(0x0552e542) /* 0.332738170 */, 15 }, + /* 1068 */ { MAD_F(0x05549951) /* 0.333154028 */, 15 }, + /* 1069 */ { MAD_F(0x05564d83) /* 0.333570016 */, 15 }, + /* 1070 */ { MAD_F(0x055801d8) /* 0.333986133 */, 15 }, + /* 1071 */ { MAD_F(0x0559b64f) /* 0.334402380 */, 15 }, + + /* 1072 */ { MAD_F(0x055b6ae9) /* 0.334818756 */, 15 }, + /* 1073 */ { MAD_F(0x055d1fa6) /* 0.335235262 */, 15 }, + /* 1074 */ { MAD_F(0x055ed486) /* 0.335651898 */, 15 }, + /* 1075 */ { MAD_F(0x05608988) /* 0.336068662 */, 15 }, + /* 1076 */ { MAD_F(0x05623ead) /* 0.336485556 */, 15 }, + /* 1077 */ { MAD_F(0x0563f3f5) /* 0.336902579 */, 15 }, + /* 1078 */ { MAD_F(0x0565a960) /* 0.337319732 */, 15 }, + /* 1079 */ { MAD_F(0x05675eed) /* 0.337737013 */, 15 }, + /* 1080 */ { MAD_F(0x0569149c) /* 0.338154423 */, 15 }, + /* 1081 */ { MAD_F(0x056aca6f) /* 0.338571962 */, 15 }, + /* 1082 */ { MAD_F(0x056c8064) /* 0.338989630 */, 15 }, + /* 1083 */ { MAD_F(0x056e367b) /* 0.339407426 */, 15 }, + /* 1084 */ { MAD_F(0x056fecb5) /* 0.339825351 */, 15 }, + /* 1085 */ { MAD_F(0x0571a311) /* 0.340243405 */, 15 }, + /* 1086 */ { MAD_F(0x05735990) /* 0.340661587 */, 15 }, + /* 1087 */ { MAD_F(0x05751032) /* 0.341079898 */, 15 }, + + /* 1088 */ { MAD_F(0x0576c6f5) /* 0.341498336 */, 15 }, + /* 1089 */ { MAD_F(0x05787ddc) /* 0.341916903 */, 15 }, + /* 1090 */ { MAD_F(0x057a34e4) /* 0.342335598 */, 15 }, + /* 1091 */ { MAD_F(0x057bec0f) /* 0.342754421 */, 15 }, + /* 1092 */ { MAD_F(0x057da35d) /* 0.343173373 */, 15 }, + /* 1093 */ { MAD_F(0x057f5acc) /* 0.343592452 */, 15 }, + /* 1094 */ { MAD_F(0x0581125e) /* 0.344011659 */, 15 }, + /* 1095 */ { MAD_F(0x0582ca12) /* 0.344430993 */, 15 }, + /* 1096 */ { MAD_F(0x058481e9) /* 0.344850455 */, 15 }, + /* 1097 */ { MAD_F(0x058639e2) /* 0.345270045 */, 15 }, + /* 1098 */ { MAD_F(0x0587f1fd) /* 0.345689763 */, 15 }, + /* 1099 */ { MAD_F(0x0589aa3a) /* 0.346109608 */, 15 }, + /* 1100 */ { MAD_F(0x058b629a) /* 0.346529580 */, 15 }, + /* 1101 */ { MAD_F(0x058d1b1b) /* 0.346949679 */, 15 }, + /* 1102 */ { MAD_F(0x058ed3bf) /* 0.347369906 */, 15 }, + /* 1103 */ { MAD_F(0x05908c85) /* 0.347790260 */, 15 }, + + /* 1104 */ { MAD_F(0x0592456d) /* 0.348210741 */, 15 }, + /* 1105 */ { MAD_F(0x0593fe77) /* 0.348631348 */, 15 }, + /* 1106 */ { MAD_F(0x0595b7a3) /* 0.349052083 */, 15 }, + /* 1107 */ { MAD_F(0x059770f1) /* 0.349472945 */, 15 }, + /* 1108 */ { MAD_F(0x05992a61) /* 0.349893933 */, 15 }, + /* 1109 */ { MAD_F(0x059ae3f3) /* 0.350315048 */, 15 }, + /* 1110 */ { MAD_F(0x059c9da8) /* 0.350736290 */, 15 }, + /* 1111 */ { MAD_F(0x059e577e) /* 0.351157658 */, 15 }, + /* 1112 */ { MAD_F(0x05a01176) /* 0.351579152 */, 15 }, + /* 1113 */ { MAD_F(0x05a1cb90) /* 0.352000773 */, 15 }, + /* 1114 */ { MAD_F(0x05a385cc) /* 0.352422520 */, 15 }, + /* 1115 */ { MAD_F(0x05a5402a) /* 0.352844394 */, 15 }, + /* 1116 */ { MAD_F(0x05a6faa9) /* 0.353266393 */, 15 }, + /* 1117 */ { MAD_F(0x05a8b54b) /* 0.353688519 */, 15 }, + /* 1118 */ { MAD_F(0x05aa700e) /* 0.354110771 */, 15 }, + /* 1119 */ { MAD_F(0x05ac2af3) /* 0.354533148 */, 15 }, + + /* 1120 */ { MAD_F(0x05ade5fa) /* 0.354955651 */, 15 }, + /* 1121 */ { MAD_F(0x05afa123) /* 0.355378281 */, 15 }, + /* 1122 */ { MAD_F(0x05b15c6d) /* 0.355801035 */, 15 }, + /* 1123 */ { MAD_F(0x05b317d9) /* 0.356223916 */, 15 }, + /* 1124 */ { MAD_F(0x05b4d367) /* 0.356646922 */, 15 }, + /* 1125 */ { MAD_F(0x05b68f16) /* 0.357070053 */, 15 }, + /* 1126 */ { MAD_F(0x05b84ae7) /* 0.357493310 */, 15 }, + /* 1127 */ { MAD_F(0x05ba06da) /* 0.357916692 */, 15 }, + /* 1128 */ { MAD_F(0x05bbc2ef) /* 0.358340200 */, 15 }, + /* 1129 */ { MAD_F(0x05bd7f25) /* 0.358763832 */, 15 }, + /* 1130 */ { MAD_F(0x05bf3b7c) /* 0.359187590 */, 15 }, + /* 1131 */ { MAD_F(0x05c0f7f5) /* 0.359611472 */, 15 }, + /* 1132 */ { MAD_F(0x05c2b490) /* 0.360035480 */, 15 }, + /* 1133 */ { MAD_F(0x05c4714c) /* 0.360459613 */, 15 }, + /* 1134 */ { MAD_F(0x05c62e2a) /* 0.360883870 */, 15 }, + /* 1135 */ { MAD_F(0x05c7eb29) /* 0.361308252 */, 15 }, + + /* 1136 */ { MAD_F(0x05c9a84a) /* 0.361732758 */, 15 }, + /* 1137 */ { MAD_F(0x05cb658c) /* 0.362157390 */, 15 }, + /* 1138 */ { MAD_F(0x05cd22ef) /* 0.362582145 */, 15 }, + /* 1139 */ { MAD_F(0x05cee074) /* 0.363007026 */, 15 }, + /* 1140 */ { MAD_F(0x05d09e1b) /* 0.363432030 */, 15 }, + /* 1141 */ { MAD_F(0x05d25be2) /* 0.363857159 */, 15 }, + /* 1142 */ { MAD_F(0x05d419cb) /* 0.364282412 */, 15 }, + /* 1143 */ { MAD_F(0x05d5d7d5) /* 0.364707789 */, 15 }, + /* 1144 */ { MAD_F(0x05d79601) /* 0.365133291 */, 15 }, + /* 1145 */ { MAD_F(0x05d9544e) /* 0.365558916 */, 15 }, + /* 1146 */ { MAD_F(0x05db12bc) /* 0.365984665 */, 15 }, + /* 1147 */ { MAD_F(0x05dcd14c) /* 0.366410538 */, 15 }, + /* 1148 */ { MAD_F(0x05de8ffc) /* 0.366836535 */, 15 }, + /* 1149 */ { MAD_F(0x05e04ece) /* 0.367262655 */, 15 }, + /* 1150 */ { MAD_F(0x05e20dc1) /* 0.367688900 */, 15 }, + /* 1151 */ { MAD_F(0x05e3ccd5) /* 0.368115267 */, 15 }, + + /* 1152 */ { MAD_F(0x05e58c0b) /* 0.368541759 */, 15 }, + /* 1153 */ { MAD_F(0x05e74b61) /* 0.368968373 */, 15 }, + /* 1154 */ { MAD_F(0x05e90ad9) /* 0.369395111 */, 15 }, + /* 1155 */ { MAD_F(0x05eaca72) /* 0.369821973 */, 15 }, + /* 1156 */ { MAD_F(0x05ec8a2b) /* 0.370248957 */, 15 }, + /* 1157 */ { MAD_F(0x05ee4a06) /* 0.370676065 */, 15 }, + /* 1158 */ { MAD_F(0x05f00a02) /* 0.371103295 */, 15 }, + /* 1159 */ { MAD_F(0x05f1ca1f) /* 0.371530649 */, 15 }, + /* 1160 */ { MAD_F(0x05f38a5d) /* 0.371958126 */, 15 }, + /* 1161 */ { MAD_F(0x05f54abc) /* 0.372385725 */, 15 }, + /* 1162 */ { MAD_F(0x05f70b3c) /* 0.372813448 */, 15 }, + /* 1163 */ { MAD_F(0x05f8cbdc) /* 0.373241292 */, 15 }, + /* 1164 */ { MAD_F(0x05fa8c9e) /* 0.373669260 */, 15 }, + /* 1165 */ { MAD_F(0x05fc4d81) /* 0.374097350 */, 15 }, + /* 1166 */ { MAD_F(0x05fe0e84) /* 0.374525563 */, 15 }, + /* 1167 */ { MAD_F(0x05ffcfa8) /* 0.374953898 */, 15 }, + + /* 1168 */ { MAD_F(0x060190ee) /* 0.375382356 */, 15 }, + /* 1169 */ { MAD_F(0x06035254) /* 0.375810936 */, 15 }, + /* 1170 */ { MAD_F(0x060513da) /* 0.376239638 */, 15 }, + /* 1171 */ { MAD_F(0x0606d582) /* 0.376668462 */, 15 }, + /* 1172 */ { MAD_F(0x0608974a) /* 0.377097408 */, 15 }, + /* 1173 */ { MAD_F(0x060a5934) /* 0.377526476 */, 15 }, + /* 1174 */ { MAD_F(0x060c1b3d) /* 0.377955667 */, 15 }, + /* 1175 */ { MAD_F(0x060ddd68) /* 0.378384979 */, 15 }, + /* 1176 */ { MAD_F(0x060f9fb3) /* 0.378814413 */, 15 }, + /* 1177 */ { MAD_F(0x0611621f) /* 0.379243968 */, 15 }, + /* 1178 */ { MAD_F(0x061324ac) /* 0.379673646 */, 15 }, + /* 1179 */ { MAD_F(0x0614e759) /* 0.380103444 */, 15 }, + /* 1180 */ { MAD_F(0x0616aa27) /* 0.380533365 */, 15 }, + /* 1181 */ { MAD_F(0x06186d16) /* 0.380963407 */, 15 }, + /* 1182 */ { MAD_F(0x061a3025) /* 0.381393570 */, 15 }, + /* 1183 */ { MAD_F(0x061bf354) /* 0.381823855 */, 15 }, + + /* 1184 */ { MAD_F(0x061db6a5) /* 0.382254261 */, 15 }, + /* 1185 */ { MAD_F(0x061f7a15) /* 0.382684788 */, 15 }, + /* 1186 */ { MAD_F(0x06213da7) /* 0.383115436 */, 15 }, + /* 1187 */ { MAD_F(0x06230158) /* 0.383546205 */, 15 }, + /* 1188 */ { MAD_F(0x0624c52a) /* 0.383977096 */, 15 }, + /* 1189 */ { MAD_F(0x0626891d) /* 0.384408107 */, 15 }, + /* 1190 */ { MAD_F(0x06284d30) /* 0.384839239 */, 15 }, + /* 1191 */ { MAD_F(0x062a1164) /* 0.385270492 */, 15 }, + /* 1192 */ { MAD_F(0x062bd5b8) /* 0.385701865 */, 15 }, + /* 1193 */ { MAD_F(0x062d9a2c) /* 0.386133359 */, 15 }, + /* 1194 */ { MAD_F(0x062f5ec1) /* 0.386564974 */, 15 }, + /* 1195 */ { MAD_F(0x06312376) /* 0.386996709 */, 15 }, + /* 1196 */ { MAD_F(0x0632e84b) /* 0.387428565 */, 15 }, + /* 1197 */ { MAD_F(0x0634ad41) /* 0.387860541 */, 15 }, + /* 1198 */ { MAD_F(0x06367257) /* 0.388292637 */, 15 }, + /* 1199 */ { MAD_F(0x0638378d) /* 0.388724854 */, 15 }, + + /* 1200 */ { MAD_F(0x0639fce4) /* 0.389157191 */, 15 }, + /* 1201 */ { MAD_F(0x063bc25b) /* 0.389589648 */, 15 }, + /* 1202 */ { MAD_F(0x063d87f2) /* 0.390022225 */, 15 }, + /* 1203 */ { MAD_F(0x063f4da9) /* 0.390454922 */, 15 }, + /* 1204 */ { MAD_F(0x06411380) /* 0.390887739 */, 15 }, + /* 1205 */ { MAD_F(0x0642d978) /* 0.391320675 */, 15 }, + /* 1206 */ { MAD_F(0x06449f8f) /* 0.391753732 */, 15 }, + /* 1207 */ { MAD_F(0x064665c7) /* 0.392186908 */, 15 }, + /* 1208 */ { MAD_F(0x06482c1f) /* 0.392620204 */, 15 }, + /* 1209 */ { MAD_F(0x0649f297) /* 0.393053619 */, 15 }, + /* 1210 */ { MAD_F(0x064bb92f) /* 0.393487154 */, 15 }, + /* 1211 */ { MAD_F(0x064d7fe8) /* 0.393920808 */, 15 }, + /* 1212 */ { MAD_F(0x064f46c0) /* 0.394354582 */, 15 }, + /* 1213 */ { MAD_F(0x06510db8) /* 0.394788475 */, 15 }, + /* 1214 */ { MAD_F(0x0652d4d0) /* 0.395222488 */, 15 }, + /* 1215 */ { MAD_F(0x06549c09) /* 0.395656619 */, 15 }, + + /* 1216 */ { MAD_F(0x06566361) /* 0.396090870 */, 15 }, + /* 1217 */ { MAD_F(0x06582ad9) /* 0.396525239 */, 15 }, + /* 1218 */ { MAD_F(0x0659f271) /* 0.396959728 */, 15 }, + /* 1219 */ { MAD_F(0x065bba29) /* 0.397394336 */, 15 }, + /* 1220 */ { MAD_F(0x065d8201) /* 0.397829062 */, 15 }, + /* 1221 */ { MAD_F(0x065f49f9) /* 0.398263907 */, 15 }, + /* 1222 */ { MAD_F(0x06611211) /* 0.398698871 */, 15 }, + /* 1223 */ { MAD_F(0x0662da49) /* 0.399133954 */, 15 }, + /* 1224 */ { MAD_F(0x0664a2a0) /* 0.399569155 */, 15 }, + /* 1225 */ { MAD_F(0x06666b17) /* 0.400004475 */, 15 }, + /* 1226 */ { MAD_F(0x066833ae) /* 0.400439913 */, 15 }, + /* 1227 */ { MAD_F(0x0669fc65) /* 0.400875470 */, 15 }, + /* 1228 */ { MAD_F(0x066bc53c) /* 0.401311145 */, 15 }, + /* 1229 */ { MAD_F(0x066d8e32) /* 0.401746938 */, 15 }, + /* 1230 */ { MAD_F(0x066f5748) /* 0.402182850 */, 15 }, + /* 1231 */ { MAD_F(0x0671207e) /* 0.402618879 */, 15 }, + + /* 1232 */ { MAD_F(0x0672e9d4) /* 0.403055027 */, 15 }, + /* 1233 */ { MAD_F(0x0674b349) /* 0.403491293 */, 15 }, + /* 1234 */ { MAD_F(0x06767cde) /* 0.403927676 */, 15 }, + /* 1235 */ { MAD_F(0x06784692) /* 0.404364178 */, 15 }, + /* 1236 */ { MAD_F(0x067a1066) /* 0.404800797 */, 15 }, + /* 1237 */ { MAD_F(0x067bda5a) /* 0.405237535 */, 15 }, + /* 1238 */ { MAD_F(0x067da46d) /* 0.405674390 */, 15 }, + /* 1239 */ { MAD_F(0x067f6ea0) /* 0.406111362 */, 15 }, + /* 1240 */ { MAD_F(0x068138f3) /* 0.406548452 */, 15 }, + /* 1241 */ { MAD_F(0x06830365) /* 0.406985660 */, 15 }, + /* 1242 */ { MAD_F(0x0684cdf6) /* 0.407422985 */, 15 }, + /* 1243 */ { MAD_F(0x068698a8) /* 0.407860427 */, 15 }, + /* 1244 */ { MAD_F(0x06886378) /* 0.408297987 */, 15 }, + /* 1245 */ { MAD_F(0x068a2e68) /* 0.408735664 */, 15 }, + /* 1246 */ { MAD_F(0x068bf978) /* 0.409173458 */, 15 }, + /* 1247 */ { MAD_F(0x068dc4a7) /* 0.409611370 */, 15 }, + + /* 1248 */ { MAD_F(0x068f8ff5) /* 0.410049398 */, 15 }, + /* 1249 */ { MAD_F(0x06915b63) /* 0.410487544 */, 15 }, + /* 1250 */ { MAD_F(0x069326f0) /* 0.410925806 */, 15 }, + /* 1251 */ { MAD_F(0x0694f29c) /* 0.411364185 */, 15 }, + /* 1252 */ { MAD_F(0x0696be68) /* 0.411802681 */, 15 }, + /* 1253 */ { MAD_F(0x06988a54) /* 0.412241294 */, 15 }, + /* 1254 */ { MAD_F(0x069a565e) /* 0.412680024 */, 15 }, + /* 1255 */ { MAD_F(0x069c2288) /* 0.413118870 */, 15 }, + /* 1256 */ { MAD_F(0x069deed1) /* 0.413557833 */, 15 }, + /* 1257 */ { MAD_F(0x069fbb3a) /* 0.413996912 */, 15 }, + /* 1258 */ { MAD_F(0x06a187c1) /* 0.414436108 */, 15 }, + /* 1259 */ { MAD_F(0x06a35468) /* 0.414875420 */, 15 }, + /* 1260 */ { MAD_F(0x06a5212f) /* 0.415314849 */, 15 }, + /* 1261 */ { MAD_F(0x06a6ee14) /* 0.415754393 */, 15 }, + /* 1262 */ { MAD_F(0x06a8bb18) /* 0.416194054 */, 15 }, + /* 1263 */ { MAD_F(0x06aa883c) /* 0.416633831 */, 15 }, + + /* 1264 */ { MAD_F(0x06ac557f) /* 0.417073724 */, 15 }, + /* 1265 */ { MAD_F(0x06ae22e1) /* 0.417513734 */, 15 }, + /* 1266 */ { MAD_F(0x06aff062) /* 0.417953859 */, 15 }, + /* 1267 */ { MAD_F(0x06b1be03) /* 0.418394100 */, 15 }, + /* 1268 */ { MAD_F(0x06b38bc2) /* 0.418834457 */, 15 }, + /* 1269 */ { MAD_F(0x06b559a1) /* 0.419274929 */, 15 }, + /* 1270 */ { MAD_F(0x06b7279e) /* 0.419715518 */, 15 }, + /* 1271 */ { MAD_F(0x06b8f5bb) /* 0.420156222 */, 15 }, + /* 1272 */ { MAD_F(0x06bac3f6) /* 0.420597041 */, 15 }, + /* 1273 */ { MAD_F(0x06bc9251) /* 0.421037977 */, 15 }, + /* 1274 */ { MAD_F(0x06be60cb) /* 0.421479027 */, 15 }, + /* 1275 */ { MAD_F(0x06c02f63) /* 0.421920193 */, 15 }, + /* 1276 */ { MAD_F(0x06c1fe1b) /* 0.422361475 */, 15 }, + /* 1277 */ { MAD_F(0x06c3ccf1) /* 0.422802871 */, 15 }, + /* 1278 */ { MAD_F(0x06c59be7) /* 0.423244383 */, 15 }, + /* 1279 */ { MAD_F(0x06c76afb) /* 0.423686010 */, 15 }, + + /* 1280 */ { MAD_F(0x06c93a2e) /* 0.424127753 */, 15 }, + /* 1281 */ { MAD_F(0x06cb0981) /* 0.424569610 */, 15 }, + /* 1282 */ { MAD_F(0x06ccd8f2) /* 0.425011582 */, 15 }, + /* 1283 */ { MAD_F(0x06cea881) /* 0.425453669 */, 15 }, + /* 1284 */ { MAD_F(0x06d07830) /* 0.425895871 */, 15 }, + /* 1285 */ { MAD_F(0x06d247fe) /* 0.426338188 */, 15 }, + /* 1286 */ { MAD_F(0x06d417ea) /* 0.426780620 */, 15 }, + /* 1287 */ { MAD_F(0x06d5e7f5) /* 0.427223166 */, 15 }, + /* 1288 */ { MAD_F(0x06d7b81f) /* 0.427665827 */, 15 }, + /* 1289 */ { MAD_F(0x06d98868) /* 0.428108603 */, 15 }, + /* 1290 */ { MAD_F(0x06db58cf) /* 0.428551493 */, 15 }, + /* 1291 */ { MAD_F(0x06dd2955) /* 0.428994497 */, 15 }, + /* 1292 */ { MAD_F(0x06def9fa) /* 0.429437616 */, 15 }, + /* 1293 */ { MAD_F(0x06e0cabe) /* 0.429880849 */, 15 }, + /* 1294 */ { MAD_F(0x06e29ba0) /* 0.430324197 */, 15 }, + /* 1295 */ { MAD_F(0x06e46ca1) /* 0.430767659 */, 15 }, + + /* 1296 */ { MAD_F(0x06e63dc0) /* 0.431211234 */, 15 }, + /* 1297 */ { MAD_F(0x06e80efe) /* 0.431654924 */, 15 }, + /* 1298 */ { MAD_F(0x06e9e05b) /* 0.432098728 */, 15 }, + /* 1299 */ { MAD_F(0x06ebb1d6) /* 0.432542647 */, 15 }, + /* 1300 */ { MAD_F(0x06ed8370) /* 0.432986678 */, 15 }, + /* 1301 */ { MAD_F(0x06ef5529) /* 0.433430824 */, 15 }, + /* 1302 */ { MAD_F(0x06f12700) /* 0.433875084 */, 15 }, + /* 1303 */ { MAD_F(0x06f2f8f5) /* 0.434319457 */, 15 }, + /* 1304 */ { MAD_F(0x06f4cb09) /* 0.434763944 */, 15 }, + /* 1305 */ { MAD_F(0x06f69d3c) /* 0.435208545 */, 15 }, + /* 1306 */ { MAD_F(0x06f86f8d) /* 0.435653259 */, 15 }, + /* 1307 */ { MAD_F(0x06fa41fd) /* 0.436098087 */, 15 }, + /* 1308 */ { MAD_F(0x06fc148b) /* 0.436543029 */, 15 }, + /* 1309 */ { MAD_F(0x06fde737) /* 0.436988083 */, 15 }, + /* 1310 */ { MAD_F(0x06ffba02) /* 0.437433251 */, 15 }, + /* 1311 */ { MAD_F(0x07018ceb) /* 0.437878533 */, 15 }, + + /* 1312 */ { MAD_F(0x07035ff3) /* 0.438323927 */, 15 }, + /* 1313 */ { MAD_F(0x07053319) /* 0.438769435 */, 15 }, + /* 1314 */ { MAD_F(0x0707065d) /* 0.439215056 */, 15 }, + /* 1315 */ { MAD_F(0x0708d9c0) /* 0.439660790 */, 15 }, + /* 1316 */ { MAD_F(0x070aad41) /* 0.440106636 */, 15 }, + /* 1317 */ { MAD_F(0x070c80e1) /* 0.440552596 */, 15 }, + /* 1318 */ { MAD_F(0x070e549f) /* 0.440998669 */, 15 }, + /* 1319 */ { MAD_F(0x0710287b) /* 0.441444855 */, 15 }, + /* 1320 */ { MAD_F(0x0711fc75) /* 0.441891153 */, 15 }, + /* 1321 */ { MAD_F(0x0713d08d) /* 0.442337564 */, 15 }, + /* 1322 */ { MAD_F(0x0715a4c4) /* 0.442784088 */, 15 }, + /* 1323 */ { MAD_F(0x07177919) /* 0.443230724 */, 15 }, + /* 1324 */ { MAD_F(0x07194d8c) /* 0.443677473 */, 15 }, + /* 1325 */ { MAD_F(0x071b221e) /* 0.444124334 */, 15 }, + /* 1326 */ { MAD_F(0x071cf6ce) /* 0.444571308 */, 15 }, + /* 1327 */ { MAD_F(0x071ecb9b) /* 0.445018394 */, 15 }, + + /* 1328 */ { MAD_F(0x0720a087) /* 0.445465593 */, 15 }, + /* 1329 */ { MAD_F(0x07227591) /* 0.445912903 */, 15 }, + /* 1330 */ { MAD_F(0x07244ab9) /* 0.446360326 */, 15 }, + /* 1331 */ { MAD_F(0x07262000) /* 0.446807861 */, 15 }, + /* 1332 */ { MAD_F(0x0727f564) /* 0.447255509 */, 15 }, + /* 1333 */ { MAD_F(0x0729cae7) /* 0.447703268 */, 15 }, + /* 1334 */ { MAD_F(0x072ba087) /* 0.448151139 */, 15 }, + /* 1335 */ { MAD_F(0x072d7646) /* 0.448599122 */, 15 }, + /* 1336 */ { MAD_F(0x072f4c22) /* 0.449047217 */, 15 }, + /* 1337 */ { MAD_F(0x0731221d) /* 0.449495424 */, 15 }, + /* 1338 */ { MAD_F(0x0732f835) /* 0.449943742 */, 15 }, + /* 1339 */ { MAD_F(0x0734ce6c) /* 0.450392173 */, 15 }, + /* 1340 */ { MAD_F(0x0736a4c1) /* 0.450840715 */, 15 }, + /* 1341 */ { MAD_F(0x07387b33) /* 0.451289368 */, 15 }, + /* 1342 */ { MAD_F(0x073a51c4) /* 0.451738133 */, 15 }, + /* 1343 */ { MAD_F(0x073c2872) /* 0.452187010 */, 15 }, + + /* 1344 */ { MAD_F(0x073dff3e) /* 0.452635998 */, 15 }, + /* 1345 */ { MAD_F(0x073fd628) /* 0.453085097 */, 15 }, + /* 1346 */ { MAD_F(0x0741ad30) /* 0.453534308 */, 15 }, + /* 1347 */ { MAD_F(0x07438456) /* 0.453983630 */, 15 }, + /* 1348 */ { MAD_F(0x07455b9a) /* 0.454433063 */, 15 }, + /* 1349 */ { MAD_F(0x074732fc) /* 0.454882607 */, 15 }, + /* 1350 */ { MAD_F(0x07490a7b) /* 0.455332262 */, 15 }, + /* 1351 */ { MAD_F(0x074ae218) /* 0.455782029 */, 15 }, + /* 1352 */ { MAD_F(0x074cb9d3) /* 0.456231906 */, 15 }, + /* 1353 */ { MAD_F(0x074e91ac) /* 0.456681894 */, 15 }, + /* 1354 */ { MAD_F(0x075069a3) /* 0.457131993 */, 15 }, + /* 1355 */ { MAD_F(0x075241b7) /* 0.457582203 */, 15 }, + /* 1356 */ { MAD_F(0x075419e9) /* 0.458032524 */, 15 }, + /* 1357 */ { MAD_F(0x0755f239) /* 0.458482956 */, 15 }, + /* 1358 */ { MAD_F(0x0757caa7) /* 0.458933498 */, 15 }, + /* 1359 */ { MAD_F(0x0759a332) /* 0.459384151 */, 15 }, + + /* 1360 */ { MAD_F(0x075b7bdb) /* 0.459834914 */, 15 }, + /* 1361 */ { MAD_F(0x075d54a1) /* 0.460285788 */, 15 }, + /* 1362 */ { MAD_F(0x075f2d85) /* 0.460736772 */, 15 }, + /* 1363 */ { MAD_F(0x07610687) /* 0.461187867 */, 15 }, + /* 1364 */ { MAD_F(0x0762dfa6) /* 0.461639071 */, 15 }, + /* 1365 */ { MAD_F(0x0764b8e3) /* 0.462090387 */, 15 }, + /* 1366 */ { MAD_F(0x0766923e) /* 0.462541812 */, 15 }, + /* 1367 */ { MAD_F(0x07686bb6) /* 0.462993348 */, 15 }, + /* 1368 */ { MAD_F(0x076a454c) /* 0.463444993 */, 15 }, + /* 1369 */ { MAD_F(0x076c1eff) /* 0.463896749 */, 15 }, + /* 1370 */ { MAD_F(0x076df8d0) /* 0.464348615 */, 15 }, + /* 1371 */ { MAD_F(0x076fd2be) /* 0.464800591 */, 15 }, + /* 1372 */ { MAD_F(0x0771acca) /* 0.465252676 */, 15 }, + /* 1373 */ { MAD_F(0x077386f3) /* 0.465704872 */, 15 }, + /* 1374 */ { MAD_F(0x0775613a) /* 0.466157177 */, 15 }, + /* 1375 */ { MAD_F(0x07773b9e) /* 0.466609592 */, 15 }, + + /* 1376 */ { MAD_F(0x07791620) /* 0.467062117 */, 15 }, + /* 1377 */ { MAD_F(0x077af0bf) /* 0.467514751 */, 15 }, + /* 1378 */ { MAD_F(0x077ccb7c) /* 0.467967495 */, 15 }, + /* 1379 */ { MAD_F(0x077ea656) /* 0.468420349 */, 15 }, + /* 1380 */ { MAD_F(0x0780814d) /* 0.468873312 */, 15 }, + /* 1381 */ { MAD_F(0x07825c62) /* 0.469326384 */, 15 }, + /* 1382 */ { MAD_F(0x07843794) /* 0.469779566 */, 15 }, + /* 1383 */ { MAD_F(0x078612e3) /* 0.470232857 */, 15 }, + /* 1384 */ { MAD_F(0x0787ee50) /* 0.470686258 */, 15 }, + /* 1385 */ { MAD_F(0x0789c9da) /* 0.471139767 */, 15 }, + /* 1386 */ { MAD_F(0x078ba581) /* 0.471593386 */, 15 }, + /* 1387 */ { MAD_F(0x078d8146) /* 0.472047114 */, 15 }, + /* 1388 */ { MAD_F(0x078f5d28) /* 0.472500951 */, 15 }, + /* 1389 */ { MAD_F(0x07913927) /* 0.472954896 */, 15 }, + /* 1390 */ { MAD_F(0x07931543) /* 0.473408951 */, 15 }, + /* 1391 */ { MAD_F(0x0794f17d) /* 0.473863115 */, 15 }, + + /* 1392 */ { MAD_F(0x0796cdd4) /* 0.474317388 */, 15 }, + /* 1393 */ { MAD_F(0x0798aa48) /* 0.474771769 */, 15 }, + /* 1394 */ { MAD_F(0x079a86d9) /* 0.475226259 */, 15 }, + /* 1395 */ { MAD_F(0x079c6388) /* 0.475680858 */, 15 }, + /* 1396 */ { MAD_F(0x079e4053) /* 0.476135565 */, 15 }, + /* 1397 */ { MAD_F(0x07a01d3c) /* 0.476590381 */, 15 }, + /* 1398 */ { MAD_F(0x07a1fa42) /* 0.477045306 */, 15 }, + /* 1399 */ { MAD_F(0x07a3d765) /* 0.477500339 */, 15 }, + /* 1400 */ { MAD_F(0x07a5b4a5) /* 0.477955481 */, 15 }, + /* 1401 */ { MAD_F(0x07a79202) /* 0.478410731 */, 15 }, + /* 1402 */ { MAD_F(0x07a96f7d) /* 0.478866089 */, 15 }, + /* 1403 */ { MAD_F(0x07ab4d14) /* 0.479321555 */, 15 }, + /* 1404 */ { MAD_F(0x07ad2ac8) /* 0.479777130 */, 15 }, + /* 1405 */ { MAD_F(0x07af089a) /* 0.480232813 */, 15 }, + /* 1406 */ { MAD_F(0x07b0e688) /* 0.480688604 */, 15 }, + /* 1407 */ { MAD_F(0x07b2c494) /* 0.481144503 */, 15 }, + + /* 1408 */ { MAD_F(0x07b4a2bc) /* 0.481600510 */, 15 }, + /* 1409 */ { MAD_F(0x07b68102) /* 0.482056625 */, 15 }, + /* 1410 */ { MAD_F(0x07b85f64) /* 0.482512848 */, 15 }, + /* 1411 */ { MAD_F(0x07ba3de4) /* 0.482969179 */, 15 }, + /* 1412 */ { MAD_F(0x07bc1c80) /* 0.483425618 */, 15 }, + /* 1413 */ { MAD_F(0x07bdfb39) /* 0.483882164 */, 15 }, + /* 1414 */ { MAD_F(0x07bfda0f) /* 0.484338818 */, 15 }, + /* 1415 */ { MAD_F(0x07c1b902) /* 0.484795580 */, 15 }, + /* 1416 */ { MAD_F(0x07c39812) /* 0.485252449 */, 15 }, + /* 1417 */ { MAD_F(0x07c5773f) /* 0.485709426 */, 15 }, + /* 1418 */ { MAD_F(0x07c75689) /* 0.486166511 */, 15 }, + /* 1419 */ { MAD_F(0x07c935ef) /* 0.486623703 */, 15 }, + /* 1420 */ { MAD_F(0x07cb1573) /* 0.487081002 */, 15 }, + /* 1421 */ { MAD_F(0x07ccf513) /* 0.487538409 */, 15 }, + /* 1422 */ { MAD_F(0x07ced4d0) /* 0.487995923 */, 15 }, + /* 1423 */ { MAD_F(0x07d0b4aa) /* 0.488453544 */, 15 }, + + /* 1424 */ { MAD_F(0x07d294a0) /* 0.488911273 */, 15 }, + /* 1425 */ { MAD_F(0x07d474b3) /* 0.489369108 */, 15 }, + /* 1426 */ { MAD_F(0x07d654e4) /* 0.489827051 */, 15 }, + /* 1427 */ { MAD_F(0x07d83530) /* 0.490285101 */, 15 }, + /* 1428 */ { MAD_F(0x07da159a) /* 0.490743258 */, 15 }, + /* 1429 */ { MAD_F(0x07dbf620) /* 0.491201522 */, 15 }, + /* 1430 */ { MAD_F(0x07ddd6c3) /* 0.491659892 */, 15 }, + /* 1431 */ { MAD_F(0x07dfb783) /* 0.492118370 */, 15 }, + /* 1432 */ { MAD_F(0x07e1985f) /* 0.492576954 */, 15 }, + /* 1433 */ { MAD_F(0x07e37958) /* 0.493035645 */, 15 }, + /* 1434 */ { MAD_F(0x07e55a6e) /* 0.493494443 */, 15 }, + /* 1435 */ { MAD_F(0x07e73ba0) /* 0.493953348 */, 15 }, + /* 1436 */ { MAD_F(0x07e91cef) /* 0.494412359 */, 15 }, + /* 1437 */ { MAD_F(0x07eafe5a) /* 0.494871476 */, 15 }, + /* 1438 */ { MAD_F(0x07ecdfe2) /* 0.495330701 */, 15 }, + /* 1439 */ { MAD_F(0x07eec187) /* 0.495790031 */, 15 }, + + /* 1440 */ { MAD_F(0x07f0a348) /* 0.496249468 */, 15 }, + /* 1441 */ { MAD_F(0x07f28526) /* 0.496709012 */, 15 }, + /* 1442 */ { MAD_F(0x07f46720) /* 0.497168662 */, 15 }, + /* 1443 */ { MAD_F(0x07f64937) /* 0.497628418 */, 15 }, + /* 1444 */ { MAD_F(0x07f82b6a) /* 0.498088280 */, 15 }, + /* 1445 */ { MAD_F(0x07fa0dba) /* 0.498548248 */, 15 }, + /* 1446 */ { MAD_F(0x07fbf026) /* 0.499008323 */, 15 }, + /* 1447 */ { MAD_F(0x07fdd2af) /* 0.499468503 */, 15 }, + /* 1448 */ { MAD_F(0x07ffb554) /* 0.499928790 */, 15 }, + /* 1449 */ { MAD_F(0x0400cc0b) /* 0.250194591 */, 16 }, + /* 1450 */ { MAD_F(0x0401bd7a) /* 0.250424840 */, 16 }, + /* 1451 */ { MAD_F(0x0402aef7) /* 0.250655143 */, 16 }, + /* 1452 */ { MAD_F(0x0403a083) /* 0.250885498 */, 16 }, + /* 1453 */ { MAD_F(0x0404921c) /* 0.251115906 */, 16 }, + /* 1454 */ { MAD_F(0x040583c4) /* 0.251346367 */, 16 }, + /* 1455 */ { MAD_F(0x0406757a) /* 0.251576880 */, 16 }, + + /* 1456 */ { MAD_F(0x0407673f) /* 0.251807447 */, 16 }, + /* 1457 */ { MAD_F(0x04085911) /* 0.252038066 */, 16 }, + /* 1458 */ { MAD_F(0x04094af1) /* 0.252268738 */, 16 }, + /* 1459 */ { MAD_F(0x040a3ce0) /* 0.252499463 */, 16 }, + /* 1460 */ { MAD_F(0x040b2edd) /* 0.252730240 */, 16 }, + /* 1461 */ { MAD_F(0x040c20e8) /* 0.252961071 */, 16 }, + /* 1462 */ { MAD_F(0x040d1301) /* 0.253191953 */, 16 }, + /* 1463 */ { MAD_F(0x040e0529) /* 0.253422889 */, 16 }, + /* 1464 */ { MAD_F(0x040ef75e) /* 0.253653877 */, 16 }, + /* 1465 */ { MAD_F(0x040fe9a1) /* 0.253884918 */, 16 }, + /* 1466 */ { MAD_F(0x0410dbf3) /* 0.254116011 */, 16 }, + /* 1467 */ { MAD_F(0x0411ce53) /* 0.254347157 */, 16 }, + /* 1468 */ { MAD_F(0x0412c0c1) /* 0.254578356 */, 16 }, + /* 1469 */ { MAD_F(0x0413b33d) /* 0.254809606 */, 16 }, + /* 1470 */ { MAD_F(0x0414a5c7) /* 0.255040910 */, 16 }, + /* 1471 */ { MAD_F(0x0415985f) /* 0.255272266 */, 16 }, + + /* 1472 */ { MAD_F(0x04168b05) /* 0.255503674 */, 16 }, + /* 1473 */ { MAD_F(0x04177db9) /* 0.255735135 */, 16 }, + /* 1474 */ { MAD_F(0x0418707c) /* 0.255966648 */, 16 }, + /* 1475 */ { MAD_F(0x0419634c) /* 0.256198213 */, 16 }, + /* 1476 */ { MAD_F(0x041a562a) /* 0.256429831 */, 16 }, + /* 1477 */ { MAD_F(0x041b4917) /* 0.256661501 */, 16 }, + /* 1478 */ { MAD_F(0x041c3c11) /* 0.256893223 */, 16 }, + /* 1479 */ { MAD_F(0x041d2f1a) /* 0.257124998 */, 16 }, + /* 1480 */ { MAD_F(0x041e2230) /* 0.257356825 */, 16 }, + /* 1481 */ { MAD_F(0x041f1555) /* 0.257588704 */, 16 }, + /* 1482 */ { MAD_F(0x04200888) /* 0.257820635 */, 16 }, + /* 1483 */ { MAD_F(0x0420fbc8) /* 0.258052619 */, 16 }, + /* 1484 */ { MAD_F(0x0421ef17) /* 0.258284654 */, 16 }, + /* 1485 */ { MAD_F(0x0422e273) /* 0.258516742 */, 16 }, + /* 1486 */ { MAD_F(0x0423d5de) /* 0.258748882 */, 16 }, + /* 1487 */ { MAD_F(0x0424c956) /* 0.258981074 */, 16 }, + + /* 1488 */ { MAD_F(0x0425bcdd) /* 0.259213318 */, 16 }, + /* 1489 */ { MAD_F(0x0426b071) /* 0.259445614 */, 16 }, + /* 1490 */ { MAD_F(0x0427a414) /* 0.259677962 */, 16 }, + /* 1491 */ { MAD_F(0x042897c4) /* 0.259910362 */, 16 }, + /* 1492 */ { MAD_F(0x04298b83) /* 0.260142814 */, 16 }, + /* 1493 */ { MAD_F(0x042a7f4f) /* 0.260375318 */, 16 }, + /* 1494 */ { MAD_F(0x042b7329) /* 0.260607874 */, 16 }, + /* 1495 */ { MAD_F(0x042c6711) /* 0.260840481 */, 16 }, + /* 1496 */ { MAD_F(0x042d5b07) /* 0.261073141 */, 16 }, + /* 1497 */ { MAD_F(0x042e4f0b) /* 0.261305852 */, 16 }, + /* 1498 */ { MAD_F(0x042f431d) /* 0.261538616 */, 16 }, + /* 1499 */ { MAD_F(0x0430373d) /* 0.261771431 */, 16 }, + /* 1500 */ { MAD_F(0x04312b6b) /* 0.262004297 */, 16 }, + /* 1501 */ { MAD_F(0x04321fa6) /* 0.262237216 */, 16 }, + /* 1502 */ { MAD_F(0x043313f0) /* 0.262470186 */, 16 }, + /* 1503 */ { MAD_F(0x04340847) /* 0.262703208 */, 16 }, + + /* 1504 */ { MAD_F(0x0434fcad) /* 0.262936282 */, 16 }, + /* 1505 */ { MAD_F(0x0435f120) /* 0.263169407 */, 16 }, + /* 1506 */ { MAD_F(0x0436e5a1) /* 0.263402584 */, 16 }, + /* 1507 */ { MAD_F(0x0437da2f) /* 0.263635813 */, 16 }, + /* 1508 */ { MAD_F(0x0438cecc) /* 0.263869093 */, 16 }, + /* 1509 */ { MAD_F(0x0439c377) /* 0.264102425 */, 16 }, + /* 1510 */ { MAD_F(0x043ab82f) /* 0.264335808 */, 16 }, + /* 1511 */ { MAD_F(0x043bacf5) /* 0.264569243 */, 16 }, + /* 1512 */ { MAD_F(0x043ca1c9) /* 0.264802730 */, 16 }, + /* 1513 */ { MAD_F(0x043d96ab) /* 0.265036267 */, 16 }, + /* 1514 */ { MAD_F(0x043e8b9b) /* 0.265269857 */, 16 }, + /* 1515 */ { MAD_F(0x043f8098) /* 0.265503498 */, 16 }, + /* 1516 */ { MAD_F(0x044075a3) /* 0.265737190 */, 16 }, + /* 1517 */ { MAD_F(0x04416abc) /* 0.265970933 */, 16 }, + /* 1518 */ { MAD_F(0x04425fe3) /* 0.266204728 */, 16 }, + /* 1519 */ { MAD_F(0x04435518) /* 0.266438574 */, 16 }, + + /* 1520 */ { MAD_F(0x04444a5a) /* 0.266672472 */, 16 }, + /* 1521 */ { MAD_F(0x04453fab) /* 0.266906421 */, 16 }, + /* 1522 */ { MAD_F(0x04463508) /* 0.267140421 */, 16 }, + /* 1523 */ { MAD_F(0x04472a74) /* 0.267374472 */, 16 }, + /* 1524 */ { MAD_F(0x04481fee) /* 0.267608575 */, 16 }, + /* 1525 */ { MAD_F(0x04491575) /* 0.267842729 */, 16 }, + /* 1526 */ { MAD_F(0x044a0b0a) /* 0.268076934 */, 16 }, + /* 1527 */ { MAD_F(0x044b00ac) /* 0.268311190 */, 16 }, + /* 1528 */ { MAD_F(0x044bf65d) /* 0.268545497 */, 16 }, + /* 1529 */ { MAD_F(0x044cec1b) /* 0.268779856 */, 16 }, + /* 1530 */ { MAD_F(0x044de1e7) /* 0.269014265 */, 16 }, + /* 1531 */ { MAD_F(0x044ed7c0) /* 0.269248726 */, 16 }, + /* 1532 */ { MAD_F(0x044fcda8) /* 0.269483238 */, 16 }, + /* 1533 */ { MAD_F(0x0450c39c) /* 0.269717800 */, 16 }, + /* 1534 */ { MAD_F(0x0451b99f) /* 0.269952414 */, 16 }, + /* 1535 */ { MAD_F(0x0452afaf) /* 0.270187079 */, 16 }, + + /* 1536 */ { MAD_F(0x0453a5cd) /* 0.270421794 */, 16 }, + /* 1537 */ { MAD_F(0x04549bf9) /* 0.270656561 */, 16 }, + /* 1538 */ { MAD_F(0x04559232) /* 0.270891379 */, 16 }, + /* 1539 */ { MAD_F(0x04568879) /* 0.271126247 */, 16 }, + /* 1540 */ { MAD_F(0x04577ece) /* 0.271361166 */, 16 }, + /* 1541 */ { MAD_F(0x04587530) /* 0.271596136 */, 16 }, + /* 1542 */ { MAD_F(0x04596ba0) /* 0.271831157 */, 16 }, + /* 1543 */ { MAD_F(0x045a621e) /* 0.272066229 */, 16 }, + /* 1544 */ { MAD_F(0x045b58a9) /* 0.272301352 */, 16 }, + /* 1545 */ { MAD_F(0x045c4f42) /* 0.272536525 */, 16 }, + /* 1546 */ { MAD_F(0x045d45e9) /* 0.272771749 */, 16 }, + /* 1547 */ { MAD_F(0x045e3c9d) /* 0.273007024 */, 16 }, + /* 1548 */ { MAD_F(0x045f335e) /* 0.273242350 */, 16 }, + /* 1549 */ { MAD_F(0x04602a2e) /* 0.273477726 */, 16 }, + /* 1550 */ { MAD_F(0x0461210b) /* 0.273713153 */, 16 }, + /* 1551 */ { MAD_F(0x046217f5) /* 0.273948630 */, 16 }, + + /* 1552 */ { MAD_F(0x04630eed) /* 0.274184158 */, 16 }, + /* 1553 */ { MAD_F(0x046405f3) /* 0.274419737 */, 16 }, + /* 1554 */ { MAD_F(0x0464fd06) /* 0.274655366 */, 16 }, + /* 1555 */ { MAD_F(0x0465f427) /* 0.274891046 */, 16 }, + /* 1556 */ { MAD_F(0x0466eb55) /* 0.275126776 */, 16 }, + /* 1557 */ { MAD_F(0x0467e291) /* 0.275362557 */, 16 }, + /* 1558 */ { MAD_F(0x0468d9db) /* 0.275598389 */, 16 }, + /* 1559 */ { MAD_F(0x0469d132) /* 0.275834270 */, 16 }, + /* 1560 */ { MAD_F(0x046ac896) /* 0.276070203 */, 16 }, + /* 1561 */ { MAD_F(0x046bc009) /* 0.276306185 */, 16 }, + /* 1562 */ { MAD_F(0x046cb788) /* 0.276542218 */, 16 }, + /* 1563 */ { MAD_F(0x046daf15) /* 0.276778302 */, 16 }, + /* 1564 */ { MAD_F(0x046ea6b0) /* 0.277014435 */, 16 }, + /* 1565 */ { MAD_F(0x046f9e58) /* 0.277250619 */, 16 }, + /* 1566 */ { MAD_F(0x0470960e) /* 0.277486854 */, 16 }, + /* 1567 */ { MAD_F(0x04718dd1) /* 0.277723139 */, 16 }, + + /* 1568 */ { MAD_F(0x047285a2) /* 0.277959474 */, 16 }, + /* 1569 */ { MAD_F(0x04737d80) /* 0.278195859 */, 16 }, + /* 1570 */ { MAD_F(0x0474756c) /* 0.278432294 */, 16 }, + /* 1571 */ { MAD_F(0x04756d65) /* 0.278668780 */, 16 }, + /* 1572 */ { MAD_F(0x0476656b) /* 0.278905316 */, 16 }, + /* 1573 */ { MAD_F(0x04775d7f) /* 0.279141902 */, 16 }, + /* 1574 */ { MAD_F(0x047855a1) /* 0.279378538 */, 16 }, + /* 1575 */ { MAD_F(0x04794dd0) /* 0.279615224 */, 16 }, + /* 1576 */ { MAD_F(0x047a460c) /* 0.279851960 */, 16 }, + /* 1577 */ { MAD_F(0x047b3e56) /* 0.280088747 */, 16 }, + /* 1578 */ { MAD_F(0x047c36ae) /* 0.280325583 */, 16 }, + /* 1579 */ { MAD_F(0x047d2f12) /* 0.280562470 */, 16 }, + /* 1580 */ { MAD_F(0x047e2784) /* 0.280799406 */, 16 }, + /* 1581 */ { MAD_F(0x047f2004) /* 0.281036393 */, 16 }, + /* 1582 */ { MAD_F(0x04801891) /* 0.281273429 */, 16 }, + /* 1583 */ { MAD_F(0x0481112b) /* 0.281510516 */, 16 }, + + /* 1584 */ { MAD_F(0x048209d3) /* 0.281747652 */, 16 }, + /* 1585 */ { MAD_F(0x04830288) /* 0.281984838 */, 16 }, + /* 1586 */ { MAD_F(0x0483fb4b) /* 0.282222075 */, 16 }, + /* 1587 */ { MAD_F(0x0484f41b) /* 0.282459361 */, 16 }, + /* 1588 */ { MAD_F(0x0485ecf8) /* 0.282696697 */, 16 }, + /* 1589 */ { MAD_F(0x0486e5e3) /* 0.282934082 */, 16 }, + /* 1590 */ { MAD_F(0x0487dedb) /* 0.283171518 */, 16 }, + /* 1591 */ { MAD_F(0x0488d7e1) /* 0.283409003 */, 16 }, + /* 1592 */ { MAD_F(0x0489d0f4) /* 0.283646538 */, 16 }, + /* 1593 */ { MAD_F(0x048aca14) /* 0.283884123 */, 16 }, + /* 1594 */ { MAD_F(0x048bc341) /* 0.284121757 */, 16 }, + /* 1595 */ { MAD_F(0x048cbc7c) /* 0.284359441 */, 16 }, + /* 1596 */ { MAD_F(0x048db5c4) /* 0.284597175 */, 16 }, + /* 1597 */ { MAD_F(0x048eaf1a) /* 0.284834959 */, 16 }, + /* 1598 */ { MAD_F(0x048fa87d) /* 0.285072792 */, 16 }, + /* 1599 */ { MAD_F(0x0490a1ed) /* 0.285310675 */, 16 }, + + /* 1600 */ { MAD_F(0x04919b6a) /* 0.285548607 */, 16 }, + /* 1601 */ { MAD_F(0x049294f5) /* 0.285786589 */, 16 }, + /* 1602 */ { MAD_F(0x04938e8d) /* 0.286024621 */, 16 }, + /* 1603 */ { MAD_F(0x04948833) /* 0.286262702 */, 16 }, + /* 1604 */ { MAD_F(0x049581e5) /* 0.286500832 */, 16 }, + /* 1605 */ { MAD_F(0x04967ba5) /* 0.286739012 */, 16 }, + /* 1606 */ { MAD_F(0x04977573) /* 0.286977242 */, 16 }, + /* 1607 */ { MAD_F(0x04986f4d) /* 0.287215521 */, 16 }, + /* 1608 */ { MAD_F(0x04996935) /* 0.287453849 */, 16 }, + /* 1609 */ { MAD_F(0x049a632a) /* 0.287692227 */, 16 }, + /* 1610 */ { MAD_F(0x049b5d2c) /* 0.287930654 */, 16 }, + /* 1611 */ { MAD_F(0x049c573c) /* 0.288169131 */, 16 }, + /* 1612 */ { MAD_F(0x049d5159) /* 0.288407657 */, 16 }, + /* 1613 */ { MAD_F(0x049e4b83) /* 0.288646232 */, 16 }, + /* 1614 */ { MAD_F(0x049f45ba) /* 0.288884857 */, 16 }, + /* 1615 */ { MAD_F(0x04a03ffe) /* 0.289123530 */, 16 }, + + /* 1616 */ { MAD_F(0x04a13a50) /* 0.289362253 */, 16 }, + /* 1617 */ { MAD_F(0x04a234af) /* 0.289601026 */, 16 }, + /* 1618 */ { MAD_F(0x04a32f1b) /* 0.289839847 */, 16 }, + /* 1619 */ { MAD_F(0x04a42995) /* 0.290078718 */, 16 }, + /* 1620 */ { MAD_F(0x04a5241b) /* 0.290317638 */, 16 }, + /* 1621 */ { MAD_F(0x04a61eaf) /* 0.290556607 */, 16 }, + /* 1622 */ { MAD_F(0x04a71950) /* 0.290795626 */, 16 }, + /* 1623 */ { MAD_F(0x04a813fe) /* 0.291034693 */, 16 }, + /* 1624 */ { MAD_F(0x04a90eba) /* 0.291273810 */, 16 }, + /* 1625 */ { MAD_F(0x04aa0982) /* 0.291512975 */, 16 }, + /* 1626 */ { MAD_F(0x04ab0458) /* 0.291752190 */, 16 }, + /* 1627 */ { MAD_F(0x04abff3b) /* 0.291991453 */, 16 }, + /* 1628 */ { MAD_F(0x04acfa2b) /* 0.292230766 */, 16 }, + /* 1629 */ { MAD_F(0x04adf528) /* 0.292470128 */, 16 }, + /* 1630 */ { MAD_F(0x04aef032) /* 0.292709539 */, 16 }, + /* 1631 */ { MAD_F(0x04afeb4a) /* 0.292948998 */, 16 }, + + /* 1632 */ { MAD_F(0x04b0e66e) /* 0.293188507 */, 16 }, + /* 1633 */ { MAD_F(0x04b1e1a0) /* 0.293428065 */, 16 }, + /* 1634 */ { MAD_F(0x04b2dcdf) /* 0.293667671 */, 16 }, + /* 1635 */ { MAD_F(0x04b3d82b) /* 0.293907326 */, 16 }, + /* 1636 */ { MAD_F(0x04b4d384) /* 0.294147031 */, 16 }, + /* 1637 */ { MAD_F(0x04b5ceea) /* 0.294386784 */, 16 }, + /* 1638 */ { MAD_F(0x04b6ca5e) /* 0.294626585 */, 16 }, + /* 1639 */ { MAD_F(0x04b7c5de) /* 0.294866436 */, 16 }, + /* 1640 */ { MAD_F(0x04b8c16c) /* 0.295106336 */, 16 }, + /* 1641 */ { MAD_F(0x04b9bd06) /* 0.295346284 */, 16 }, + /* 1642 */ { MAD_F(0x04bab8ae) /* 0.295586281 */, 16 }, + /* 1643 */ { MAD_F(0x04bbb463) /* 0.295826327 */, 16 }, + /* 1644 */ { MAD_F(0x04bcb024) /* 0.296066421 */, 16 }, + /* 1645 */ { MAD_F(0x04bdabf3) /* 0.296306564 */, 16 }, + /* 1646 */ { MAD_F(0x04bea7cf) /* 0.296546756 */, 16 }, + /* 1647 */ { MAD_F(0x04bfa3b8) /* 0.296786996 */, 16 }, + + /* 1648 */ { MAD_F(0x04c09faf) /* 0.297027285 */, 16 }, + /* 1649 */ { MAD_F(0x04c19bb2) /* 0.297267623 */, 16 }, + /* 1650 */ { MAD_F(0x04c297c2) /* 0.297508009 */, 16 }, + /* 1651 */ { MAD_F(0x04c393df) /* 0.297748444 */, 16 }, + /* 1652 */ { MAD_F(0x04c49009) /* 0.297988927 */, 16 }, + /* 1653 */ { MAD_F(0x04c58c41) /* 0.298229459 */, 16 }, + /* 1654 */ { MAD_F(0x04c68885) /* 0.298470039 */, 16 }, + /* 1655 */ { MAD_F(0x04c784d6) /* 0.298710668 */, 16 }, + /* 1656 */ { MAD_F(0x04c88135) /* 0.298951346 */, 16 }, + /* 1657 */ { MAD_F(0x04c97da0) /* 0.299192071 */, 16 }, + /* 1658 */ { MAD_F(0x04ca7a18) /* 0.299432846 */, 16 }, + /* 1659 */ { MAD_F(0x04cb769e) /* 0.299673668 */, 16 }, + /* 1660 */ { MAD_F(0x04cc7330) /* 0.299914539 */, 16 }, + /* 1661 */ { MAD_F(0x04cd6fcf) /* 0.300155459 */, 16 }, + /* 1662 */ { MAD_F(0x04ce6c7b) /* 0.300396426 */, 16 }, + /* 1663 */ { MAD_F(0x04cf6935) /* 0.300637443 */, 16 }, + + /* 1664 */ { MAD_F(0x04d065fb) /* 0.300878507 */, 16 }, + /* 1665 */ { MAD_F(0x04d162ce) /* 0.301119620 */, 16 }, + /* 1666 */ { MAD_F(0x04d25fae) /* 0.301360781 */, 16 }, + /* 1667 */ { MAD_F(0x04d35c9b) /* 0.301601990 */, 16 }, + /* 1668 */ { MAD_F(0x04d45995) /* 0.301843247 */, 16 }, + /* 1669 */ { MAD_F(0x04d5569c) /* 0.302084553 */, 16 }, + /* 1670 */ { MAD_F(0x04d653b0) /* 0.302325907 */, 16 }, + /* 1671 */ { MAD_F(0x04d750d1) /* 0.302567309 */, 16 }, + /* 1672 */ { MAD_F(0x04d84dff) /* 0.302808759 */, 16 }, + /* 1673 */ { MAD_F(0x04d94b3a) /* 0.303050257 */, 16 }, + /* 1674 */ { MAD_F(0x04da4881) /* 0.303291804 */, 16 }, + /* 1675 */ { MAD_F(0x04db45d6) /* 0.303533399 */, 16 }, + /* 1676 */ { MAD_F(0x04dc4337) /* 0.303775041 */, 16 }, + /* 1677 */ { MAD_F(0x04dd40a6) /* 0.304016732 */, 16 }, + /* 1678 */ { MAD_F(0x04de3e21) /* 0.304258471 */, 16 }, + /* 1679 */ { MAD_F(0x04df3ba9) /* 0.304500257 */, 16 }, + + /* 1680 */ { MAD_F(0x04e0393e) /* 0.304742092 */, 16 }, + /* 1681 */ { MAD_F(0x04e136e0) /* 0.304983975 */, 16 }, + /* 1682 */ { MAD_F(0x04e2348f) /* 0.305225906 */, 16 }, + /* 1683 */ { MAD_F(0x04e3324b) /* 0.305467885 */, 16 }, + /* 1684 */ { MAD_F(0x04e43013) /* 0.305709911 */, 16 }, + /* 1685 */ { MAD_F(0x04e52de9) /* 0.305951986 */, 16 }, + /* 1686 */ { MAD_F(0x04e62bcb) /* 0.306194108 */, 16 }, + /* 1687 */ { MAD_F(0x04e729ba) /* 0.306436279 */, 16 }, + /* 1688 */ { MAD_F(0x04e827b6) /* 0.306678497 */, 16 }, + /* 1689 */ { MAD_F(0x04e925bf) /* 0.306920763 */, 16 }, + /* 1690 */ { MAD_F(0x04ea23d4) /* 0.307163077 */, 16 }, + /* 1691 */ { MAD_F(0x04eb21f7) /* 0.307405438 */, 16 }, + /* 1692 */ { MAD_F(0x04ec2026) /* 0.307647848 */, 16 }, + /* 1693 */ { MAD_F(0x04ed1e62) /* 0.307890305 */, 16 }, + /* 1694 */ { MAD_F(0x04ee1cab) /* 0.308132810 */, 16 }, + /* 1695 */ { MAD_F(0x04ef1b01) /* 0.308375362 */, 16 }, + + /* 1696 */ { MAD_F(0x04f01963) /* 0.308617963 */, 16 }, + /* 1697 */ { MAD_F(0x04f117d3) /* 0.308860611 */, 16 }, + /* 1698 */ { MAD_F(0x04f2164f) /* 0.309103306 */, 16 }, + /* 1699 */ { MAD_F(0x04f314d8) /* 0.309346050 */, 16 }, + /* 1700 */ { MAD_F(0x04f4136d) /* 0.309588841 */, 16 }, + /* 1701 */ { MAD_F(0x04f51210) /* 0.309831679 */, 16 }, + /* 1702 */ { MAD_F(0x04f610bf) /* 0.310074565 */, 16 }, + /* 1703 */ { MAD_F(0x04f70f7b) /* 0.310317499 */, 16 }, + /* 1704 */ { MAD_F(0x04f80e44) /* 0.310560480 */, 16 }, + /* 1705 */ { MAD_F(0x04f90d19) /* 0.310803509 */, 16 }, + /* 1706 */ { MAD_F(0x04fa0bfc) /* 0.311046586 */, 16 }, + /* 1707 */ { MAD_F(0x04fb0aeb) /* 0.311289710 */, 16 }, + /* 1708 */ { MAD_F(0x04fc09e7) /* 0.311532881 */, 16 }, + /* 1709 */ { MAD_F(0x04fd08ef) /* 0.311776100 */, 16 }, + /* 1710 */ { MAD_F(0x04fe0805) /* 0.312019366 */, 16 }, + /* 1711 */ { MAD_F(0x04ff0727) /* 0.312262680 */, 16 }, + + /* 1712 */ { MAD_F(0x05000655) /* 0.312506041 */, 16 }, + /* 1713 */ { MAD_F(0x05010591) /* 0.312749449 */, 16 }, + /* 1714 */ { MAD_F(0x050204d9) /* 0.312992905 */, 16 }, + /* 1715 */ { MAD_F(0x0503042e) /* 0.313236408 */, 16 }, + /* 1716 */ { MAD_F(0x0504038f) /* 0.313479959 */, 16 }, + /* 1717 */ { MAD_F(0x050502fe) /* 0.313723556 */, 16 }, + /* 1718 */ { MAD_F(0x05060279) /* 0.313967202 */, 16 }, + /* 1719 */ { MAD_F(0x05070200) /* 0.314210894 */, 16 }, + /* 1720 */ { MAD_F(0x05080195) /* 0.314454634 */, 16 }, + /* 1721 */ { MAD_F(0x05090136) /* 0.314698420 */, 16 }, + /* 1722 */ { MAD_F(0x050a00e3) /* 0.314942255 */, 16 }, + /* 1723 */ { MAD_F(0x050b009e) /* 0.315186136 */, 16 }, + /* 1724 */ { MAD_F(0x050c0065) /* 0.315430064 */, 16 }, + /* 1725 */ { MAD_F(0x050d0039) /* 0.315674040 */, 16 }, + /* 1726 */ { MAD_F(0x050e0019) /* 0.315918063 */, 16 }, + /* 1727 */ { MAD_F(0x050f0006) /* 0.316162133 */, 16 }, + + /* 1728 */ { MAD_F(0x05100000) /* 0.316406250 */, 16 }, + /* 1729 */ { MAD_F(0x05110006) /* 0.316650414 */, 16 }, + /* 1730 */ { MAD_F(0x05120019) /* 0.316894625 */, 16 }, + /* 1731 */ { MAD_F(0x05130039) /* 0.317138884 */, 16 }, + /* 1732 */ { MAD_F(0x05140065) /* 0.317383189 */, 16 }, + /* 1733 */ { MAD_F(0x0515009e) /* 0.317627541 */, 16 }, + /* 1734 */ { MAD_F(0x051600e3) /* 0.317871941 */, 16 }, + /* 1735 */ { MAD_F(0x05170135) /* 0.318116387 */, 16 }, + /* 1736 */ { MAD_F(0x05180194) /* 0.318360880 */, 16 }, + /* 1737 */ { MAD_F(0x051901ff) /* 0.318605421 */, 16 }, + /* 1738 */ { MAD_F(0x051a0277) /* 0.318850008 */, 16 }, + /* 1739 */ { MAD_F(0x051b02fc) /* 0.319094642 */, 16 }, + /* 1740 */ { MAD_F(0x051c038d) /* 0.319339323 */, 16 }, + /* 1741 */ { MAD_F(0x051d042a) /* 0.319584051 */, 16 }, + /* 1742 */ { MAD_F(0x051e04d4) /* 0.319828826 */, 16 }, + /* 1743 */ { MAD_F(0x051f058b) /* 0.320073647 */, 16 }, + + /* 1744 */ { MAD_F(0x0520064f) /* 0.320318516 */, 16 }, + /* 1745 */ { MAD_F(0x0521071f) /* 0.320563431 */, 16 }, + /* 1746 */ { MAD_F(0x052207fb) /* 0.320808393 */, 16 }, + /* 1747 */ { MAD_F(0x052308e4) /* 0.321053402 */, 16 }, + /* 1748 */ { MAD_F(0x052409da) /* 0.321298457 */, 16 }, + /* 1749 */ { MAD_F(0x05250adc) /* 0.321543560 */, 16 }, + /* 1750 */ { MAD_F(0x05260bea) /* 0.321788709 */, 16 }, + /* 1751 */ { MAD_F(0x05270d06) /* 0.322033904 */, 16 }, + /* 1752 */ { MAD_F(0x05280e2d) /* 0.322279147 */, 16 }, + /* 1753 */ { MAD_F(0x05290f62) /* 0.322524436 */, 16 }, + /* 1754 */ { MAD_F(0x052a10a3) /* 0.322769771 */, 16 }, + /* 1755 */ { MAD_F(0x052b11f0) /* 0.323015154 */, 16 }, + /* 1756 */ { MAD_F(0x052c134a) /* 0.323260583 */, 16 }, + /* 1757 */ { MAD_F(0x052d14b0) /* 0.323506058 */, 16 }, + /* 1758 */ { MAD_F(0x052e1623) /* 0.323751580 */, 16 }, + /* 1759 */ { MAD_F(0x052f17a2) /* 0.323997149 */, 16 }, + + /* 1760 */ { MAD_F(0x0530192e) /* 0.324242764 */, 16 }, + /* 1761 */ { MAD_F(0x05311ac6) /* 0.324488426 */, 16 }, + /* 1762 */ { MAD_F(0x05321c6b) /* 0.324734134 */, 16 }, + /* 1763 */ { MAD_F(0x05331e1c) /* 0.324979889 */, 16 }, + /* 1764 */ { MAD_F(0x05341fda) /* 0.325225690 */, 16 }, + /* 1765 */ { MAD_F(0x053521a4) /* 0.325471538 */, 16 }, + /* 1766 */ { MAD_F(0x0536237b) /* 0.325717432 */, 16 }, + /* 1767 */ { MAD_F(0x0537255e) /* 0.325963372 */, 16 }, + /* 1768 */ { MAD_F(0x0538274e) /* 0.326209359 */, 16 }, + /* 1769 */ { MAD_F(0x0539294a) /* 0.326455392 */, 16 }, + /* 1770 */ { MAD_F(0x053a2b52) /* 0.326701472 */, 16 }, + /* 1771 */ { MAD_F(0x053b2d67) /* 0.326947598 */, 16 }, + /* 1772 */ { MAD_F(0x053c2f89) /* 0.327193770 */, 16 }, + /* 1773 */ { MAD_F(0x053d31b6) /* 0.327439989 */, 16 }, + /* 1774 */ { MAD_F(0x053e33f1) /* 0.327686254 */, 16 }, + /* 1775 */ { MAD_F(0x053f3637) /* 0.327932565 */, 16 }, + + /* 1776 */ { MAD_F(0x0540388a) /* 0.328178922 */, 16 }, + /* 1777 */ { MAD_F(0x05413aea) /* 0.328425326 */, 16 }, + /* 1778 */ { MAD_F(0x05423d56) /* 0.328671776 */, 16 }, + /* 1779 */ { MAD_F(0x05433fce) /* 0.328918272 */, 16 }, + /* 1780 */ { MAD_F(0x05444253) /* 0.329164814 */, 16 }, + /* 1781 */ { MAD_F(0x054544e4) /* 0.329411403 */, 16 }, + /* 1782 */ { MAD_F(0x05464781) /* 0.329658038 */, 16 }, + /* 1783 */ { MAD_F(0x05474a2b) /* 0.329904718 */, 16 }, + /* 1784 */ { MAD_F(0x05484ce2) /* 0.330151445 */, 16 }, + /* 1785 */ { MAD_F(0x05494fa4) /* 0.330398218 */, 16 }, + /* 1786 */ { MAD_F(0x054a5273) /* 0.330645037 */, 16 }, + /* 1787 */ { MAD_F(0x054b554e) /* 0.330891903 */, 16 }, + /* 1788 */ { MAD_F(0x054c5836) /* 0.331138814 */, 16 }, + /* 1789 */ { MAD_F(0x054d5b2a) /* 0.331385771 */, 16 }, + /* 1790 */ { MAD_F(0x054e5e2b) /* 0.331632774 */, 16 }, + /* 1791 */ { MAD_F(0x054f6138) /* 0.331879824 */, 16 }, + + /* 1792 */ { MAD_F(0x05506451) /* 0.332126919 */, 16 }, + /* 1793 */ { MAD_F(0x05516776) /* 0.332374060 */, 16 }, + /* 1794 */ { MAD_F(0x05526aa8) /* 0.332621247 */, 16 }, + /* 1795 */ { MAD_F(0x05536de6) /* 0.332868480 */, 16 }, + /* 1796 */ { MAD_F(0x05547131) /* 0.333115759 */, 16 }, + /* 1797 */ { MAD_F(0x05557487) /* 0.333363084 */, 16 }, + /* 1798 */ { MAD_F(0x055677ea) /* 0.333610455 */, 16 }, + /* 1799 */ { MAD_F(0x05577b5a) /* 0.333857872 */, 16 }, + /* 1800 */ { MAD_F(0x05587ed5) /* 0.334105334 */, 16 }, + /* 1801 */ { MAD_F(0x0559825e) /* 0.334352843 */, 16 }, + /* 1802 */ { MAD_F(0x055a85f2) /* 0.334600397 */, 16 }, + /* 1803 */ { MAD_F(0x055b8992) /* 0.334847997 */, 16 }, + /* 1804 */ { MAD_F(0x055c8d3f) /* 0.335095642 */, 16 }, + /* 1805 */ { MAD_F(0x055d90f9) /* 0.335343334 */, 16 }, + /* 1806 */ { MAD_F(0x055e94be) /* 0.335591071 */, 16 }, + /* 1807 */ { MAD_F(0x055f9890) /* 0.335838854 */, 16 }, + + /* 1808 */ { MAD_F(0x05609c6e) /* 0.336086683 */, 16 }, + /* 1809 */ { MAD_F(0x0561a058) /* 0.336334557 */, 16 }, + /* 1810 */ { MAD_F(0x0562a44f) /* 0.336582477 */, 16 }, + /* 1811 */ { MAD_F(0x0563a851) /* 0.336830443 */, 16 }, + /* 1812 */ { MAD_F(0x0564ac60) /* 0.337078454 */, 16 }, + /* 1813 */ { MAD_F(0x0565b07c) /* 0.337326511 */, 16 }, + /* 1814 */ { MAD_F(0x0566b4a3) /* 0.337574614 */, 16 }, + /* 1815 */ { MAD_F(0x0567b8d7) /* 0.337822762 */, 16 }, + /* 1816 */ { MAD_F(0x0568bd17) /* 0.338070956 */, 16 }, + /* 1817 */ { MAD_F(0x0569c163) /* 0.338319195 */, 16 }, + /* 1818 */ { MAD_F(0x056ac5bc) /* 0.338567480 */, 16 }, + /* 1819 */ { MAD_F(0x056bca20) /* 0.338815811 */, 16 }, + /* 1820 */ { MAD_F(0x056cce91) /* 0.339064186 */, 16 }, + /* 1821 */ { MAD_F(0x056dd30e) /* 0.339312608 */, 16 }, + /* 1822 */ { MAD_F(0x056ed798) /* 0.339561075 */, 16 }, + /* 1823 */ { MAD_F(0x056fdc2d) /* 0.339809587 */, 16 }, + + /* 1824 */ { MAD_F(0x0570e0cf) /* 0.340058145 */, 16 }, + /* 1825 */ { MAD_F(0x0571e57d) /* 0.340306748 */, 16 }, + /* 1826 */ { MAD_F(0x0572ea37) /* 0.340555397 */, 16 }, + /* 1827 */ { MAD_F(0x0573eefd) /* 0.340804091 */, 16 }, + /* 1828 */ { MAD_F(0x0574f3d0) /* 0.341052830 */, 16 }, + /* 1829 */ { MAD_F(0x0575f8ae) /* 0.341301615 */, 16 }, + /* 1830 */ { MAD_F(0x0576fd99) /* 0.341550445 */, 16 }, + /* 1831 */ { MAD_F(0x05780290) /* 0.341799321 */, 16 }, + /* 1832 */ { MAD_F(0x05790793) /* 0.342048241 */, 16 }, + /* 1833 */ { MAD_F(0x057a0ca3) /* 0.342297207 */, 16 }, + /* 1834 */ { MAD_F(0x057b11be) /* 0.342546219 */, 16 }, + /* 1835 */ { MAD_F(0x057c16e6) /* 0.342795275 */, 16 }, + /* 1836 */ { MAD_F(0x057d1c1a) /* 0.343044377 */, 16 }, + /* 1837 */ { MAD_F(0x057e2159) /* 0.343293524 */, 16 }, + /* 1838 */ { MAD_F(0x057f26a6) /* 0.343542717 */, 16 }, + /* 1839 */ { MAD_F(0x05802bfe) /* 0.343791954 */, 16 }, + + /* 1840 */ { MAD_F(0x05813162) /* 0.344041237 */, 16 }, + /* 1841 */ { MAD_F(0x058236d2) /* 0.344290564 */, 16 }, + /* 1842 */ { MAD_F(0x05833c4f) /* 0.344539937 */, 16 }, + /* 1843 */ { MAD_F(0x058441d8) /* 0.344789356 */, 16 }, + /* 1844 */ { MAD_F(0x0585476c) /* 0.345038819 */, 16 }, + /* 1845 */ { MAD_F(0x05864d0d) /* 0.345288327 */, 16 }, + /* 1846 */ { MAD_F(0x058752ba) /* 0.345537880 */, 16 }, + /* 1847 */ { MAD_F(0x05885873) /* 0.345787479 */, 16 }, + /* 1848 */ { MAD_F(0x05895e39) /* 0.346037122 */, 16 }, + /* 1849 */ { MAD_F(0x058a640a) /* 0.346286811 */, 16 }, + /* 1850 */ { MAD_F(0x058b69e7) /* 0.346536545 */, 16 }, + /* 1851 */ { MAD_F(0x058c6fd1) /* 0.346786323 */, 16 }, + /* 1852 */ { MAD_F(0x058d75c6) /* 0.347036147 */, 16 }, + /* 1853 */ { MAD_F(0x058e7bc8) /* 0.347286015 */, 16 }, + /* 1854 */ { MAD_F(0x058f81d5) /* 0.347535929 */, 16 }, + /* 1855 */ { MAD_F(0x059087ef) /* 0.347785887 */, 16 }, + + /* 1856 */ { MAD_F(0x05918e15) /* 0.348035890 */, 16 }, + /* 1857 */ { MAD_F(0x05929447) /* 0.348285939 */, 16 }, + /* 1858 */ { MAD_F(0x05939a84) /* 0.348536032 */, 16 }, + /* 1859 */ { MAD_F(0x0594a0ce) /* 0.348786170 */, 16 }, + /* 1860 */ { MAD_F(0x0595a724) /* 0.349036353 */, 16 }, + /* 1861 */ { MAD_F(0x0596ad86) /* 0.349286580 */, 16 }, + /* 1862 */ { MAD_F(0x0597b3f4) /* 0.349536853 */, 16 }, + /* 1863 */ { MAD_F(0x0598ba6e) /* 0.349787170 */, 16 }, + /* 1864 */ { MAD_F(0x0599c0f4) /* 0.350037532 */, 16 }, + /* 1865 */ { MAD_F(0x059ac786) /* 0.350287939 */, 16 }, + /* 1866 */ { MAD_F(0x059bce25) /* 0.350538391 */, 16 }, + /* 1867 */ { MAD_F(0x059cd4cf) /* 0.350788887 */, 16 }, + /* 1868 */ { MAD_F(0x059ddb85) /* 0.351039428 */, 16 }, + /* 1869 */ { MAD_F(0x059ee247) /* 0.351290014 */, 16 }, + /* 1870 */ { MAD_F(0x059fe915) /* 0.351540645 */, 16 }, + /* 1871 */ { MAD_F(0x05a0efef) /* 0.351791320 */, 16 }, + + /* 1872 */ { MAD_F(0x05a1f6d5) /* 0.352042040 */, 16 }, + /* 1873 */ { MAD_F(0x05a2fdc7) /* 0.352292804 */, 16 }, + /* 1874 */ { MAD_F(0x05a404c5) /* 0.352543613 */, 16 }, + /* 1875 */ { MAD_F(0x05a50bcf) /* 0.352794467 */, 16 }, + /* 1876 */ { MAD_F(0x05a612e5) /* 0.353045365 */, 16 }, + /* 1877 */ { MAD_F(0x05a71a07) /* 0.353296308 */, 16 }, + /* 1878 */ { MAD_F(0x05a82135) /* 0.353547296 */, 16 }, + /* 1879 */ { MAD_F(0x05a9286f) /* 0.353798328 */, 16 }, + /* 1880 */ { MAD_F(0x05aa2fb5) /* 0.354049405 */, 16 }, + /* 1881 */ { MAD_F(0x05ab3707) /* 0.354300526 */, 16 }, + /* 1882 */ { MAD_F(0x05ac3e65) /* 0.354551691 */, 16 }, + /* 1883 */ { MAD_F(0x05ad45ce) /* 0.354802901 */, 16 }, + /* 1884 */ { MAD_F(0x05ae4d44) /* 0.355054156 */, 16 }, + /* 1885 */ { MAD_F(0x05af54c6) /* 0.355305455 */, 16 }, + /* 1886 */ { MAD_F(0x05b05c53) /* 0.355556799 */, 16 }, + /* 1887 */ { MAD_F(0x05b163ed) /* 0.355808187 */, 16 }, + + /* 1888 */ { MAD_F(0x05b26b92) /* 0.356059619 */, 16 }, + /* 1889 */ { MAD_F(0x05b37343) /* 0.356311096 */, 16 }, + /* 1890 */ { MAD_F(0x05b47b00) /* 0.356562617 */, 16 }, + /* 1891 */ { MAD_F(0x05b582c9) /* 0.356814182 */, 16 }, + /* 1892 */ { MAD_F(0x05b68a9e) /* 0.357065792 */, 16 }, + /* 1893 */ { MAD_F(0x05b7927f) /* 0.357317446 */, 16 }, + /* 1894 */ { MAD_F(0x05b89a6c) /* 0.357569145 */, 16 }, + /* 1895 */ { MAD_F(0x05b9a265) /* 0.357820887 */, 16 }, + /* 1896 */ { MAD_F(0x05baaa69) /* 0.358072674 */, 16 }, + /* 1897 */ { MAD_F(0x05bbb27a) /* 0.358324506 */, 16 }, + /* 1898 */ { MAD_F(0x05bcba96) /* 0.358576381 */, 16 }, + /* 1899 */ { MAD_F(0x05bdc2be) /* 0.358828301 */, 16 }, + /* 1900 */ { MAD_F(0x05becaf2) /* 0.359080265 */, 16 }, + /* 1901 */ { MAD_F(0x05bfd332) /* 0.359332273 */, 16 }, + /* 1902 */ { MAD_F(0x05c0db7e) /* 0.359584326 */, 16 }, + /* 1903 */ { MAD_F(0x05c1e3d6) /* 0.359836423 */, 16 }, + + /* 1904 */ { MAD_F(0x05c2ec39) /* 0.360088563 */, 16 }, + /* 1905 */ { MAD_F(0x05c3f4a9) /* 0.360340748 */, 16 }, + /* 1906 */ { MAD_F(0x05c4fd24) /* 0.360592977 */, 16 }, + /* 1907 */ { MAD_F(0x05c605ab) /* 0.360845251 */, 16 }, + /* 1908 */ { MAD_F(0x05c70e3e) /* 0.361097568 */, 16 }, + /* 1909 */ { MAD_F(0x05c816dd) /* 0.361349929 */, 16 }, + /* 1910 */ { MAD_F(0x05c91f87) /* 0.361602335 */, 16 }, + /* 1911 */ { MAD_F(0x05ca283e) /* 0.361854784 */, 16 }, + /* 1912 */ { MAD_F(0x05cb3100) /* 0.362107278 */, 16 }, + /* 1913 */ { MAD_F(0x05cc39ce) /* 0.362359815 */, 16 }, + /* 1914 */ { MAD_F(0x05cd42a8) /* 0.362612397 */, 16 }, + /* 1915 */ { MAD_F(0x05ce4b8d) /* 0.362865022 */, 16 }, + /* 1916 */ { MAD_F(0x05cf547f) /* 0.363117692 */, 16 }, + /* 1917 */ { MAD_F(0x05d05d7c) /* 0.363370405 */, 16 }, + /* 1918 */ { MAD_F(0x05d16685) /* 0.363623163 */, 16 }, + /* 1919 */ { MAD_F(0x05d26f9a) /* 0.363875964 */, 16 }, + + /* 1920 */ { MAD_F(0x05d378bb) /* 0.364128809 */, 16 }, + /* 1921 */ { MAD_F(0x05d481e7) /* 0.364381698 */, 16 }, + /* 1922 */ { MAD_F(0x05d58b1f) /* 0.364634632 */, 16 }, + /* 1923 */ { MAD_F(0x05d69463) /* 0.364887608 */, 16 }, + /* 1924 */ { MAD_F(0x05d79db3) /* 0.365140629 */, 16 }, + /* 1925 */ { MAD_F(0x05d8a70f) /* 0.365393694 */, 16 }, + /* 1926 */ { MAD_F(0x05d9b076) /* 0.365646802 */, 16 }, + /* 1927 */ { MAD_F(0x05dab9e9) /* 0.365899955 */, 16 }, + /* 1928 */ { MAD_F(0x05dbc368) /* 0.366153151 */, 16 }, + /* 1929 */ { MAD_F(0x05dcccf2) /* 0.366406390 */, 16 }, + /* 1930 */ { MAD_F(0x05ddd689) /* 0.366659674 */, 16 }, + /* 1931 */ { MAD_F(0x05dee02b) /* 0.366913001 */, 16 }, + /* 1932 */ { MAD_F(0x05dfe9d8) /* 0.367166372 */, 16 }, + /* 1933 */ { MAD_F(0x05e0f392) /* 0.367419787 */, 16 }, + /* 1934 */ { MAD_F(0x05e1fd57) /* 0.367673246 */, 16 }, + /* 1935 */ { MAD_F(0x05e30728) /* 0.367926748 */, 16 }, + + /* 1936 */ { MAD_F(0x05e41105) /* 0.368180294 */, 16 }, + /* 1937 */ { MAD_F(0x05e51aed) /* 0.368433883 */, 16 }, + /* 1938 */ { MAD_F(0x05e624e1) /* 0.368687517 */, 16 }, + /* 1939 */ { MAD_F(0x05e72ee1) /* 0.368941193 */, 16 }, + /* 1940 */ { MAD_F(0x05e838ed) /* 0.369194914 */, 16 }, + /* 1941 */ { MAD_F(0x05e94304) /* 0.369448678 */, 16 }, + /* 1942 */ { MAD_F(0x05ea4d27) /* 0.369702485 */, 16 }, + /* 1943 */ { MAD_F(0x05eb5756) /* 0.369956336 */, 16 }, + /* 1944 */ { MAD_F(0x05ec6190) /* 0.370210231 */, 16 }, + /* 1945 */ { MAD_F(0x05ed6bd6) /* 0.370464169 */, 16 }, + /* 1946 */ { MAD_F(0x05ee7628) /* 0.370718151 */, 16 }, + /* 1947 */ { MAD_F(0x05ef8085) /* 0.370972177 */, 16 }, + /* 1948 */ { MAD_F(0x05f08aee) /* 0.371226245 */, 16 }, + /* 1949 */ { MAD_F(0x05f19563) /* 0.371480358 */, 16 }, + /* 1950 */ { MAD_F(0x05f29fe3) /* 0.371734513 */, 16 }, + /* 1951 */ { MAD_F(0x05f3aa6f) /* 0.371988712 */, 16 }, + + /* 1952 */ { MAD_F(0x05f4b507) /* 0.372242955 */, 16 }, + /* 1953 */ { MAD_F(0x05f5bfab) /* 0.372497241 */, 16 }, + /* 1954 */ { MAD_F(0x05f6ca5a) /* 0.372751570 */, 16 }, + /* 1955 */ { MAD_F(0x05f7d514) /* 0.373005943 */, 16 }, + /* 1956 */ { MAD_F(0x05f8dfdb) /* 0.373260359 */, 16 }, + /* 1957 */ { MAD_F(0x05f9eaad) /* 0.373514819 */, 16 }, + /* 1958 */ { MAD_F(0x05faf58a) /* 0.373769322 */, 16 }, + /* 1959 */ { MAD_F(0x05fc0073) /* 0.374023868 */, 16 }, + /* 1960 */ { MAD_F(0x05fd0b68) /* 0.374278458 */, 16 }, + /* 1961 */ { MAD_F(0x05fe1669) /* 0.374533091 */, 16 }, + /* 1962 */ { MAD_F(0x05ff2175) /* 0.374787767 */, 16 }, + /* 1963 */ { MAD_F(0x06002c8d) /* 0.375042486 */, 16 }, + /* 1964 */ { MAD_F(0x060137b0) /* 0.375297249 */, 16 }, + /* 1965 */ { MAD_F(0x060242df) /* 0.375552055 */, 16 }, + /* 1966 */ { MAD_F(0x06034e19) /* 0.375806904 */, 16 }, + /* 1967 */ { MAD_F(0x0604595f) /* 0.376061796 */, 16 }, + + /* 1968 */ { MAD_F(0x060564b1) /* 0.376316732 */, 16 }, + /* 1969 */ { MAD_F(0x0606700f) /* 0.376571710 */, 16 }, + /* 1970 */ { MAD_F(0x06077b77) /* 0.376826732 */, 16 }, + /* 1971 */ { MAD_F(0x060886ec) /* 0.377081797 */, 16 }, + /* 1972 */ { MAD_F(0x0609926c) /* 0.377336905 */, 16 }, + /* 1973 */ { MAD_F(0x060a9df8) /* 0.377592057 */, 16 }, + /* 1974 */ { MAD_F(0x060ba98f) /* 0.377847251 */, 16 }, + /* 1975 */ { MAD_F(0x060cb532) /* 0.378102489 */, 16 }, + /* 1976 */ { MAD_F(0x060dc0e0) /* 0.378357769 */, 16 }, + /* 1977 */ { MAD_F(0x060ecc9a) /* 0.378613093 */, 16 }, + /* 1978 */ { MAD_F(0x060fd860) /* 0.378868460 */, 16 }, + /* 1979 */ { MAD_F(0x0610e431) /* 0.379123870 */, 16 }, + /* 1980 */ { MAD_F(0x0611f00d) /* 0.379379322 */, 16 }, + /* 1981 */ { MAD_F(0x0612fbf5) /* 0.379634818 */, 16 }, + /* 1982 */ { MAD_F(0x061407e9) /* 0.379890357 */, 16 }, + /* 1983 */ { MAD_F(0x061513e8) /* 0.380145939 */, 16 }, + + /* 1984 */ { MAD_F(0x06161ff3) /* 0.380401563 */, 16 }, + /* 1985 */ { MAD_F(0x06172c09) /* 0.380657231 */, 16 }, + /* 1986 */ { MAD_F(0x0618382b) /* 0.380912942 */, 16 }, + /* 1987 */ { MAD_F(0x06194458) /* 0.381168695 */, 16 }, + /* 1988 */ { MAD_F(0x061a5091) /* 0.381424492 */, 16 }, + /* 1989 */ { MAD_F(0x061b5cd5) /* 0.381680331 */, 16 }, + /* 1990 */ { MAD_F(0x061c6925) /* 0.381936213 */, 16 }, + /* 1991 */ { MAD_F(0x061d7581) /* 0.382192138 */, 16 }, + /* 1992 */ { MAD_F(0x061e81e8) /* 0.382448106 */, 16 }, + /* 1993 */ { MAD_F(0x061f8e5a) /* 0.382704117 */, 16 }, + /* 1994 */ { MAD_F(0x06209ad8) /* 0.382960171 */, 16 }, + /* 1995 */ { MAD_F(0x0621a761) /* 0.383216267 */, 16 }, + /* 1996 */ { MAD_F(0x0622b3f6) /* 0.383472406 */, 16 }, + /* 1997 */ { MAD_F(0x0623c096) /* 0.383728588 */, 16 }, + /* 1998 */ { MAD_F(0x0624cd42) /* 0.383984813 */, 16 }, + /* 1999 */ { MAD_F(0x0625d9f9) /* 0.384241080 */, 16 }, + + /* 2000 */ { MAD_F(0x0626e6bc) /* 0.384497391 */, 16 }, + /* 2001 */ { MAD_F(0x0627f38a) /* 0.384753744 */, 16 }, + /* 2002 */ { MAD_F(0x06290064) /* 0.385010139 */, 16 }, + /* 2003 */ { MAD_F(0x062a0d49) /* 0.385266578 */, 16 }, + /* 2004 */ { MAD_F(0x062b1a3a) /* 0.385523059 */, 16 }, + /* 2005 */ { MAD_F(0x062c2736) /* 0.385779582 */, 16 }, + /* 2006 */ { MAD_F(0x062d343d) /* 0.386036149 */, 16 }, + /* 2007 */ { MAD_F(0x062e4150) /* 0.386292758 */, 16 }, + /* 2008 */ { MAD_F(0x062f4e6f) /* 0.386549409 */, 16 }, + /* 2009 */ { MAD_F(0x06305b99) /* 0.386806104 */, 16 }, + /* 2010 */ { MAD_F(0x063168ce) /* 0.387062840 */, 16 }, + /* 2011 */ { MAD_F(0x0632760f) /* 0.387319620 */, 16 }, + /* 2012 */ { MAD_F(0x0633835b) /* 0.387576442 */, 16 }, + /* 2013 */ { MAD_F(0x063490b2) /* 0.387833306 */, 16 }, + /* 2014 */ { MAD_F(0x06359e15) /* 0.388090213 */, 16 }, + /* 2015 */ { MAD_F(0x0636ab83) /* 0.388347163 */, 16 }, + + /* 2016 */ { MAD_F(0x0637b8fd) /* 0.388604155 */, 16 }, + /* 2017 */ { MAD_F(0x0638c682) /* 0.388861190 */, 16 }, + /* 2018 */ { MAD_F(0x0639d413) /* 0.389118267 */, 16 }, + /* 2019 */ { MAD_F(0x063ae1af) /* 0.389375386 */, 16 }, + /* 2020 */ { MAD_F(0x063bef56) /* 0.389632548 */, 16 }, + /* 2021 */ { MAD_F(0x063cfd09) /* 0.389889752 */, 16 }, + /* 2022 */ { MAD_F(0x063e0ac7) /* 0.390146999 */, 16 }, + /* 2023 */ { MAD_F(0x063f1891) /* 0.390404289 */, 16 }, + /* 2024 */ { MAD_F(0x06402666) /* 0.390661620 */, 16 }, + /* 2025 */ { MAD_F(0x06413446) /* 0.390918994 */, 16 }, + /* 2026 */ { MAD_F(0x06424232) /* 0.391176411 */, 16 }, + /* 2027 */ { MAD_F(0x06435029) /* 0.391433869 */, 16 }, + /* 2028 */ { MAD_F(0x06445e2b) /* 0.391691371 */, 16 }, + /* 2029 */ { MAD_F(0x06456c39) /* 0.391948914 */, 16 }, + /* 2030 */ { MAD_F(0x06467a52) /* 0.392206500 */, 16 }, + /* 2031 */ { MAD_F(0x06478877) /* 0.392464128 */, 16 }, + + /* 2032 */ { MAD_F(0x064896a7) /* 0.392721798 */, 16 }, + /* 2033 */ { MAD_F(0x0649a4e2) /* 0.392979511 */, 16 }, + /* 2034 */ { MAD_F(0x064ab328) /* 0.393237266 */, 16 }, + /* 2035 */ { MAD_F(0x064bc17a) /* 0.393495063 */, 16 }, + /* 2036 */ { MAD_F(0x064ccfd8) /* 0.393752902 */, 16 }, + /* 2037 */ { MAD_F(0x064dde40) /* 0.394010784 */, 16 }, + /* 2038 */ { MAD_F(0x064eecb4) /* 0.394268707 */, 16 }, + /* 2039 */ { MAD_F(0x064ffb33) /* 0.394526673 */, 16 }, + /* 2040 */ { MAD_F(0x065109be) /* 0.394784681 */, 16 }, + /* 2041 */ { MAD_F(0x06521854) /* 0.395042732 */, 16 }, + /* 2042 */ { MAD_F(0x065326f5) /* 0.395300824 */, 16 }, + /* 2043 */ { MAD_F(0x065435a1) /* 0.395558959 */, 16 }, + /* 2044 */ { MAD_F(0x06554459) /* 0.395817135 */, 16 }, + /* 2045 */ { MAD_F(0x0656531c) /* 0.396075354 */, 16 }, + /* 2046 */ { MAD_F(0x065761ea) /* 0.396333615 */, 16 }, + /* 2047 */ { MAD_F(0x065870c4) /* 0.396591918 */, 16 }, + + /* 2048 */ { MAD_F(0x06597fa9) /* 0.396850263 */, 16 }, + /* 2049 */ { MAD_F(0x065a8e99) /* 0.397108650 */, 16 }, + /* 2050 */ { MAD_F(0x065b9d95) /* 0.397367079 */, 16 }, + /* 2051 */ { MAD_F(0x065cac9c) /* 0.397625550 */, 16 }, + /* 2052 */ { MAD_F(0x065dbbae) /* 0.397884063 */, 16 }, + /* 2053 */ { MAD_F(0x065ecacb) /* 0.398142619 */, 16 }, + /* 2054 */ { MAD_F(0x065fd9f4) /* 0.398401216 */, 16 }, + /* 2055 */ { MAD_F(0x0660e928) /* 0.398659855 */, 16 }, + /* 2056 */ { MAD_F(0x0661f867) /* 0.398918536 */, 16 }, + /* 2057 */ { MAD_F(0x066307b1) /* 0.399177259 */, 16 }, + /* 2058 */ { MAD_F(0x06641707) /* 0.399436024 */, 16 }, + /* 2059 */ { MAD_F(0x06652668) /* 0.399694831 */, 16 }, + /* 2060 */ { MAD_F(0x066635d4) /* 0.399953679 */, 16 }, + /* 2061 */ { MAD_F(0x0667454c) /* 0.400212570 */, 16 }, + /* 2062 */ { MAD_F(0x066854ce) /* 0.400471503 */, 16 }, + /* 2063 */ { MAD_F(0x0669645c) /* 0.400730477 */, 16 }, + + /* 2064 */ { MAD_F(0x066a73f5) /* 0.400989493 */, 16 }, + /* 2065 */ { MAD_F(0x066b839a) /* 0.401248551 */, 16 }, + /* 2066 */ { MAD_F(0x066c9349) /* 0.401507651 */, 16 }, + /* 2067 */ { MAD_F(0x066da304) /* 0.401766793 */, 16 }, + /* 2068 */ { MAD_F(0x066eb2ca) /* 0.402025976 */, 16 }, + /* 2069 */ { MAD_F(0x066fc29b) /* 0.402285202 */, 16 }, + /* 2070 */ { MAD_F(0x0670d278) /* 0.402544469 */, 16 }, + /* 2071 */ { MAD_F(0x0671e25f) /* 0.402803777 */, 16 }, + /* 2072 */ { MAD_F(0x0672f252) /* 0.403063128 */, 16 }, + /* 2073 */ { MAD_F(0x06740250) /* 0.403322520 */, 16 }, + /* 2074 */ { MAD_F(0x0675125a) /* 0.403581954 */, 16 }, + /* 2075 */ { MAD_F(0x0676226e) /* 0.403841430 */, 16 }, + /* 2076 */ { MAD_F(0x0677328e) /* 0.404100947 */, 16 }, + /* 2077 */ { MAD_F(0x067842b9) /* 0.404360506 */, 16 }, + /* 2078 */ { MAD_F(0x067952ef) /* 0.404620107 */, 16 }, + /* 2079 */ { MAD_F(0x067a6330) /* 0.404879749 */, 16 }, + + /* 2080 */ { MAD_F(0x067b737c) /* 0.405139433 */, 16 }, + /* 2081 */ { MAD_F(0x067c83d4) /* 0.405399159 */, 16 }, + /* 2082 */ { MAD_F(0x067d9436) /* 0.405658926 */, 16 }, + /* 2083 */ { MAD_F(0x067ea4a4) /* 0.405918735 */, 16 }, + /* 2084 */ { MAD_F(0x067fb51d) /* 0.406178585 */, 16 }, + /* 2085 */ { MAD_F(0x0680c5a2) /* 0.406438477 */, 16 }, + /* 2086 */ { MAD_F(0x0681d631) /* 0.406698410 */, 16 }, + /* 2087 */ { MAD_F(0x0682e6cb) /* 0.406958385 */, 16 }, + /* 2088 */ { MAD_F(0x0683f771) /* 0.407218402 */, 16 }, + /* 2089 */ { MAD_F(0x06850822) /* 0.407478460 */, 16 }, + /* 2090 */ { MAD_F(0x068618de) /* 0.407738559 */, 16 }, + /* 2091 */ { MAD_F(0x068729a5) /* 0.407998700 */, 16 }, + /* 2092 */ { MAD_F(0x06883a77) /* 0.408258883 */, 16 }, + /* 2093 */ { MAD_F(0x06894b55) /* 0.408519107 */, 16 }, + /* 2094 */ { MAD_F(0x068a5c3d) /* 0.408779372 */, 16 }, + /* 2095 */ { MAD_F(0x068b6d31) /* 0.409039679 */, 16 }, + + /* 2096 */ { MAD_F(0x068c7e2f) /* 0.409300027 */, 16 }, + /* 2097 */ { MAD_F(0x068d8f39) /* 0.409560417 */, 16 }, + /* 2098 */ { MAD_F(0x068ea04e) /* 0.409820848 */, 16 }, + /* 2099 */ { MAD_F(0x068fb16e) /* 0.410081321 */, 16 }, + /* 2100 */ { MAD_F(0x0690c299) /* 0.410341834 */, 16 }, + /* 2101 */ { MAD_F(0x0691d3cf) /* 0.410602390 */, 16 }, + /* 2102 */ { MAD_F(0x0692e511) /* 0.410862986 */, 16 }, + /* 2103 */ { MAD_F(0x0693f65d) /* 0.411123624 */, 16 }, + /* 2104 */ { MAD_F(0x069507b5) /* 0.411384303 */, 16 }, + /* 2105 */ { MAD_F(0x06961917) /* 0.411645024 */, 16 }, + /* 2106 */ { MAD_F(0x06972a85) /* 0.411905785 */, 16 }, + /* 2107 */ { MAD_F(0x06983bfe) /* 0.412166588 */, 16 }, + /* 2108 */ { MAD_F(0x06994d82) /* 0.412427433 */, 16 }, + /* 2109 */ { MAD_F(0x069a5f11) /* 0.412688318 */, 16 }, + /* 2110 */ { MAD_F(0x069b70ab) /* 0.412949245 */, 16 }, + /* 2111 */ { MAD_F(0x069c8250) /* 0.413210213 */, 16 }, + + /* 2112 */ { MAD_F(0x069d9400) /* 0.413471222 */, 16 }, + /* 2113 */ { MAD_F(0x069ea5bb) /* 0.413732273 */, 16 }, + /* 2114 */ { MAD_F(0x069fb781) /* 0.413993364 */, 16 }, + /* 2115 */ { MAD_F(0x06a0c953) /* 0.414254497 */, 16 }, + /* 2116 */ { MAD_F(0x06a1db2f) /* 0.414515671 */, 16 }, + /* 2117 */ { MAD_F(0x06a2ed16) /* 0.414776886 */, 16 }, + /* 2118 */ { MAD_F(0x06a3ff09) /* 0.415038142 */, 16 }, + /* 2119 */ { MAD_F(0x06a51106) /* 0.415299440 */, 16 }, + /* 2120 */ { MAD_F(0x06a6230f) /* 0.415560778 */, 16 }, + /* 2121 */ { MAD_F(0x06a73522) /* 0.415822157 */, 16 }, + /* 2122 */ { MAD_F(0x06a84741) /* 0.416083578 */, 16 }, + /* 2123 */ { MAD_F(0x06a9596a) /* 0.416345040 */, 16 }, + /* 2124 */ { MAD_F(0x06aa6b9f) /* 0.416606542 */, 16 }, + /* 2125 */ { MAD_F(0x06ab7ddf) /* 0.416868086 */, 16 }, + /* 2126 */ { MAD_F(0x06ac9029) /* 0.417129671 */, 16 }, + /* 2127 */ { MAD_F(0x06ada27f) /* 0.417391297 */, 16 }, + + /* 2128 */ { MAD_F(0x06aeb4e0) /* 0.417652964 */, 16 }, + /* 2129 */ { MAD_F(0x06afc74b) /* 0.417914672 */, 16 }, + /* 2130 */ { MAD_F(0x06b0d9c2) /* 0.418176420 */, 16 }, + /* 2131 */ { MAD_F(0x06b1ec43) /* 0.418438210 */, 16 }, + /* 2132 */ { MAD_F(0x06b2fed0) /* 0.418700041 */, 16 }, + /* 2133 */ { MAD_F(0x06b41168) /* 0.418961912 */, 16 }, + /* 2134 */ { MAD_F(0x06b5240a) /* 0.419223825 */, 16 }, + /* 2135 */ { MAD_F(0x06b636b8) /* 0.419485778 */, 16 }, + /* 2136 */ { MAD_F(0x06b74971) /* 0.419747773 */, 16 }, + /* 2137 */ { MAD_F(0x06b85c34) /* 0.420009808 */, 16 }, + /* 2138 */ { MAD_F(0x06b96f03) /* 0.420271884 */, 16 }, + /* 2139 */ { MAD_F(0x06ba81dc) /* 0.420534001 */, 16 }, + /* 2140 */ { MAD_F(0x06bb94c1) /* 0.420796159 */, 16 }, + /* 2141 */ { MAD_F(0x06bca7b0) /* 0.421058358 */, 16 }, + /* 2142 */ { MAD_F(0x06bdbaaa) /* 0.421320597 */, 16 }, + /* 2143 */ { MAD_F(0x06becdb0) /* 0.421582878 */, 16 }, + + /* 2144 */ { MAD_F(0x06bfe0c0) /* 0.421845199 */, 16 }, + /* 2145 */ { MAD_F(0x06c0f3db) /* 0.422107561 */, 16 }, + /* 2146 */ { MAD_F(0x06c20702) /* 0.422369964 */, 16 }, + /* 2147 */ { MAD_F(0x06c31a33) /* 0.422632407 */, 16 }, + /* 2148 */ { MAD_F(0x06c42d6f) /* 0.422894891 */, 16 }, + /* 2149 */ { MAD_F(0x06c540b6) /* 0.423157416 */, 16 }, + /* 2150 */ { MAD_F(0x06c65408) /* 0.423419982 */, 16 }, + /* 2151 */ { MAD_F(0x06c76765) /* 0.423682588 */, 16 }, + /* 2152 */ { MAD_F(0x06c87acc) /* 0.423945235 */, 16 }, + /* 2153 */ { MAD_F(0x06c98e3f) /* 0.424207923 */, 16 }, + /* 2154 */ { MAD_F(0x06caa1bd) /* 0.424470652 */, 16 }, + /* 2155 */ { MAD_F(0x06cbb545) /* 0.424733421 */, 16 }, + /* 2156 */ { MAD_F(0x06ccc8d9) /* 0.424996230 */, 16 }, + /* 2157 */ { MAD_F(0x06cddc77) /* 0.425259081 */, 16 }, + /* 2158 */ { MAD_F(0x06cef020) /* 0.425521972 */, 16 }, + /* 2159 */ { MAD_F(0x06d003d4) /* 0.425784903 */, 16 }, + + /* 2160 */ { MAD_F(0x06d11794) /* 0.426047876 */, 16 }, + /* 2161 */ { MAD_F(0x06d22b5e) /* 0.426310889 */, 16 }, + /* 2162 */ { MAD_F(0x06d33f32) /* 0.426573942 */, 16 }, + /* 2163 */ { MAD_F(0x06d45312) /* 0.426837036 */, 16 }, + /* 2164 */ { MAD_F(0x06d566fd) /* 0.427100170 */, 16 }, + /* 2165 */ { MAD_F(0x06d67af2) /* 0.427363345 */, 16 }, + /* 2166 */ { MAD_F(0x06d78ef3) /* 0.427626561 */, 16 }, + /* 2167 */ { MAD_F(0x06d8a2fe) /* 0.427889817 */, 16 }, + /* 2168 */ { MAD_F(0x06d9b714) /* 0.428153114 */, 16 }, + /* 2169 */ { MAD_F(0x06dacb35) /* 0.428416451 */, 16 }, + /* 2170 */ { MAD_F(0x06dbdf61) /* 0.428679828 */, 16 }, + /* 2171 */ { MAD_F(0x06dcf398) /* 0.428943246 */, 16 }, + /* 2172 */ { MAD_F(0x06de07d9) /* 0.429206704 */, 16 }, + /* 2173 */ { MAD_F(0x06df1c26) /* 0.429470203 */, 16 }, + /* 2174 */ { MAD_F(0x06e0307d) /* 0.429733743 */, 16 }, + /* 2175 */ { MAD_F(0x06e144df) /* 0.429997322 */, 16 }, + + /* 2176 */ { MAD_F(0x06e2594c) /* 0.430260942 */, 16 }, + /* 2177 */ { MAD_F(0x06e36dc4) /* 0.430524603 */, 16 }, + /* 2178 */ { MAD_F(0x06e48246) /* 0.430788304 */, 16 }, + /* 2179 */ { MAD_F(0x06e596d4) /* 0.431052045 */, 16 }, + /* 2180 */ { MAD_F(0x06e6ab6c) /* 0.431315826 */, 16 }, + /* 2181 */ { MAD_F(0x06e7c00f) /* 0.431579648 */, 16 }, + /* 2182 */ { MAD_F(0x06e8d4bd) /* 0.431843511 */, 16 }, + /* 2183 */ { MAD_F(0x06e9e976) /* 0.432107413 */, 16 }, + /* 2184 */ { MAD_F(0x06eafe3a) /* 0.432371356 */, 16 }, + /* 2185 */ { MAD_F(0x06ec1308) /* 0.432635339 */, 16 }, + /* 2186 */ { MAD_F(0x06ed27e2) /* 0.432899362 */, 16 }, + /* 2187 */ { MAD_F(0x06ee3cc6) /* 0.433163426 */, 16 }, + /* 2188 */ { MAD_F(0x06ef51b4) /* 0.433427530 */, 16 }, + /* 2189 */ { MAD_F(0x06f066ae) /* 0.433691674 */, 16 }, + /* 2190 */ { MAD_F(0x06f17bb3) /* 0.433955859 */, 16 }, + /* 2191 */ { MAD_F(0x06f290c2) /* 0.434220083 */, 16 }, + + /* 2192 */ { MAD_F(0x06f3a5dc) /* 0.434484348 */, 16 }, + /* 2193 */ { MAD_F(0x06f4bb01) /* 0.434748653 */, 16 }, + /* 2194 */ { MAD_F(0x06f5d030) /* 0.435012998 */, 16 }, + /* 2195 */ { MAD_F(0x06f6e56b) /* 0.435277383 */, 16 }, + /* 2196 */ { MAD_F(0x06f7fab0) /* 0.435541809 */, 16 }, + /* 2197 */ { MAD_F(0x06f91000) /* 0.435806274 */, 16 }, + /* 2198 */ { MAD_F(0x06fa255a) /* 0.436070780 */, 16 }, + /* 2199 */ { MAD_F(0x06fb3ac0) /* 0.436335326 */, 16 }, + /* 2200 */ { MAD_F(0x06fc5030) /* 0.436599912 */, 16 }, + /* 2201 */ { MAD_F(0x06fd65ab) /* 0.436864538 */, 16 }, + /* 2202 */ { MAD_F(0x06fe7b31) /* 0.437129204 */, 16 }, + /* 2203 */ { MAD_F(0x06ff90c2) /* 0.437393910 */, 16 }, + /* 2204 */ { MAD_F(0x0700a65d) /* 0.437658657 */, 16 }, + /* 2205 */ { MAD_F(0x0701bc03) /* 0.437923443 */, 16 }, + /* 2206 */ { MAD_F(0x0702d1b4) /* 0.438188269 */, 16 }, + /* 2207 */ { MAD_F(0x0703e76f) /* 0.438453136 */, 16 }, + + /* 2208 */ { MAD_F(0x0704fd35) /* 0.438718042 */, 16 }, + /* 2209 */ { MAD_F(0x07061306) /* 0.438982988 */, 16 }, + /* 2210 */ { MAD_F(0x070728e2) /* 0.439247975 */, 16 }, + /* 2211 */ { MAD_F(0x07083ec9) /* 0.439513001 */, 16 }, + /* 2212 */ { MAD_F(0x070954ba) /* 0.439778067 */, 16 }, + /* 2213 */ { MAD_F(0x070a6ab6) /* 0.440043173 */, 16 }, + /* 2214 */ { MAD_F(0x070b80bc) /* 0.440308320 */, 16 }, + /* 2215 */ { MAD_F(0x070c96ce) /* 0.440573506 */, 16 }, + /* 2216 */ { MAD_F(0x070dacea) /* 0.440838732 */, 16 }, + /* 2217 */ { MAD_F(0x070ec310) /* 0.441103997 */, 16 }, + /* 2218 */ { MAD_F(0x070fd942) /* 0.441369303 */, 16 }, + /* 2219 */ { MAD_F(0x0710ef7e) /* 0.441634649 */, 16 }, + /* 2220 */ { MAD_F(0x071205c5) /* 0.441900034 */, 16 }, + /* 2221 */ { MAD_F(0x07131c17) /* 0.442165460 */, 16 }, + /* 2222 */ { MAD_F(0x07143273) /* 0.442430925 */, 16 }, + /* 2223 */ { MAD_F(0x071548da) /* 0.442696430 */, 16 }, + + /* 2224 */ { MAD_F(0x07165f4b) /* 0.442961975 */, 16 }, + /* 2225 */ { MAD_F(0x071775c8) /* 0.443227559 */, 16 }, + /* 2226 */ { MAD_F(0x07188c4f) /* 0.443493184 */, 16 }, + /* 2227 */ { MAD_F(0x0719a2e0) /* 0.443758848 */, 16 }, + /* 2228 */ { MAD_F(0x071ab97d) /* 0.444024552 */, 16 }, + /* 2229 */ { MAD_F(0x071bd024) /* 0.444290296 */, 16 }, + /* 2230 */ { MAD_F(0x071ce6d6) /* 0.444556079 */, 16 }, + /* 2231 */ { MAD_F(0x071dfd92) /* 0.444821902 */, 16 }, + /* 2232 */ { MAD_F(0x071f1459) /* 0.445087765 */, 16 }, + /* 2233 */ { MAD_F(0x07202b2b) /* 0.445353668 */, 16 }, + /* 2234 */ { MAD_F(0x07214207) /* 0.445619610 */, 16 }, + /* 2235 */ { MAD_F(0x072258ee) /* 0.445885592 */, 16 }, + /* 2236 */ { MAD_F(0x07236fe0) /* 0.446151614 */, 16 }, + /* 2237 */ { MAD_F(0x072486dc) /* 0.446417675 */, 16 }, + /* 2238 */ { MAD_F(0x07259de3) /* 0.446683776 */, 16 }, + /* 2239 */ { MAD_F(0x0726b4f4) /* 0.446949917 */, 16 }, + + /* 2240 */ { MAD_F(0x0727cc11) /* 0.447216097 */, 16 }, + /* 2241 */ { MAD_F(0x0728e338) /* 0.447482317 */, 16 }, + /* 2242 */ { MAD_F(0x0729fa69) /* 0.447748576 */, 16 }, + /* 2243 */ { MAD_F(0x072b11a5) /* 0.448014875 */, 16 }, + /* 2244 */ { MAD_F(0x072c28ec) /* 0.448281214 */, 16 }, + /* 2245 */ { MAD_F(0x072d403d) /* 0.448547592 */, 16 }, + /* 2246 */ { MAD_F(0x072e5799) /* 0.448814010 */, 16 }, + /* 2247 */ { MAD_F(0x072f6f00) /* 0.449080467 */, 16 }, + /* 2248 */ { MAD_F(0x07308671) /* 0.449346964 */, 16 }, + /* 2249 */ { MAD_F(0x07319ded) /* 0.449613501 */, 16 }, + /* 2250 */ { MAD_F(0x0732b573) /* 0.449880076 */, 16 }, + /* 2251 */ { MAD_F(0x0733cd04) /* 0.450146692 */, 16 }, + /* 2252 */ { MAD_F(0x0734e4a0) /* 0.450413347 */, 16 }, + /* 2253 */ { MAD_F(0x0735fc46) /* 0.450680041 */, 16 }, + /* 2254 */ { MAD_F(0x073713f7) /* 0.450946775 */, 16 }, + /* 2255 */ { MAD_F(0x07382bb2) /* 0.451213548 */, 16 }, + + /* 2256 */ { MAD_F(0x07394378) /* 0.451480360 */, 16 }, + /* 2257 */ { MAD_F(0x073a5b49) /* 0.451747213 */, 16 }, + /* 2258 */ { MAD_F(0x073b7324) /* 0.452014104 */, 16 }, + /* 2259 */ { MAD_F(0x073c8b0a) /* 0.452281035 */, 16 }, + /* 2260 */ { MAD_F(0x073da2fa) /* 0.452548005 */, 16 }, + /* 2261 */ { MAD_F(0x073ebaf5) /* 0.452815015 */, 16 }, + /* 2262 */ { MAD_F(0x073fd2fa) /* 0.453082064 */, 16 }, + /* 2263 */ { MAD_F(0x0740eb0a) /* 0.453349152 */, 16 }, + /* 2264 */ { MAD_F(0x07420325) /* 0.453616280 */, 16 }, + /* 2265 */ { MAD_F(0x07431b4a) /* 0.453883447 */, 16 }, + /* 2266 */ { MAD_F(0x0744337a) /* 0.454150653 */, 16 }, + /* 2267 */ { MAD_F(0x07454bb4) /* 0.454417899 */, 16 }, + /* 2268 */ { MAD_F(0x074663f8) /* 0.454685184 */, 16 }, + /* 2269 */ { MAD_F(0x07477c48) /* 0.454952508 */, 16 }, + /* 2270 */ { MAD_F(0x074894a2) /* 0.455219872 */, 16 }, + /* 2271 */ { MAD_F(0x0749ad06) /* 0.455487275 */, 16 }, + + /* 2272 */ { MAD_F(0x074ac575) /* 0.455754717 */, 16 }, + /* 2273 */ { MAD_F(0x074bddee) /* 0.456022198 */, 16 }, + /* 2274 */ { MAD_F(0x074cf672) /* 0.456289719 */, 16 }, + /* 2275 */ { MAD_F(0x074e0f01) /* 0.456557278 */, 16 }, + /* 2276 */ { MAD_F(0x074f279a) /* 0.456824877 */, 16 }, + /* 2277 */ { MAD_F(0x0750403e) /* 0.457092516 */, 16 }, + /* 2278 */ { MAD_F(0x075158ec) /* 0.457360193 */, 16 }, + /* 2279 */ { MAD_F(0x075271a4) /* 0.457627909 */, 16 }, + /* 2280 */ { MAD_F(0x07538a67) /* 0.457895665 */, 16 }, + /* 2281 */ { MAD_F(0x0754a335) /* 0.458163460 */, 16 }, + /* 2282 */ { MAD_F(0x0755bc0d) /* 0.458431294 */, 16 }, + /* 2283 */ { MAD_F(0x0756d4f0) /* 0.458699167 */, 16 }, + /* 2284 */ { MAD_F(0x0757eddd) /* 0.458967079 */, 16 }, + /* 2285 */ { MAD_F(0x075906d5) /* 0.459235030 */, 16 }, + /* 2286 */ { MAD_F(0x075a1fd7) /* 0.459503021 */, 16 }, + /* 2287 */ { MAD_F(0x075b38e3) /* 0.459771050 */, 16 }, + + /* 2288 */ { MAD_F(0x075c51fa) /* 0.460039119 */, 16 }, + /* 2289 */ { MAD_F(0x075d6b1c) /* 0.460307226 */, 16 }, + /* 2290 */ { MAD_F(0x075e8448) /* 0.460575373 */, 16 }, + /* 2291 */ { MAD_F(0x075f9d7f) /* 0.460843559 */, 16 }, + /* 2292 */ { MAD_F(0x0760b6c0) /* 0.461111783 */, 16 }, + /* 2293 */ { MAD_F(0x0761d00b) /* 0.461380047 */, 16 }, + /* 2294 */ { MAD_F(0x0762e961) /* 0.461648350 */, 16 }, + /* 2295 */ { MAD_F(0x076402c1) /* 0.461916691 */, 16 }, + /* 2296 */ { MAD_F(0x07651c2c) /* 0.462185072 */, 16 }, + /* 2297 */ { MAD_F(0x076635a2) /* 0.462453492 */, 16 }, + /* 2298 */ { MAD_F(0x07674f22) /* 0.462721950 */, 16 }, + /* 2299 */ { MAD_F(0x076868ac) /* 0.462990448 */, 16 }, + /* 2300 */ { MAD_F(0x07698240) /* 0.463258984 */, 16 }, + /* 2301 */ { MAD_F(0x076a9be0) /* 0.463527560 */, 16 }, + /* 2302 */ { MAD_F(0x076bb589) /* 0.463796174 */, 16 }, + /* 2303 */ { MAD_F(0x076ccf3d) /* 0.464064827 */, 16 }, + + /* 2304 */ { MAD_F(0x076de8fc) /* 0.464333519 */, 16 }, + /* 2305 */ { MAD_F(0x076f02c5) /* 0.464602250 */, 16 }, + /* 2306 */ { MAD_F(0x07701c98) /* 0.464871020 */, 16 }, + /* 2307 */ { MAD_F(0x07713676) /* 0.465139829 */, 16 }, + /* 2308 */ { MAD_F(0x0772505e) /* 0.465408676 */, 16 }, + /* 2309 */ { MAD_F(0x07736a51) /* 0.465677563 */, 16 }, + /* 2310 */ { MAD_F(0x0774844e) /* 0.465946488 */, 16 }, + /* 2311 */ { MAD_F(0x07759e55) /* 0.466215452 */, 16 }, + /* 2312 */ { MAD_F(0x0776b867) /* 0.466484455 */, 16 }, + /* 2313 */ { MAD_F(0x0777d283) /* 0.466753496 */, 16 }, + /* 2314 */ { MAD_F(0x0778ecaa) /* 0.467022577 */, 16 }, + /* 2315 */ { MAD_F(0x077a06db) /* 0.467291696 */, 16 }, + /* 2316 */ { MAD_F(0x077b2117) /* 0.467560854 */, 16 }, + /* 2317 */ { MAD_F(0x077c3b5d) /* 0.467830050 */, 16 }, + /* 2318 */ { MAD_F(0x077d55ad) /* 0.468099285 */, 16 }, + /* 2319 */ { MAD_F(0x077e7008) /* 0.468368560 */, 16 }, + + /* 2320 */ { MAD_F(0x077f8a6d) /* 0.468637872 */, 16 }, + /* 2321 */ { MAD_F(0x0780a4dc) /* 0.468907224 */, 16 }, + /* 2322 */ { MAD_F(0x0781bf56) /* 0.469176614 */, 16 }, + /* 2323 */ { MAD_F(0x0782d9da) /* 0.469446043 */, 16 }, + /* 2324 */ { MAD_F(0x0783f469) /* 0.469715510 */, 16 }, + /* 2325 */ { MAD_F(0x07850f02) /* 0.469985016 */, 16 }, + /* 2326 */ { MAD_F(0x078629a5) /* 0.470254561 */, 16 }, + /* 2327 */ { MAD_F(0x07874453) /* 0.470524145 */, 16 }, + /* 2328 */ { MAD_F(0x07885f0b) /* 0.470793767 */, 16 }, + /* 2329 */ { MAD_F(0x078979ce) /* 0.471063427 */, 16 }, + /* 2330 */ { MAD_F(0x078a949a) /* 0.471333126 */, 16 }, + /* 2331 */ { MAD_F(0x078baf72) /* 0.471602864 */, 16 }, + /* 2332 */ { MAD_F(0x078cca53) /* 0.471872641 */, 16 }, + /* 2333 */ { MAD_F(0x078de53f) /* 0.472142456 */, 16 }, + /* 2334 */ { MAD_F(0x078f0035) /* 0.472412309 */, 16 }, + /* 2335 */ { MAD_F(0x07901b36) /* 0.472682201 */, 16 }, + + /* 2336 */ { MAD_F(0x07913641) /* 0.472952132 */, 16 }, + /* 2337 */ { MAD_F(0x07925156) /* 0.473222101 */, 16 }, + /* 2338 */ { MAD_F(0x07936c76) /* 0.473492108 */, 16 }, + /* 2339 */ { MAD_F(0x079487a0) /* 0.473762155 */, 16 }, + /* 2340 */ { MAD_F(0x0795a2d4) /* 0.474032239 */, 16 }, + /* 2341 */ { MAD_F(0x0796be13) /* 0.474302362 */, 16 }, + /* 2342 */ { MAD_F(0x0797d95c) /* 0.474572524 */, 16 }, + /* 2343 */ { MAD_F(0x0798f4af) /* 0.474842724 */, 16 }, + /* 2344 */ { MAD_F(0x079a100c) /* 0.475112962 */, 16 }, + /* 2345 */ { MAD_F(0x079b2b74) /* 0.475383239 */, 16 }, + /* 2346 */ { MAD_F(0x079c46e7) /* 0.475653554 */, 16 }, + /* 2347 */ { MAD_F(0x079d6263) /* 0.475923908 */, 16 }, + /* 2348 */ { MAD_F(0x079e7dea) /* 0.476194300 */, 16 }, + /* 2349 */ { MAD_F(0x079f997b) /* 0.476464731 */, 16 }, + /* 2350 */ { MAD_F(0x07a0b516) /* 0.476735200 */, 16 }, + /* 2351 */ { MAD_F(0x07a1d0bc) /* 0.477005707 */, 16 }, + + /* 2352 */ { MAD_F(0x07a2ec6c) /* 0.477276252 */, 16 }, + /* 2353 */ { MAD_F(0x07a40827) /* 0.477546836 */, 16 }, + /* 2354 */ { MAD_F(0x07a523eb) /* 0.477817459 */, 16 }, + /* 2355 */ { MAD_F(0x07a63fba) /* 0.478088119 */, 16 }, + /* 2356 */ { MAD_F(0x07a75b93) /* 0.478358818 */, 16 }, + /* 2357 */ { MAD_F(0x07a87777) /* 0.478629555 */, 16 }, + /* 2358 */ { MAD_F(0x07a99364) /* 0.478900331 */, 16 }, + /* 2359 */ { MAD_F(0x07aaaf5c) /* 0.479171145 */, 16 }, + /* 2360 */ { MAD_F(0x07abcb5f) /* 0.479441997 */, 16 }, + /* 2361 */ { MAD_F(0x07ace76b) /* 0.479712887 */, 16 }, + /* 2362 */ { MAD_F(0x07ae0382) /* 0.479983816 */, 16 }, + /* 2363 */ { MAD_F(0x07af1fa3) /* 0.480254782 */, 16 }, + /* 2364 */ { MAD_F(0x07b03bcf) /* 0.480525787 */, 16 }, + /* 2365 */ { MAD_F(0x07b15804) /* 0.480796831 */, 16 }, + /* 2366 */ { MAD_F(0x07b27444) /* 0.481067912 */, 16 }, + /* 2367 */ { MAD_F(0x07b3908e) /* 0.481339032 */, 16 }, + + /* 2368 */ { MAD_F(0x07b4ace3) /* 0.481610189 */, 16 }, + /* 2369 */ { MAD_F(0x07b5c941) /* 0.481881385 */, 16 }, + /* 2370 */ { MAD_F(0x07b6e5aa) /* 0.482152620 */, 16 }, + /* 2371 */ { MAD_F(0x07b8021d) /* 0.482423892 */, 16 }, + /* 2372 */ { MAD_F(0x07b91e9b) /* 0.482695202 */, 16 }, + /* 2373 */ { MAD_F(0x07ba3b22) /* 0.482966551 */, 16 }, + /* 2374 */ { MAD_F(0x07bb57b4) /* 0.483237938 */, 16 }, + /* 2375 */ { MAD_F(0x07bc7450) /* 0.483509362 */, 16 }, + /* 2376 */ { MAD_F(0x07bd90f6) /* 0.483780825 */, 16 }, + /* 2377 */ { MAD_F(0x07beada7) /* 0.484052326 */, 16 }, + /* 2378 */ { MAD_F(0x07bfca61) /* 0.484323865 */, 16 }, + /* 2379 */ { MAD_F(0x07c0e726) /* 0.484595443 */, 16 }, + /* 2380 */ { MAD_F(0x07c203f5) /* 0.484867058 */, 16 }, + /* 2381 */ { MAD_F(0x07c320cf) /* 0.485138711 */, 16 }, + /* 2382 */ { MAD_F(0x07c43db2) /* 0.485410402 */, 16 }, + /* 2383 */ { MAD_F(0x07c55aa0) /* 0.485682131 */, 16 }, + + /* 2384 */ { MAD_F(0x07c67798) /* 0.485953899 */, 16 }, + /* 2385 */ { MAD_F(0x07c7949a) /* 0.486225704 */, 16 }, + /* 2386 */ { MAD_F(0x07c8b1a7) /* 0.486497547 */, 16 }, + /* 2387 */ { MAD_F(0x07c9cebd) /* 0.486769429 */, 16 }, + /* 2388 */ { MAD_F(0x07caebde) /* 0.487041348 */, 16 }, + /* 2389 */ { MAD_F(0x07cc0909) /* 0.487313305 */, 16 }, + /* 2390 */ { MAD_F(0x07cd263e) /* 0.487585300 */, 16 }, + /* 2391 */ { MAD_F(0x07ce437d) /* 0.487857333 */, 16 }, + /* 2392 */ { MAD_F(0x07cf60c7) /* 0.488129404 */, 16 }, + /* 2393 */ { MAD_F(0x07d07e1b) /* 0.488401513 */, 16 }, + /* 2394 */ { MAD_F(0x07d19b79) /* 0.488673660 */, 16 }, + /* 2395 */ { MAD_F(0x07d2b8e1) /* 0.488945845 */, 16 }, + /* 2396 */ { MAD_F(0x07d3d653) /* 0.489218067 */, 16 }, + /* 2397 */ { MAD_F(0x07d4f3cf) /* 0.489490328 */, 16 }, + /* 2398 */ { MAD_F(0x07d61156) /* 0.489762626 */, 16 }, + /* 2399 */ { MAD_F(0x07d72ee6) /* 0.490034962 */, 16 }, + + /* 2400 */ { MAD_F(0x07d84c81) /* 0.490307336 */, 16 }, + /* 2401 */ { MAD_F(0x07d96a26) /* 0.490579748 */, 16 }, + /* 2402 */ { MAD_F(0x07da87d5) /* 0.490852198 */, 16 }, + /* 2403 */ { MAD_F(0x07dba58f) /* 0.491124686 */, 16 }, + /* 2404 */ { MAD_F(0x07dcc352) /* 0.491397211 */, 16 }, + /* 2405 */ { MAD_F(0x07dde120) /* 0.491669774 */, 16 }, + /* 2406 */ { MAD_F(0x07defef7) /* 0.491942375 */, 16 }, + /* 2407 */ { MAD_F(0x07e01cd9) /* 0.492215014 */, 16 }, + /* 2408 */ { MAD_F(0x07e13ac5) /* 0.492487690 */, 16 }, + /* 2409 */ { MAD_F(0x07e258bc) /* 0.492760404 */, 16 }, + /* 2410 */ { MAD_F(0x07e376bc) /* 0.493033156 */, 16 }, + /* 2411 */ { MAD_F(0x07e494c6) /* 0.493305946 */, 16 }, + /* 2412 */ { MAD_F(0x07e5b2db) /* 0.493578773 */, 16 }, + /* 2413 */ { MAD_F(0x07e6d0f9) /* 0.493851638 */, 16 }, + /* 2414 */ { MAD_F(0x07e7ef22) /* 0.494124541 */, 16 }, + /* 2415 */ { MAD_F(0x07e90d55) /* 0.494397481 */, 16 }, + + /* 2416 */ { MAD_F(0x07ea2b92) /* 0.494670459 */, 16 }, + /* 2417 */ { MAD_F(0x07eb49d9) /* 0.494943475 */, 16 }, + /* 2418 */ { MAD_F(0x07ec682a) /* 0.495216529 */, 16 }, + /* 2419 */ { MAD_F(0x07ed8686) /* 0.495489620 */, 16 }, + /* 2420 */ { MAD_F(0x07eea4eb) /* 0.495762748 */, 16 }, + /* 2421 */ { MAD_F(0x07efc35b) /* 0.496035915 */, 16 }, + /* 2422 */ { MAD_F(0x07f0e1d4) /* 0.496309119 */, 16 }, + /* 2423 */ { MAD_F(0x07f20058) /* 0.496582360 */, 16 }, + /* 2424 */ { MAD_F(0x07f31ee6) /* 0.496855639 */, 16 }, + /* 2425 */ { MAD_F(0x07f43d7e) /* 0.497128956 */, 16 }, + /* 2426 */ { MAD_F(0x07f55c20) /* 0.497402310 */, 16 }, + /* 2427 */ { MAD_F(0x07f67acc) /* 0.497675702 */, 16 }, + /* 2428 */ { MAD_F(0x07f79982) /* 0.497949132 */, 16 }, + /* 2429 */ { MAD_F(0x07f8b842) /* 0.498222598 */, 16 }, + /* 2430 */ { MAD_F(0x07f9d70c) /* 0.498496103 */, 16 }, + /* 2431 */ { MAD_F(0x07faf5e1) /* 0.498769645 */, 16 }, + + /* 2432 */ { MAD_F(0x07fc14bf) /* 0.499043224 */, 16 }, + /* 2433 */ { MAD_F(0x07fd33a8) /* 0.499316841 */, 16 }, + /* 2434 */ { MAD_F(0x07fe529a) /* 0.499590496 */, 16 }, + /* 2435 */ { MAD_F(0x07ff7197) /* 0.499864188 */, 16 }, + /* 2436 */ { MAD_F(0x0400484f) /* 0.250068959 */, 17 }, + /* 2437 */ { MAD_F(0x0400d7d7) /* 0.250205842 */, 17 }, + /* 2438 */ { MAD_F(0x04016764) /* 0.250342744 */, 17 }, + /* 2439 */ { MAD_F(0x0401f6f7) /* 0.250479665 */, 17 }, + /* 2440 */ { MAD_F(0x0402868e) /* 0.250616605 */, 17 }, + /* 2441 */ { MAD_F(0x0403162b) /* 0.250753563 */, 17 }, + /* 2442 */ { MAD_F(0x0403a5cc) /* 0.250890540 */, 17 }, + /* 2443 */ { MAD_F(0x04043573) /* 0.251027536 */, 17 }, + /* 2444 */ { MAD_F(0x0404c51e) /* 0.251164550 */, 17 }, + /* 2445 */ { MAD_F(0x040554cf) /* 0.251301583 */, 17 }, + /* 2446 */ { MAD_F(0x0405e484) /* 0.251438635 */, 17 }, + /* 2447 */ { MAD_F(0x0406743f) /* 0.251575706 */, 17 }, + + /* 2448 */ { MAD_F(0x040703ff) /* 0.251712795 */, 17 }, + /* 2449 */ { MAD_F(0x040793c3) /* 0.251849903 */, 17 }, + /* 2450 */ { MAD_F(0x0408238d) /* 0.251987029 */, 17 }, + /* 2451 */ { MAD_F(0x0408b35b) /* 0.252124174 */, 17 }, + /* 2452 */ { MAD_F(0x0409432f) /* 0.252261338 */, 17 }, + /* 2453 */ { MAD_F(0x0409d308) /* 0.252398520 */, 17 }, + /* 2454 */ { MAD_F(0x040a62e5) /* 0.252535721 */, 17 }, + /* 2455 */ { MAD_F(0x040af2c8) /* 0.252672941 */, 17 }, + /* 2456 */ { MAD_F(0x040b82b0) /* 0.252810180 */, 17 }, + /* 2457 */ { MAD_F(0x040c129c) /* 0.252947436 */, 17 }, + /* 2458 */ { MAD_F(0x040ca28e) /* 0.253084712 */, 17 }, + /* 2459 */ { MAD_F(0x040d3284) /* 0.253222006 */, 17 }, + /* 2460 */ { MAD_F(0x040dc280) /* 0.253359319 */, 17 }, + /* 2461 */ { MAD_F(0x040e5281) /* 0.253496651 */, 17 }, + /* 2462 */ { MAD_F(0x040ee286) /* 0.253634001 */, 17 }, + /* 2463 */ { MAD_F(0x040f7291) /* 0.253771369 */, 17 }, + + /* 2464 */ { MAD_F(0x041002a1) /* 0.253908756 */, 17 }, + /* 2465 */ { MAD_F(0x041092b5) /* 0.254046162 */, 17 }, + /* 2466 */ { MAD_F(0x041122cf) /* 0.254183587 */, 17 }, + /* 2467 */ { MAD_F(0x0411b2ed) /* 0.254321030 */, 17 }, + /* 2468 */ { MAD_F(0x04124311) /* 0.254458491 */, 17 }, + /* 2469 */ { MAD_F(0x0412d339) /* 0.254595971 */, 17 }, + /* 2470 */ { MAD_F(0x04136367) /* 0.254733470 */, 17 }, + /* 2471 */ { MAD_F(0x0413f399) /* 0.254870987 */, 17 }, + /* 2472 */ { MAD_F(0x041483d1) /* 0.255008523 */, 17 }, + /* 2473 */ { MAD_F(0x0415140d) /* 0.255146077 */, 17 }, + /* 2474 */ { MAD_F(0x0415a44f) /* 0.255283650 */, 17 }, + /* 2475 */ { MAD_F(0x04163495) /* 0.255421241 */, 17 }, + /* 2476 */ { MAD_F(0x0416c4e1) /* 0.255558851 */, 17 }, + /* 2477 */ { MAD_F(0x04175531) /* 0.255696480 */, 17 }, + /* 2478 */ { MAD_F(0x0417e586) /* 0.255834127 */, 17 }, + /* 2479 */ { MAD_F(0x041875e1) /* 0.255971792 */, 17 }, + + /* 2480 */ { MAD_F(0x04190640) /* 0.256109476 */, 17 }, + /* 2481 */ { MAD_F(0x041996a4) /* 0.256247179 */, 17 }, + /* 2482 */ { MAD_F(0x041a270d) /* 0.256384900 */, 17 }, + /* 2483 */ { MAD_F(0x041ab77b) /* 0.256522639 */, 17 }, + /* 2484 */ { MAD_F(0x041b47ef) /* 0.256660397 */, 17 }, + /* 2485 */ { MAD_F(0x041bd867) /* 0.256798174 */, 17 }, + /* 2486 */ { MAD_F(0x041c68e4) /* 0.256935969 */, 17 }, + /* 2487 */ { MAD_F(0x041cf966) /* 0.257073782 */, 17 }, + /* 2488 */ { MAD_F(0x041d89ed) /* 0.257211614 */, 17 }, + /* 2489 */ { MAD_F(0x041e1a79) /* 0.257349465 */, 17 }, + /* 2490 */ { MAD_F(0x041eab0a) /* 0.257487334 */, 17 }, + /* 2491 */ { MAD_F(0x041f3b9f) /* 0.257625221 */, 17 }, + /* 2492 */ { MAD_F(0x041fcc3a) /* 0.257763127 */, 17 }, + /* 2493 */ { MAD_F(0x04205cda) /* 0.257901051 */, 17 }, + /* 2494 */ { MAD_F(0x0420ed7f) /* 0.258038994 */, 17 }, + /* 2495 */ { MAD_F(0x04217e28) /* 0.258176955 */, 17 }, + + /* 2496 */ { MAD_F(0x04220ed7) /* 0.258314934 */, 17 }, + /* 2497 */ { MAD_F(0x04229f8a) /* 0.258452932 */, 17 }, + /* 2498 */ { MAD_F(0x04233043) /* 0.258590948 */, 17 }, + /* 2499 */ { MAD_F(0x0423c100) /* 0.258728983 */, 17 }, + /* 2500 */ { MAD_F(0x042451c3) /* 0.258867036 */, 17 }, + /* 2501 */ { MAD_F(0x0424e28a) /* 0.259005108 */, 17 }, + /* 2502 */ { MAD_F(0x04257356) /* 0.259143198 */, 17 }, + /* 2503 */ { MAD_F(0x04260428) /* 0.259281307 */, 17 }, + /* 2504 */ { MAD_F(0x042694fe) /* 0.259419433 */, 17 }, + /* 2505 */ { MAD_F(0x042725d9) /* 0.259557579 */, 17 }, + /* 2506 */ { MAD_F(0x0427b6b9) /* 0.259695742 */, 17 }, + /* 2507 */ { MAD_F(0x0428479e) /* 0.259833924 */, 17 }, + /* 2508 */ { MAD_F(0x0428d888) /* 0.259972124 */, 17 }, + /* 2509 */ { MAD_F(0x04296976) /* 0.260110343 */, 17 }, + /* 2510 */ { MAD_F(0x0429fa6a) /* 0.260248580 */, 17 }, + /* 2511 */ { MAD_F(0x042a8b63) /* 0.260386836 */, 17 }, + + /* 2512 */ { MAD_F(0x042b1c60) /* 0.260525110 */, 17 }, + /* 2513 */ { MAD_F(0x042bad63) /* 0.260663402 */, 17 }, + /* 2514 */ { MAD_F(0x042c3e6a) /* 0.260801712 */, 17 }, + /* 2515 */ { MAD_F(0x042ccf77) /* 0.260940041 */, 17 }, + /* 2516 */ { MAD_F(0x042d6088) /* 0.261078388 */, 17 }, + /* 2517 */ { MAD_F(0x042df19e) /* 0.261216754 */, 17 }, + /* 2518 */ { MAD_F(0x042e82b9) /* 0.261355137 */, 17 }, + /* 2519 */ { MAD_F(0x042f13d9) /* 0.261493540 */, 17 }, + /* 2520 */ { MAD_F(0x042fa4fe) /* 0.261631960 */, 17 }, + /* 2521 */ { MAD_F(0x04303628) /* 0.261770399 */, 17 }, + /* 2522 */ { MAD_F(0x0430c757) /* 0.261908856 */, 17 }, + /* 2523 */ { MAD_F(0x0431588b) /* 0.262047331 */, 17 }, + /* 2524 */ { MAD_F(0x0431e9c3) /* 0.262185825 */, 17 }, + /* 2525 */ { MAD_F(0x04327b01) /* 0.262324337 */, 17 }, + /* 2526 */ { MAD_F(0x04330c43) /* 0.262462867 */, 17 }, + /* 2527 */ { MAD_F(0x04339d8a) /* 0.262601416 */, 17 }, + + /* 2528 */ { MAD_F(0x04342ed7) /* 0.262739982 */, 17 }, + /* 2529 */ { MAD_F(0x0434c028) /* 0.262878568 */, 17 }, + /* 2530 */ { MAD_F(0x0435517e) /* 0.263017171 */, 17 }, + /* 2531 */ { MAD_F(0x0435e2d9) /* 0.263155792 */, 17 }, + /* 2532 */ { MAD_F(0x04367439) /* 0.263294432 */, 17 }, + /* 2533 */ { MAD_F(0x0437059e) /* 0.263433090 */, 17 }, + /* 2534 */ { MAD_F(0x04379707) /* 0.263571767 */, 17 }, + /* 2535 */ { MAD_F(0x04382876) /* 0.263710461 */, 17 }, + /* 2536 */ { MAD_F(0x0438b9e9) /* 0.263849174 */, 17 }, + /* 2537 */ { MAD_F(0x04394b61) /* 0.263987905 */, 17 }, + /* 2538 */ { MAD_F(0x0439dcdf) /* 0.264126655 */, 17 }, + /* 2539 */ { MAD_F(0x043a6e61) /* 0.264265422 */, 17 }, + /* 2540 */ { MAD_F(0x043affe8) /* 0.264404208 */, 17 }, + /* 2541 */ { MAD_F(0x043b9174) /* 0.264543012 */, 17 }, + /* 2542 */ { MAD_F(0x043c2305) /* 0.264681834 */, 17 }, + /* 2543 */ { MAD_F(0x043cb49a) /* 0.264820674 */, 17 }, + + /* 2544 */ { MAD_F(0x043d4635) /* 0.264959533 */, 17 }, + /* 2545 */ { MAD_F(0x043dd7d4) /* 0.265098410 */, 17 }, + /* 2546 */ { MAD_F(0x043e6979) /* 0.265237305 */, 17 }, + /* 2547 */ { MAD_F(0x043efb22) /* 0.265376218 */, 17 }, + /* 2548 */ { MAD_F(0x043f8cd0) /* 0.265515149 */, 17 }, + /* 2549 */ { MAD_F(0x04401e83) /* 0.265654099 */, 17 }, + /* 2550 */ { MAD_F(0x0440b03b) /* 0.265793066 */, 17 }, + /* 2551 */ { MAD_F(0x044141f7) /* 0.265932052 */, 17 }, + /* 2552 */ { MAD_F(0x0441d3b9) /* 0.266071056 */, 17 }, + /* 2553 */ { MAD_F(0x04426580) /* 0.266210078 */, 17 }, + /* 2554 */ { MAD_F(0x0442f74b) /* 0.266349119 */, 17 }, + /* 2555 */ { MAD_F(0x0443891b) /* 0.266488177 */, 17 }, + /* 2556 */ { MAD_F(0x04441af0) /* 0.266627254 */, 17 }, + /* 2557 */ { MAD_F(0x0444acca) /* 0.266766349 */, 17 }, + /* 2558 */ { MAD_F(0x04453ea9) /* 0.266905462 */, 17 }, + /* 2559 */ { MAD_F(0x0445d08d) /* 0.267044593 */, 17 }, + + /* 2560 */ { MAD_F(0x04466275) /* 0.267183742 */, 17 }, + /* 2561 */ { MAD_F(0x0446f463) /* 0.267322909 */, 17 }, + /* 2562 */ { MAD_F(0x04478655) /* 0.267462094 */, 17 }, + /* 2563 */ { MAD_F(0x0448184c) /* 0.267601298 */, 17 }, + /* 2564 */ { MAD_F(0x0448aa48) /* 0.267740519 */, 17 }, + /* 2565 */ { MAD_F(0x04493c49) /* 0.267879759 */, 17 }, + /* 2566 */ { MAD_F(0x0449ce4f) /* 0.268019017 */, 17 }, + /* 2567 */ { MAD_F(0x044a6059) /* 0.268158293 */, 17 }, + /* 2568 */ { MAD_F(0x044af269) /* 0.268297587 */, 17 }, + /* 2569 */ { MAD_F(0x044b847d) /* 0.268436899 */, 17 }, + /* 2570 */ { MAD_F(0x044c1696) /* 0.268576229 */, 17 }, + /* 2571 */ { MAD_F(0x044ca8b4) /* 0.268715577 */, 17 }, + /* 2572 */ { MAD_F(0x044d3ad7) /* 0.268854943 */, 17 }, + /* 2573 */ { MAD_F(0x044dccff) /* 0.268994328 */, 17 }, + /* 2574 */ { MAD_F(0x044e5f2b) /* 0.269133730 */, 17 }, + /* 2575 */ { MAD_F(0x044ef15d) /* 0.269273150 */, 17 }, + + /* 2576 */ { MAD_F(0x044f8393) /* 0.269412589 */, 17 }, + /* 2577 */ { MAD_F(0x045015ce) /* 0.269552045 */, 17 }, + /* 2578 */ { MAD_F(0x0450a80e) /* 0.269691520 */, 17 }, + /* 2579 */ { MAD_F(0x04513a53) /* 0.269831013 */, 17 }, + /* 2580 */ { MAD_F(0x0451cc9c) /* 0.269970523 */, 17 }, + /* 2581 */ { MAD_F(0x04525eeb) /* 0.270110052 */, 17 }, + /* 2582 */ { MAD_F(0x0452f13e) /* 0.270249599 */, 17 }, + /* 2583 */ { MAD_F(0x04538396) /* 0.270389163 */, 17 }, + /* 2584 */ { MAD_F(0x045415f3) /* 0.270528746 */, 17 }, + /* 2585 */ { MAD_F(0x0454a855) /* 0.270668347 */, 17 }, + /* 2586 */ { MAD_F(0x04553abb) /* 0.270807965 */, 17 }, + /* 2587 */ { MAD_F(0x0455cd27) /* 0.270947602 */, 17 }, + /* 2588 */ { MAD_F(0x04565f97) /* 0.271087257 */, 17 }, + /* 2589 */ { MAD_F(0x0456f20c) /* 0.271226930 */, 17 }, + /* 2590 */ { MAD_F(0x04578486) /* 0.271366620 */, 17 }, + /* 2591 */ { MAD_F(0x04581705) /* 0.271506329 */, 17 }, + + /* 2592 */ { MAD_F(0x0458a989) /* 0.271646056 */, 17 }, + /* 2593 */ { MAD_F(0x04593c11) /* 0.271785800 */, 17 }, + /* 2594 */ { MAD_F(0x0459ce9e) /* 0.271925563 */, 17 }, + /* 2595 */ { MAD_F(0x045a6130) /* 0.272065343 */, 17 }, + /* 2596 */ { MAD_F(0x045af3c7) /* 0.272205142 */, 17 }, + /* 2597 */ { MAD_F(0x045b8663) /* 0.272344958 */, 17 }, + /* 2598 */ { MAD_F(0x045c1903) /* 0.272484793 */, 17 }, + /* 2599 */ { MAD_F(0x045caba9) /* 0.272624645 */, 17 }, + /* 2600 */ { MAD_F(0x045d3e53) /* 0.272764515 */, 17 }, + /* 2601 */ { MAD_F(0x045dd102) /* 0.272904403 */, 17 }, + /* 2602 */ { MAD_F(0x045e63b6) /* 0.273044310 */, 17 }, + /* 2603 */ { MAD_F(0x045ef66e) /* 0.273184234 */, 17 }, + /* 2604 */ { MAD_F(0x045f892b) /* 0.273324176 */, 17 }, + /* 2605 */ { MAD_F(0x04601bee) /* 0.273464136 */, 17 }, + /* 2606 */ { MAD_F(0x0460aeb5) /* 0.273604113 */, 17 }, + /* 2607 */ { MAD_F(0x04614180) /* 0.273744109 */, 17 }, + + /* 2608 */ { MAD_F(0x0461d451) /* 0.273884123 */, 17 }, + /* 2609 */ { MAD_F(0x04626727) /* 0.274024154 */, 17 }, + /* 2610 */ { MAD_F(0x0462fa01) /* 0.274164204 */, 17 }, + /* 2611 */ { MAD_F(0x04638ce0) /* 0.274304271 */, 17 }, + /* 2612 */ { MAD_F(0x04641fc4) /* 0.274444356 */, 17 }, + /* 2613 */ { MAD_F(0x0464b2ac) /* 0.274584459 */, 17 }, + /* 2614 */ { MAD_F(0x0465459a) /* 0.274724580 */, 17 }, + /* 2615 */ { MAD_F(0x0465d88c) /* 0.274864719 */, 17 }, + /* 2616 */ { MAD_F(0x04666b83) /* 0.275004875 */, 17 }, + /* 2617 */ { MAD_F(0x0466fe7f) /* 0.275145050 */, 17 }, + /* 2618 */ { MAD_F(0x0467917f) /* 0.275285242 */, 17 }, + /* 2619 */ { MAD_F(0x04682485) /* 0.275425452 */, 17 }, + /* 2620 */ { MAD_F(0x0468b78f) /* 0.275565681 */, 17 }, + /* 2621 */ { MAD_F(0x04694a9e) /* 0.275705926 */, 17 }, + /* 2622 */ { MAD_F(0x0469ddb2) /* 0.275846190 */, 17 }, + /* 2623 */ { MAD_F(0x046a70ca) /* 0.275986472 */, 17 }, + + /* 2624 */ { MAD_F(0x046b03e7) /* 0.276126771 */, 17 }, + /* 2625 */ { MAD_F(0x046b970a) /* 0.276267088 */, 17 }, + /* 2626 */ { MAD_F(0x046c2a31) /* 0.276407423 */, 17 }, + /* 2627 */ { MAD_F(0x046cbd5c) /* 0.276547776 */, 17 }, + /* 2628 */ { MAD_F(0x046d508d) /* 0.276688147 */, 17 }, + /* 2629 */ { MAD_F(0x046de3c2) /* 0.276828535 */, 17 }, + /* 2630 */ { MAD_F(0x046e76fc) /* 0.276968942 */, 17 }, + /* 2631 */ { MAD_F(0x046f0a3b) /* 0.277109366 */, 17 }, + /* 2632 */ { MAD_F(0x046f9d7e) /* 0.277249808 */, 17 }, + /* 2633 */ { MAD_F(0x047030c7) /* 0.277390267 */, 17 }, + /* 2634 */ { MAD_F(0x0470c414) /* 0.277530745 */, 17 }, + /* 2635 */ { MAD_F(0x04715766) /* 0.277671240 */, 17 }, + /* 2636 */ { MAD_F(0x0471eabc) /* 0.277811753 */, 17 }, + /* 2637 */ { MAD_F(0x04727e18) /* 0.277952284 */, 17 }, + /* 2638 */ { MAD_F(0x04731178) /* 0.278092832 */, 17 }, + /* 2639 */ { MAD_F(0x0473a4dd) /* 0.278233399 */, 17 }, + + /* 2640 */ { MAD_F(0x04743847) /* 0.278373983 */, 17 }, + /* 2641 */ { MAD_F(0x0474cbb5) /* 0.278514584 */, 17 }, + /* 2642 */ { MAD_F(0x04755f29) /* 0.278655204 */, 17 }, + /* 2643 */ { MAD_F(0x0475f2a1) /* 0.278795841 */, 17 }, + /* 2644 */ { MAD_F(0x0476861d) /* 0.278936496 */, 17 }, + /* 2645 */ { MAD_F(0x0477199f) /* 0.279077169 */, 17 }, + /* 2646 */ { MAD_F(0x0477ad25) /* 0.279217860 */, 17 }, + /* 2647 */ { MAD_F(0x047840b0) /* 0.279358568 */, 17 }, + /* 2648 */ { MAD_F(0x0478d440) /* 0.279499294 */, 17 }, + /* 2649 */ { MAD_F(0x047967d5) /* 0.279640037 */, 17 }, + /* 2650 */ { MAD_F(0x0479fb6e) /* 0.279780799 */, 17 }, + /* 2651 */ { MAD_F(0x047a8f0c) /* 0.279921578 */, 17 }, + /* 2652 */ { MAD_F(0x047b22af) /* 0.280062375 */, 17 }, + /* 2653 */ { MAD_F(0x047bb657) /* 0.280203189 */, 17 }, + /* 2654 */ { MAD_F(0x047c4a03) /* 0.280344021 */, 17 }, + /* 2655 */ { MAD_F(0x047cddb4) /* 0.280484871 */, 17 }, + + /* 2656 */ { MAD_F(0x047d716a) /* 0.280625739 */, 17 }, + /* 2657 */ { MAD_F(0x047e0524) /* 0.280766624 */, 17 }, + /* 2658 */ { MAD_F(0x047e98e4) /* 0.280907527 */, 17 }, + /* 2659 */ { MAD_F(0x047f2ca8) /* 0.281048447 */, 17 }, + /* 2660 */ { MAD_F(0x047fc071) /* 0.281189385 */, 17 }, + /* 2661 */ { MAD_F(0x0480543e) /* 0.281330341 */, 17 }, + /* 2662 */ { MAD_F(0x0480e811) /* 0.281471315 */, 17 }, + /* 2663 */ { MAD_F(0x04817be8) /* 0.281612306 */, 17 }, + /* 2664 */ { MAD_F(0x04820fc3) /* 0.281753315 */, 17 }, + /* 2665 */ { MAD_F(0x0482a3a4) /* 0.281894341 */, 17 }, + /* 2666 */ { MAD_F(0x04833789) /* 0.282035386 */, 17 }, + /* 2667 */ { MAD_F(0x0483cb73) /* 0.282176447 */, 17 }, + /* 2668 */ { MAD_F(0x04845f62) /* 0.282317527 */, 17 }, + /* 2669 */ { MAD_F(0x0484f355) /* 0.282458624 */, 17 }, + /* 2670 */ { MAD_F(0x0485874d) /* 0.282599738 */, 17 }, + /* 2671 */ { MAD_F(0x04861b4a) /* 0.282740871 */, 17 }, + + /* 2672 */ { MAD_F(0x0486af4c) /* 0.282882021 */, 17 }, + /* 2673 */ { MAD_F(0x04874352) /* 0.283023188 */, 17 }, + /* 2674 */ { MAD_F(0x0487d75d) /* 0.283164373 */, 17 }, + /* 2675 */ { MAD_F(0x04886b6d) /* 0.283305576 */, 17 }, + /* 2676 */ { MAD_F(0x0488ff82) /* 0.283446796 */, 17 }, + /* 2677 */ { MAD_F(0x0489939b) /* 0.283588034 */, 17 }, + /* 2678 */ { MAD_F(0x048a27b9) /* 0.283729290 */, 17 }, + /* 2679 */ { MAD_F(0x048abbdc) /* 0.283870563 */, 17 }, + /* 2680 */ { MAD_F(0x048b5003) /* 0.284011853 */, 17 }, + /* 2681 */ { MAD_F(0x048be42f) /* 0.284153161 */, 17 }, + /* 2682 */ { MAD_F(0x048c7860) /* 0.284294487 */, 17 }, + /* 2683 */ { MAD_F(0x048d0c96) /* 0.284435831 */, 17 }, + /* 2684 */ { MAD_F(0x048da0d0) /* 0.284577192 */, 17 }, + /* 2685 */ { MAD_F(0x048e350f) /* 0.284718570 */, 17 }, + /* 2686 */ { MAD_F(0x048ec953) /* 0.284859966 */, 17 }, + /* 2687 */ { MAD_F(0x048f5d9b) /* 0.285001380 */, 17 }, + + /* 2688 */ { MAD_F(0x048ff1e8) /* 0.285142811 */, 17 }, + /* 2689 */ { MAD_F(0x0490863a) /* 0.285284259 */, 17 }, + /* 2690 */ { MAD_F(0x04911a91) /* 0.285425726 */, 17 }, + /* 2691 */ { MAD_F(0x0491aeec) /* 0.285567209 */, 17 }, + /* 2692 */ { MAD_F(0x0492434c) /* 0.285708711 */, 17 }, + /* 2693 */ { MAD_F(0x0492d7b0) /* 0.285850229 */, 17 }, + /* 2694 */ { MAD_F(0x04936c1a) /* 0.285991766 */, 17 }, + /* 2695 */ { MAD_F(0x04940088) /* 0.286133319 */, 17 }, + /* 2696 */ { MAD_F(0x049494fb) /* 0.286274891 */, 17 }, + /* 2697 */ { MAD_F(0x04952972) /* 0.286416480 */, 17 }, + /* 2698 */ { MAD_F(0x0495bdee) /* 0.286558086 */, 17 }, + /* 2699 */ { MAD_F(0x0496526f) /* 0.286699710 */, 17 }, + /* 2700 */ { MAD_F(0x0496e6f5) /* 0.286841351 */, 17 }, + /* 2701 */ { MAD_F(0x04977b7f) /* 0.286983010 */, 17 }, + /* 2702 */ { MAD_F(0x0498100e) /* 0.287124686 */, 17 }, + /* 2703 */ { MAD_F(0x0498a4a1) /* 0.287266380 */, 17 }, + + /* 2704 */ { MAD_F(0x0499393a) /* 0.287408091 */, 17 }, + /* 2705 */ { MAD_F(0x0499cdd7) /* 0.287549820 */, 17 }, + /* 2706 */ { MAD_F(0x049a6278) /* 0.287691566 */, 17 }, + /* 2707 */ { MAD_F(0x049af71f) /* 0.287833330 */, 17 }, + /* 2708 */ { MAD_F(0x049b8bca) /* 0.287975111 */, 17 }, + /* 2709 */ { MAD_F(0x049c207a) /* 0.288116909 */, 17 }, + /* 2710 */ { MAD_F(0x049cb52e) /* 0.288258725 */, 17 }, + /* 2711 */ { MAD_F(0x049d49e7) /* 0.288400559 */, 17 }, + /* 2712 */ { MAD_F(0x049ddea5) /* 0.288542409 */, 17 }, + /* 2713 */ { MAD_F(0x049e7367) /* 0.288684278 */, 17 }, + /* 2714 */ { MAD_F(0x049f082f) /* 0.288826163 */, 17 }, + /* 2715 */ { MAD_F(0x049f9cfa) /* 0.288968067 */, 17 }, + /* 2716 */ { MAD_F(0x04a031cb) /* 0.289109987 */, 17 }, + /* 2717 */ { MAD_F(0x04a0c6a0) /* 0.289251925 */, 17 }, + /* 2718 */ { MAD_F(0x04a15b7a) /* 0.289393881 */, 17 }, + /* 2719 */ { MAD_F(0x04a1f059) /* 0.289535854 */, 17 }, + + /* 2720 */ { MAD_F(0x04a2853c) /* 0.289677844 */, 17 }, + /* 2721 */ { MAD_F(0x04a31a24) /* 0.289819851 */, 17 }, + /* 2722 */ { MAD_F(0x04a3af10) /* 0.289961876 */, 17 }, + /* 2723 */ { MAD_F(0x04a44401) /* 0.290103919 */, 17 }, + /* 2724 */ { MAD_F(0x04a4d8f7) /* 0.290245979 */, 17 }, + /* 2725 */ { MAD_F(0x04a56df2) /* 0.290388056 */, 17 }, + /* 2726 */ { MAD_F(0x04a602f1) /* 0.290530150 */, 17 }, + /* 2727 */ { MAD_F(0x04a697f5) /* 0.290672262 */, 17 }, + /* 2728 */ { MAD_F(0x04a72cfe) /* 0.290814392 */, 17 }, + /* 2729 */ { MAD_F(0x04a7c20b) /* 0.290956538 */, 17 }, + /* 2730 */ { MAD_F(0x04a8571d) /* 0.291098703 */, 17 }, + /* 2731 */ { MAD_F(0x04a8ec33) /* 0.291240884 */, 17 }, + /* 2732 */ { MAD_F(0x04a9814e) /* 0.291383083 */, 17 }, + /* 2733 */ { MAD_F(0x04aa166e) /* 0.291525299 */, 17 }, + /* 2734 */ { MAD_F(0x04aaab93) /* 0.291667532 */, 17 }, + /* 2735 */ { MAD_F(0x04ab40bc) /* 0.291809783 */, 17 }, + + /* 2736 */ { MAD_F(0x04abd5ea) /* 0.291952051 */, 17 }, + /* 2737 */ { MAD_F(0x04ac6b1c) /* 0.292094337 */, 17 }, + /* 2738 */ { MAD_F(0x04ad0053) /* 0.292236640 */, 17 }, + /* 2739 */ { MAD_F(0x04ad958f) /* 0.292378960 */, 17 }, + /* 2740 */ { MAD_F(0x04ae2ad0) /* 0.292521297 */, 17 }, + /* 2741 */ { MAD_F(0x04aec015) /* 0.292663652 */, 17 }, + /* 2742 */ { MAD_F(0x04af555e) /* 0.292806024 */, 17 }, + /* 2743 */ { MAD_F(0x04afeaad) /* 0.292948414 */, 17 }, + /* 2744 */ { MAD_F(0x04b08000) /* 0.293090820 */, 17 }, + /* 2745 */ { MAD_F(0x04b11557) /* 0.293233244 */, 17 }, + /* 2746 */ { MAD_F(0x04b1aab4) /* 0.293375686 */, 17 }, + /* 2747 */ { MAD_F(0x04b24015) /* 0.293518144 */, 17 }, + /* 2748 */ { MAD_F(0x04b2d57a) /* 0.293660620 */, 17 }, + /* 2749 */ { MAD_F(0x04b36ae4) /* 0.293803113 */, 17 }, + /* 2750 */ { MAD_F(0x04b40053) /* 0.293945624 */, 17 }, + /* 2751 */ { MAD_F(0x04b495c7) /* 0.294088151 */, 17 }, + + /* 2752 */ { MAD_F(0x04b52b3f) /* 0.294230696 */, 17 }, + /* 2753 */ { MAD_F(0x04b5c0bc) /* 0.294373259 */, 17 }, + /* 2754 */ { MAD_F(0x04b6563d) /* 0.294515838 */, 17 }, + /* 2755 */ { MAD_F(0x04b6ebc3) /* 0.294658435 */, 17 }, + /* 2756 */ { MAD_F(0x04b7814e) /* 0.294801049 */, 17 }, + /* 2757 */ { MAD_F(0x04b816dd) /* 0.294943680 */, 17 }, + /* 2758 */ { MAD_F(0x04b8ac71) /* 0.295086329 */, 17 }, + /* 2759 */ { MAD_F(0x04b9420a) /* 0.295228995 */, 17 }, + /* 2760 */ { MAD_F(0x04b9d7a7) /* 0.295371678 */, 17 }, + /* 2761 */ { MAD_F(0x04ba6d49) /* 0.295514378 */, 17 }, + /* 2762 */ { MAD_F(0x04bb02ef) /* 0.295657095 */, 17 }, + /* 2763 */ { MAD_F(0x04bb989a) /* 0.295799830 */, 17 }, + /* 2764 */ { MAD_F(0x04bc2e4a) /* 0.295942582 */, 17 }, + /* 2765 */ { MAD_F(0x04bcc3fe) /* 0.296085351 */, 17 }, + /* 2766 */ { MAD_F(0x04bd59b7) /* 0.296228138 */, 17 }, + /* 2767 */ { MAD_F(0x04bdef74) /* 0.296370941 */, 17 }, + + /* 2768 */ { MAD_F(0x04be8537) /* 0.296513762 */, 17 }, + /* 2769 */ { MAD_F(0x04bf1afd) /* 0.296656600 */, 17 }, + /* 2770 */ { MAD_F(0x04bfb0c9) /* 0.296799455 */, 17 }, + /* 2771 */ { MAD_F(0x04c04699) /* 0.296942327 */, 17 }, + /* 2772 */ { MAD_F(0x04c0dc6d) /* 0.297085217 */, 17 }, + /* 2773 */ { MAD_F(0x04c17247) /* 0.297228124 */, 17 }, + /* 2774 */ { MAD_F(0x04c20824) /* 0.297371048 */, 17 }, + /* 2775 */ { MAD_F(0x04c29e07) /* 0.297513989 */, 17 }, + /* 2776 */ { MAD_F(0x04c333ee) /* 0.297656947 */, 17 }, + /* 2777 */ { MAD_F(0x04c3c9da) /* 0.297799922 */, 17 }, + /* 2778 */ { MAD_F(0x04c45fca) /* 0.297942915 */, 17 }, + /* 2779 */ { MAD_F(0x04c4f5bf) /* 0.298085925 */, 17 }, + /* 2780 */ { MAD_F(0x04c58bb8) /* 0.298228951 */, 17 }, + /* 2781 */ { MAD_F(0x04c621b6) /* 0.298371996 */, 17 }, + /* 2782 */ { MAD_F(0x04c6b7b9) /* 0.298515057 */, 17 }, + /* 2783 */ { MAD_F(0x04c74dc0) /* 0.298658135 */, 17 }, + + /* 2784 */ { MAD_F(0x04c7e3cc) /* 0.298801231 */, 17 }, + /* 2785 */ { MAD_F(0x04c879dd) /* 0.298944343 */, 17 }, + /* 2786 */ { MAD_F(0x04c90ff2) /* 0.299087473 */, 17 }, + /* 2787 */ { MAD_F(0x04c9a60c) /* 0.299230620 */, 17 }, + /* 2788 */ { MAD_F(0x04ca3c2a) /* 0.299373784 */, 17 }, + /* 2789 */ { MAD_F(0x04cad24d) /* 0.299516965 */, 17 }, + /* 2790 */ { MAD_F(0x04cb6874) /* 0.299660163 */, 17 }, + /* 2791 */ { MAD_F(0x04cbfea0) /* 0.299803378 */, 17 }, + /* 2792 */ { MAD_F(0x04cc94d1) /* 0.299946611 */, 17 }, + /* 2793 */ { MAD_F(0x04cd2b06) /* 0.300089860 */, 17 }, + /* 2794 */ { MAD_F(0x04cdc140) /* 0.300233127 */, 17 }, + /* 2795 */ { MAD_F(0x04ce577f) /* 0.300376411 */, 17 }, + /* 2796 */ { MAD_F(0x04ceedc2) /* 0.300519711 */, 17 }, + /* 2797 */ { MAD_F(0x04cf8409) /* 0.300663029 */, 17 }, + /* 2798 */ { MAD_F(0x04d01a55) /* 0.300806364 */, 17 }, + /* 2799 */ { MAD_F(0x04d0b0a6) /* 0.300949716 */, 17 }, + + /* 2800 */ { MAD_F(0x04d146fb) /* 0.301093085 */, 17 }, + /* 2801 */ { MAD_F(0x04d1dd55) /* 0.301236472 */, 17 }, + /* 2802 */ { MAD_F(0x04d273b4) /* 0.301379875 */, 17 }, + /* 2803 */ { MAD_F(0x04d30a17) /* 0.301523295 */, 17 }, + /* 2804 */ { MAD_F(0x04d3a07f) /* 0.301666733 */, 17 }, + /* 2805 */ { MAD_F(0x04d436eb) /* 0.301810187 */, 17 }, + /* 2806 */ { MAD_F(0x04d4cd5c) /* 0.301953659 */, 17 }, + /* 2807 */ { MAD_F(0x04d563d1) /* 0.302097147 */, 17 }, + /* 2808 */ { MAD_F(0x04d5fa4b) /* 0.302240653 */, 17 }, + /* 2809 */ { MAD_F(0x04d690ca) /* 0.302384175 */, 17 }, + /* 2810 */ { MAD_F(0x04d7274d) /* 0.302527715 */, 17 }, + /* 2811 */ { MAD_F(0x04d7bdd5) /* 0.302671271 */, 17 }, + /* 2812 */ { MAD_F(0x04d85461) /* 0.302814845 */, 17 }, + /* 2813 */ { MAD_F(0x04d8eaf2) /* 0.302958436 */, 17 }, + /* 2814 */ { MAD_F(0x04d98187) /* 0.303102044 */, 17 }, + /* 2815 */ { MAD_F(0x04da1821) /* 0.303245668 */, 17 }, + + /* 2816 */ { MAD_F(0x04daaec0) /* 0.303389310 */, 17 }, + /* 2817 */ { MAD_F(0x04db4563) /* 0.303532969 */, 17 }, + /* 2818 */ { MAD_F(0x04dbdc0a) /* 0.303676645 */, 17 }, + /* 2819 */ { MAD_F(0x04dc72b7) /* 0.303820337 */, 17 }, + /* 2820 */ { MAD_F(0x04dd0967) /* 0.303964047 */, 17 }, + /* 2821 */ { MAD_F(0x04dda01d) /* 0.304107774 */, 17 }, + /* 2822 */ { MAD_F(0x04de36d7) /* 0.304251517 */, 17 }, + /* 2823 */ { MAD_F(0x04decd95) /* 0.304395278 */, 17 }, + /* 2824 */ { MAD_F(0x04df6458) /* 0.304539056 */, 17 }, + /* 2825 */ { MAD_F(0x04dffb20) /* 0.304682850 */, 17 }, + /* 2826 */ { MAD_F(0x04e091ec) /* 0.304826662 */, 17 }, + /* 2827 */ { MAD_F(0x04e128bc) /* 0.304970491 */, 17 }, + /* 2828 */ { MAD_F(0x04e1bf92) /* 0.305114336 */, 17 }, + /* 2829 */ { MAD_F(0x04e2566b) /* 0.305258199 */, 17 }, + /* 2830 */ { MAD_F(0x04e2ed4a) /* 0.305402078 */, 17 }, + /* 2831 */ { MAD_F(0x04e3842d) /* 0.305545974 */, 17 }, + + /* 2832 */ { MAD_F(0x04e41b14) /* 0.305689888 */, 17 }, + /* 2833 */ { MAD_F(0x04e4b200) /* 0.305833818 */, 17 }, + /* 2834 */ { MAD_F(0x04e548f1) /* 0.305977765 */, 17 }, + /* 2835 */ { MAD_F(0x04e5dfe6) /* 0.306121729 */, 17 }, + /* 2836 */ { MAD_F(0x04e676df) /* 0.306265710 */, 17 }, + /* 2837 */ { MAD_F(0x04e70dde) /* 0.306409708 */, 17 }, + /* 2838 */ { MAD_F(0x04e7a4e0) /* 0.306553723 */, 17 }, + /* 2839 */ { MAD_F(0x04e83be7) /* 0.306697755 */, 17 }, + /* 2840 */ { MAD_F(0x04e8d2f3) /* 0.306841804 */, 17 }, + /* 2841 */ { MAD_F(0x04e96a04) /* 0.306985869 */, 17 }, + /* 2842 */ { MAD_F(0x04ea0118) /* 0.307129952 */, 17 }, + /* 2843 */ { MAD_F(0x04ea9832) /* 0.307274051 */, 17 }, + /* 2844 */ { MAD_F(0x04eb2f50) /* 0.307418168 */, 17 }, + /* 2845 */ { MAD_F(0x04ebc672) /* 0.307562301 */, 17 }, + /* 2846 */ { MAD_F(0x04ec5d99) /* 0.307706451 */, 17 }, + /* 2847 */ { MAD_F(0x04ecf4c5) /* 0.307850618 */, 17 }, + + /* 2848 */ { MAD_F(0x04ed8bf5) /* 0.307994802 */, 17 }, + /* 2849 */ { MAD_F(0x04ee2329) /* 0.308139003 */, 17 }, + /* 2850 */ { MAD_F(0x04eeba63) /* 0.308283220 */, 17 }, + /* 2851 */ { MAD_F(0x04ef51a0) /* 0.308427455 */, 17 }, + /* 2852 */ { MAD_F(0x04efe8e2) /* 0.308571706 */, 17 }, + /* 2853 */ { MAD_F(0x04f08029) /* 0.308715974 */, 17 }, + /* 2854 */ { MAD_F(0x04f11774) /* 0.308860260 */, 17 }, + /* 2855 */ { MAD_F(0x04f1aec4) /* 0.309004561 */, 17 }, + /* 2856 */ { MAD_F(0x04f24618) /* 0.309148880 */, 17 }, + /* 2857 */ { MAD_F(0x04f2dd71) /* 0.309293216 */, 17 }, + /* 2858 */ { MAD_F(0x04f374cf) /* 0.309437568 */, 17 }, + /* 2859 */ { MAD_F(0x04f40c30) /* 0.309581938 */, 17 }, + /* 2860 */ { MAD_F(0x04f4a397) /* 0.309726324 */, 17 }, + /* 2861 */ { MAD_F(0x04f53b02) /* 0.309870727 */, 17 }, + /* 2862 */ { MAD_F(0x04f5d271) /* 0.310015147 */, 17 }, + /* 2863 */ { MAD_F(0x04f669e5) /* 0.310159583 */, 17 }, + + /* 2864 */ { MAD_F(0x04f7015d) /* 0.310304037 */, 17 }, + /* 2865 */ { MAD_F(0x04f798da) /* 0.310448507 */, 17 }, + /* 2866 */ { MAD_F(0x04f8305c) /* 0.310592994 */, 17 }, + /* 2867 */ { MAD_F(0x04f8c7e2) /* 0.310737498 */, 17 }, + /* 2868 */ { MAD_F(0x04f95f6c) /* 0.310882018 */, 17 }, + /* 2869 */ { MAD_F(0x04f9f6fb) /* 0.311026556 */, 17 }, + /* 2870 */ { MAD_F(0x04fa8e8f) /* 0.311171110 */, 17 }, + /* 2871 */ { MAD_F(0x04fb2627) /* 0.311315681 */, 17 }, + /* 2872 */ { MAD_F(0x04fbbdc3) /* 0.311460269 */, 17 }, + /* 2873 */ { MAD_F(0x04fc5564) /* 0.311604874 */, 17 }, + /* 2874 */ { MAD_F(0x04fced0a) /* 0.311749495 */, 17 }, + /* 2875 */ { MAD_F(0x04fd84b4) /* 0.311894133 */, 17 }, + /* 2876 */ { MAD_F(0x04fe1c62) /* 0.312038788 */, 17 }, + /* 2877 */ { MAD_F(0x04feb415) /* 0.312183460 */, 17 }, + /* 2878 */ { MAD_F(0x04ff4bcd) /* 0.312328148 */, 17 }, + /* 2879 */ { MAD_F(0x04ffe389) /* 0.312472854 */, 17 }, + + /* 2880 */ { MAD_F(0x05007b49) /* 0.312617576 */, 17 }, + /* 2881 */ { MAD_F(0x0501130e) /* 0.312762314 */, 17 }, + /* 2882 */ { MAD_F(0x0501aad8) /* 0.312907070 */, 17 }, + /* 2883 */ { MAD_F(0x050242a6) /* 0.313051842 */, 17 }, + /* 2884 */ { MAD_F(0x0502da78) /* 0.313196631 */, 17 }, + /* 2885 */ { MAD_F(0x0503724f) /* 0.313341437 */, 17 }, + /* 2886 */ { MAD_F(0x05040a2b) /* 0.313486259 */, 17 }, + /* 2887 */ { MAD_F(0x0504a20b) /* 0.313631098 */, 17 }, + /* 2888 */ { MAD_F(0x050539ef) /* 0.313775954 */, 17 }, + /* 2889 */ { MAD_F(0x0505d1d8) /* 0.313920827 */, 17 }, + /* 2890 */ { MAD_F(0x050669c5) /* 0.314065716 */, 17 }, + /* 2891 */ { MAD_F(0x050701b7) /* 0.314210622 */, 17 }, + /* 2892 */ { MAD_F(0x050799ae) /* 0.314355545 */, 17 }, + /* 2893 */ { MAD_F(0x050831a9) /* 0.314500484 */, 17 }, + /* 2894 */ { MAD_F(0x0508c9a8) /* 0.314645440 */, 17 }, + /* 2895 */ { MAD_F(0x050961ac) /* 0.314790413 */, 17 }, + + /* 2896 */ { MAD_F(0x0509f9b4) /* 0.314935403 */, 17 }, + /* 2897 */ { MAD_F(0x050a91c1) /* 0.315080409 */, 17 }, + /* 2898 */ { MAD_F(0x050b29d2) /* 0.315225432 */, 17 }, + /* 2899 */ { MAD_F(0x050bc1e8) /* 0.315370472 */, 17 }, + /* 2900 */ { MAD_F(0x050c5a02) /* 0.315515528 */, 17 }, + /* 2901 */ { MAD_F(0x050cf221) /* 0.315660601 */, 17 }, + /* 2902 */ { MAD_F(0x050d8a44) /* 0.315805690 */, 17 }, + /* 2903 */ { MAD_F(0x050e226c) /* 0.315950797 */, 17 }, + /* 2904 */ { MAD_F(0x050eba98) /* 0.316095920 */, 17 }, + /* 2905 */ { MAD_F(0x050f52c9) /* 0.316241059 */, 17 }, + /* 2906 */ { MAD_F(0x050feafe) /* 0.316386216 */, 17 }, + /* 2907 */ { MAD_F(0x05108337) /* 0.316531388 */, 17 }, + /* 2908 */ { MAD_F(0x05111b75) /* 0.316676578 */, 17 }, + /* 2909 */ { MAD_F(0x0511b3b8) /* 0.316821784 */, 17 }, + /* 2910 */ { MAD_F(0x05124bff) /* 0.316967007 */, 17 }, + /* 2911 */ { MAD_F(0x0512e44a) /* 0.317112247 */, 17 }, + + /* 2912 */ { MAD_F(0x05137c9a) /* 0.317257503 */, 17 }, + /* 2913 */ { MAD_F(0x051414ee) /* 0.317402775 */, 17 }, + /* 2914 */ { MAD_F(0x0514ad47) /* 0.317548065 */, 17 }, + /* 2915 */ { MAD_F(0x051545a5) /* 0.317693371 */, 17 }, + /* 2916 */ { MAD_F(0x0515de06) /* 0.317838693 */, 17 }, + /* 2917 */ { MAD_F(0x0516766d) /* 0.317984033 */, 17 }, + /* 2918 */ { MAD_F(0x05170ed7) /* 0.318129388 */, 17 }, + /* 2919 */ { MAD_F(0x0517a746) /* 0.318274761 */, 17 }, + /* 2920 */ { MAD_F(0x05183fba) /* 0.318420150 */, 17 }, + /* 2921 */ { MAD_F(0x0518d832) /* 0.318565555 */, 17 }, + /* 2922 */ { MAD_F(0x051970ae) /* 0.318710978 */, 17 }, + /* 2923 */ { MAD_F(0x051a092f) /* 0.318856416 */, 17 }, + /* 2924 */ { MAD_F(0x051aa1b5) /* 0.319001872 */, 17 }, + /* 2925 */ { MAD_F(0x051b3a3f) /* 0.319147344 */, 17 }, + /* 2926 */ { MAD_F(0x051bd2cd) /* 0.319292832 */, 17 }, + /* 2927 */ { MAD_F(0x051c6b60) /* 0.319438338 */, 17 }, + + /* 2928 */ { MAD_F(0x051d03f7) /* 0.319583859 */, 17 }, + /* 2929 */ { MAD_F(0x051d9c92) /* 0.319729398 */, 17 }, + /* 2930 */ { MAD_F(0x051e3532) /* 0.319874952 */, 17 }, + /* 2931 */ { MAD_F(0x051ecdd7) /* 0.320020524 */, 17 }, + /* 2932 */ { MAD_F(0x051f6680) /* 0.320166112 */, 17 }, + /* 2933 */ { MAD_F(0x051fff2d) /* 0.320311716 */, 17 }, + /* 2934 */ { MAD_F(0x052097df) /* 0.320457337 */, 17 }, + /* 2935 */ { MAD_F(0x05213095) /* 0.320602975 */, 17 }, + /* 2936 */ { MAD_F(0x0521c950) /* 0.320748629 */, 17 }, + /* 2937 */ { MAD_F(0x0522620f) /* 0.320894300 */, 17 }, + /* 2938 */ { MAD_F(0x0522fad3) /* 0.321039987 */, 17 }, + /* 2939 */ { MAD_F(0x0523939b) /* 0.321185691 */, 17 }, + /* 2940 */ { MAD_F(0x05242c68) /* 0.321331411 */, 17 }, + /* 2941 */ { MAD_F(0x0524c538) /* 0.321477148 */, 17 }, + /* 2942 */ { MAD_F(0x05255e0e) /* 0.321622901 */, 17 }, + /* 2943 */ { MAD_F(0x0525f6e8) /* 0.321768671 */, 17 }, + + /* 2944 */ { MAD_F(0x05268fc6) /* 0.321914457 */, 17 }, + /* 2945 */ { MAD_F(0x052728a9) /* 0.322060260 */, 17 }, + /* 2946 */ { MAD_F(0x0527c190) /* 0.322206079 */, 17 }, + /* 2947 */ { MAD_F(0x05285a7b) /* 0.322351915 */, 17 }, + /* 2948 */ { MAD_F(0x0528f36b) /* 0.322497768 */, 17 }, + /* 2949 */ { MAD_F(0x05298c5f) /* 0.322643636 */, 17 }, + /* 2950 */ { MAD_F(0x052a2558) /* 0.322789522 */, 17 }, + /* 2951 */ { MAD_F(0x052abe55) /* 0.322935424 */, 17 }, + /* 2952 */ { MAD_F(0x052b5757) /* 0.323081342 */, 17 }, + /* 2953 */ { MAD_F(0x052bf05d) /* 0.323227277 */, 17 }, + /* 2954 */ { MAD_F(0x052c8968) /* 0.323373228 */, 17 }, + /* 2955 */ { MAD_F(0x052d2277) /* 0.323519196 */, 17 }, + /* 2956 */ { MAD_F(0x052dbb8a) /* 0.323665180 */, 17 }, + /* 2957 */ { MAD_F(0x052e54a2) /* 0.323811180 */, 17 }, + /* 2958 */ { MAD_F(0x052eedbe) /* 0.323957197 */, 17 }, + /* 2959 */ { MAD_F(0x052f86de) /* 0.324103231 */, 17 }, + + /* 2960 */ { MAD_F(0x05302003) /* 0.324249281 */, 17 }, + /* 2961 */ { MAD_F(0x0530b92d) /* 0.324395347 */, 17 }, + /* 2962 */ { MAD_F(0x0531525b) /* 0.324541430 */, 17 }, + /* 2963 */ { MAD_F(0x0531eb8d) /* 0.324687530 */, 17 }, + /* 2964 */ { MAD_F(0x053284c4) /* 0.324833646 */, 17 }, + /* 2965 */ { MAD_F(0x05331dff) /* 0.324979778 */, 17 }, + /* 2966 */ { MAD_F(0x0533b73e) /* 0.325125926 */, 17 }, + /* 2967 */ { MAD_F(0x05345082) /* 0.325272091 */, 17 }, + /* 2968 */ { MAD_F(0x0534e9ca) /* 0.325418273 */, 17 }, + /* 2969 */ { MAD_F(0x05358317) /* 0.325564471 */, 17 }, + /* 2970 */ { MAD_F(0x05361c68) /* 0.325710685 */, 17 }, + /* 2971 */ { MAD_F(0x0536b5be) /* 0.325856916 */, 17 }, + /* 2972 */ { MAD_F(0x05374f17) /* 0.326003163 */, 17 }, + /* 2973 */ { MAD_F(0x0537e876) /* 0.326149427 */, 17 }, + /* 2974 */ { MAD_F(0x053881d9) /* 0.326295707 */, 17 }, + /* 2975 */ { MAD_F(0x05391b40) /* 0.326442003 */, 17 }, + + /* 2976 */ { MAD_F(0x0539b4ab) /* 0.326588316 */, 17 }, + /* 2977 */ { MAD_F(0x053a4e1b) /* 0.326734645 */, 17 }, + /* 2978 */ { MAD_F(0x053ae78f) /* 0.326880990 */, 17 }, + /* 2979 */ { MAD_F(0x053b8108) /* 0.327027352 */, 17 }, + /* 2980 */ { MAD_F(0x053c1a85) /* 0.327173730 */, 17 }, + /* 2981 */ { MAD_F(0x053cb407) /* 0.327320125 */, 17 }, + /* 2982 */ { MAD_F(0x053d4d8d) /* 0.327466536 */, 17 }, + /* 2983 */ { MAD_F(0x053de717) /* 0.327612963 */, 17 }, + /* 2984 */ { MAD_F(0x053e80a6) /* 0.327759407 */, 17 }, + /* 2985 */ { MAD_F(0x053f1a39) /* 0.327905867 */, 17 }, + /* 2986 */ { MAD_F(0x053fb3d0) /* 0.328052344 */, 17 }, + /* 2987 */ { MAD_F(0x05404d6c) /* 0.328198837 */, 17 }, + /* 2988 */ { MAD_F(0x0540e70c) /* 0.328345346 */, 17 }, + /* 2989 */ { MAD_F(0x054180b1) /* 0.328491871 */, 17 }, + /* 2990 */ { MAD_F(0x05421a5a) /* 0.328638413 */, 17 }, + /* 2991 */ { MAD_F(0x0542b407) /* 0.328784971 */, 17 }, + + /* 2992 */ { MAD_F(0x05434db9) /* 0.328931546 */, 17 }, + /* 2993 */ { MAD_F(0x0543e76f) /* 0.329078137 */, 17 }, + /* 2994 */ { MAD_F(0x0544812a) /* 0.329224744 */, 17 }, + /* 2995 */ { MAD_F(0x05451ae9) /* 0.329371367 */, 17 }, + /* 2996 */ { MAD_F(0x0545b4ac) /* 0.329518007 */, 17 }, + /* 2997 */ { MAD_F(0x05464e74) /* 0.329664663 */, 17 }, + /* 2998 */ { MAD_F(0x0546e840) /* 0.329811336 */, 17 }, + /* 2999 */ { MAD_F(0x05478211) /* 0.329958024 */, 17 }, + /* 3000 */ { MAD_F(0x05481be5) /* 0.330104730 */, 17 }, + /* 3001 */ { MAD_F(0x0548b5bf) /* 0.330251451 */, 17 }, + /* 3002 */ { MAD_F(0x05494f9c) /* 0.330398189 */, 17 }, + /* 3003 */ { MAD_F(0x0549e97e) /* 0.330544943 */, 17 }, + /* 3004 */ { MAD_F(0x054a8364) /* 0.330691713 */, 17 }, + /* 3005 */ { MAD_F(0x054b1d4f) /* 0.330838499 */, 17 }, + /* 3006 */ { MAD_F(0x054bb73e) /* 0.330985302 */, 17 }, + /* 3007 */ { MAD_F(0x054c5132) /* 0.331132121 */, 17 }, + + /* 3008 */ { MAD_F(0x054ceb2a) /* 0.331278957 */, 17 }, + /* 3009 */ { MAD_F(0x054d8526) /* 0.331425808 */, 17 }, + /* 3010 */ { MAD_F(0x054e1f26) /* 0.331572676 */, 17 }, + /* 3011 */ { MAD_F(0x054eb92b) /* 0.331719560 */, 17 }, + /* 3012 */ { MAD_F(0x054f5334) /* 0.331866461 */, 17 }, + /* 3013 */ { MAD_F(0x054fed42) /* 0.332013377 */, 17 }, + /* 3014 */ { MAD_F(0x05508754) /* 0.332160310 */, 17 }, + /* 3015 */ { MAD_F(0x0551216b) /* 0.332307260 */, 17 }, + /* 3016 */ { MAD_F(0x0551bb85) /* 0.332454225 */, 17 }, + /* 3017 */ { MAD_F(0x055255a4) /* 0.332601207 */, 17 }, + /* 3018 */ { MAD_F(0x0552efc8) /* 0.332748205 */, 17 }, + /* 3019 */ { MAD_F(0x055389f0) /* 0.332895219 */, 17 }, + /* 3020 */ { MAD_F(0x0554241c) /* 0.333042249 */, 17 }, + /* 3021 */ { MAD_F(0x0554be4c) /* 0.333189296 */, 17 }, + /* 3022 */ { MAD_F(0x05555881) /* 0.333336359 */, 17 }, + /* 3023 */ { MAD_F(0x0555f2ba) /* 0.333483438 */, 17 }, + + /* 3024 */ { MAD_F(0x05568cf8) /* 0.333630533 */, 17 }, + /* 3025 */ { MAD_F(0x0557273a) /* 0.333777645 */, 17 }, + /* 3026 */ { MAD_F(0x0557c180) /* 0.333924772 */, 17 }, + /* 3027 */ { MAD_F(0x05585bcb) /* 0.334071916 */, 17 }, + /* 3028 */ { MAD_F(0x0558f61a) /* 0.334219076 */, 17 }, + /* 3029 */ { MAD_F(0x0559906d) /* 0.334366253 */, 17 }, + /* 3030 */ { MAD_F(0x055a2ac5) /* 0.334513445 */, 17 }, + /* 3031 */ { MAD_F(0x055ac521) /* 0.334660654 */, 17 }, + /* 3032 */ { MAD_F(0x055b5f81) /* 0.334807879 */, 17 }, + /* 3033 */ { MAD_F(0x055bf9e6) /* 0.334955120 */, 17 }, + /* 3034 */ { MAD_F(0x055c944f) /* 0.335102377 */, 17 }, + /* 3035 */ { MAD_F(0x055d2ebd) /* 0.335249651 */, 17 }, + /* 3036 */ { MAD_F(0x055dc92e) /* 0.335396941 */, 17 }, + /* 3037 */ { MAD_F(0x055e63a5) /* 0.335544246 */, 17 }, + /* 3038 */ { MAD_F(0x055efe1f) /* 0.335691568 */, 17 }, + /* 3039 */ { MAD_F(0x055f989e) /* 0.335838906 */, 17 }, + + /* 3040 */ { MAD_F(0x05603321) /* 0.335986261 */, 17 }, + /* 3041 */ { MAD_F(0x0560cda8) /* 0.336133631 */, 17 }, + /* 3042 */ { MAD_F(0x05616834) /* 0.336281018 */, 17 }, + /* 3043 */ { MAD_F(0x056202c4) /* 0.336428421 */, 17 }, + /* 3044 */ { MAD_F(0x05629d59) /* 0.336575840 */, 17 }, + /* 3045 */ { MAD_F(0x056337f2) /* 0.336723275 */, 17 }, + /* 3046 */ { MAD_F(0x0563d28f) /* 0.336870726 */, 17 }, + /* 3047 */ { MAD_F(0x05646d30) /* 0.337018193 */, 17 }, + /* 3048 */ { MAD_F(0x056507d6) /* 0.337165677 */, 17 }, + /* 3049 */ { MAD_F(0x0565a280) /* 0.337313176 */, 17 }, + /* 3050 */ { MAD_F(0x05663d2f) /* 0.337460692 */, 17 }, + /* 3051 */ { MAD_F(0x0566d7e1) /* 0.337608224 */, 17 }, + /* 3052 */ { MAD_F(0x05677298) /* 0.337755772 */, 17 }, + /* 3053 */ { MAD_F(0x05680d54) /* 0.337903336 */, 17 }, + /* 3054 */ { MAD_F(0x0568a814) /* 0.338050916 */, 17 }, + /* 3055 */ { MAD_F(0x056942d8) /* 0.338198513 */, 17 }, + + /* 3056 */ { MAD_F(0x0569dda0) /* 0.338346125 */, 17 }, + /* 3057 */ { MAD_F(0x056a786d) /* 0.338493753 */, 17 }, + /* 3058 */ { MAD_F(0x056b133e) /* 0.338641398 */, 17 }, + /* 3059 */ { MAD_F(0x056bae13) /* 0.338789059 */, 17 }, + /* 3060 */ { MAD_F(0x056c48ed) /* 0.338936736 */, 17 }, + /* 3061 */ { MAD_F(0x056ce3cb) /* 0.339084429 */, 17 }, + /* 3062 */ { MAD_F(0x056d7ead) /* 0.339232138 */, 17 }, + /* 3063 */ { MAD_F(0x056e1994) /* 0.339379863 */, 17 }, + /* 3064 */ { MAD_F(0x056eb47f) /* 0.339527604 */, 17 }, + /* 3065 */ { MAD_F(0x056f4f6e) /* 0.339675361 */, 17 }, + /* 3066 */ { MAD_F(0x056fea62) /* 0.339823134 */, 17 }, + /* 3067 */ { MAD_F(0x0570855a) /* 0.339970924 */, 17 }, + /* 3068 */ { MAD_F(0x05712056) /* 0.340118729 */, 17 }, + /* 3069 */ { MAD_F(0x0571bb56) /* 0.340266550 */, 17 }, + /* 3070 */ { MAD_F(0x0572565b) /* 0.340414388 */, 17 }, + /* 3071 */ { MAD_F(0x0572f164) /* 0.340562242 */, 17 }, + + /* 3072 */ { MAD_F(0x05738c72) /* 0.340710111 */, 17 }, + /* 3073 */ { MAD_F(0x05742784) /* 0.340857997 */, 17 }, + /* 3074 */ { MAD_F(0x0574c29a) /* 0.341005899 */, 17 }, + /* 3075 */ { MAD_F(0x05755db4) /* 0.341153816 */, 17 }, + /* 3076 */ { MAD_F(0x0575f8d3) /* 0.341301750 */, 17 }, + /* 3077 */ { MAD_F(0x057693f6) /* 0.341449700 */, 17 }, + /* 3078 */ { MAD_F(0x05772f1d) /* 0.341597666 */, 17 }, + /* 3079 */ { MAD_F(0x0577ca49) /* 0.341745648 */, 17 }, + /* 3080 */ { MAD_F(0x05786578) /* 0.341893646 */, 17 }, + /* 3081 */ { MAD_F(0x057900ad) /* 0.342041659 */, 17 }, + /* 3082 */ { MAD_F(0x05799be5) /* 0.342189689 */, 17 }, + /* 3083 */ { MAD_F(0x057a3722) /* 0.342337735 */, 17 }, + /* 3084 */ { MAD_F(0x057ad263) /* 0.342485797 */, 17 }, + /* 3085 */ { MAD_F(0x057b6da8) /* 0.342633875 */, 17 }, + /* 3086 */ { MAD_F(0x057c08f2) /* 0.342781969 */, 17 }, + /* 3087 */ { MAD_F(0x057ca440) /* 0.342930079 */, 17 }, + + /* 3088 */ { MAD_F(0x057d3f92) /* 0.343078205 */, 17 }, + /* 3089 */ { MAD_F(0x057ddae9) /* 0.343226347 */, 17 }, + /* 3090 */ { MAD_F(0x057e7644) /* 0.343374505 */, 17 }, + /* 3091 */ { MAD_F(0x057f11a3) /* 0.343522679 */, 17 }, + /* 3092 */ { MAD_F(0x057fad06) /* 0.343670869 */, 17 }, + /* 3093 */ { MAD_F(0x0580486e) /* 0.343819075 */, 17 }, + /* 3094 */ { MAD_F(0x0580e3da) /* 0.343967296 */, 17 }, + /* 3095 */ { MAD_F(0x05817f4a) /* 0.344115534 */, 17 }, + /* 3096 */ { MAD_F(0x05821abf) /* 0.344263788 */, 17 }, + /* 3097 */ { MAD_F(0x0582b638) /* 0.344412058 */, 17 }, + /* 3098 */ { MAD_F(0x058351b5) /* 0.344560343 */, 17 }, + /* 3099 */ { MAD_F(0x0583ed36) /* 0.344708645 */, 17 }, + /* 3100 */ { MAD_F(0x058488bc) /* 0.344856963 */, 17 }, + /* 3101 */ { MAD_F(0x05852446) /* 0.345005296 */, 17 }, + /* 3102 */ { MAD_F(0x0585bfd4) /* 0.345153646 */, 17 }, + /* 3103 */ { MAD_F(0x05865b67) /* 0.345302011 */, 17 }, + + /* 3104 */ { MAD_F(0x0586f6fd) /* 0.345450393 */, 17 }, + /* 3105 */ { MAD_F(0x05879298) /* 0.345598790 */, 17 }, + /* 3106 */ { MAD_F(0x05882e38) /* 0.345747203 */, 17 }, + /* 3107 */ { MAD_F(0x0588c9dc) /* 0.345895632 */, 17 }, + /* 3108 */ { MAD_F(0x05896583) /* 0.346044077 */, 17 }, + /* 3109 */ { MAD_F(0x058a0130) /* 0.346192538 */, 17 }, + /* 3110 */ { MAD_F(0x058a9ce0) /* 0.346341015 */, 17 }, + /* 3111 */ { MAD_F(0x058b3895) /* 0.346489508 */, 17 }, + /* 3112 */ { MAD_F(0x058bd44e) /* 0.346638017 */, 17 }, + /* 3113 */ { MAD_F(0x058c700b) /* 0.346786542 */, 17 }, + /* 3114 */ { MAD_F(0x058d0bcd) /* 0.346935082 */, 17 }, + /* 3115 */ { MAD_F(0x058da793) /* 0.347083639 */, 17 }, + /* 3116 */ { MAD_F(0x058e435d) /* 0.347232211 */, 17 }, + /* 3117 */ { MAD_F(0x058edf2b) /* 0.347380799 */, 17 }, + /* 3118 */ { MAD_F(0x058f7afe) /* 0.347529403 */, 17 }, + /* 3119 */ { MAD_F(0x059016d5) /* 0.347678023 */, 17 }, + + /* 3120 */ { MAD_F(0x0590b2b0) /* 0.347826659 */, 17 }, + /* 3121 */ { MAD_F(0x05914e8f) /* 0.347975311 */, 17 }, + /* 3122 */ { MAD_F(0x0591ea73) /* 0.348123979 */, 17 }, + /* 3123 */ { MAD_F(0x0592865b) /* 0.348272662 */, 17 }, + /* 3124 */ { MAD_F(0x05932247) /* 0.348421362 */, 17 }, + /* 3125 */ { MAD_F(0x0593be37) /* 0.348570077 */, 17 }, + /* 3126 */ { MAD_F(0x05945a2c) /* 0.348718808 */, 17 }, + /* 3127 */ { MAD_F(0x0594f625) /* 0.348867555 */, 17 }, + /* 3128 */ { MAD_F(0x05959222) /* 0.349016318 */, 17 }, + /* 3129 */ { MAD_F(0x05962e24) /* 0.349165097 */, 17 }, + /* 3130 */ { MAD_F(0x0596ca2a) /* 0.349313892 */, 17 }, + /* 3131 */ { MAD_F(0x05976634) /* 0.349462702 */, 17 }, + /* 3132 */ { MAD_F(0x05980242) /* 0.349611528 */, 17 }, + /* 3133 */ { MAD_F(0x05989e54) /* 0.349760370 */, 17 }, + /* 3134 */ { MAD_F(0x05993a6b) /* 0.349909228 */, 17 }, + /* 3135 */ { MAD_F(0x0599d686) /* 0.350058102 */, 17 }, + + /* 3136 */ { MAD_F(0x059a72a5) /* 0.350206992 */, 17 }, + /* 3137 */ { MAD_F(0x059b0ec9) /* 0.350355897 */, 17 }, + /* 3138 */ { MAD_F(0x059baaf1) /* 0.350504818 */, 17 }, + /* 3139 */ { MAD_F(0x059c471d) /* 0.350653756 */, 17 }, + /* 3140 */ { MAD_F(0x059ce34d) /* 0.350802708 */, 17 }, + /* 3141 */ { MAD_F(0x059d7f81) /* 0.350951677 */, 17 }, + /* 3142 */ { MAD_F(0x059e1bba) /* 0.351100662 */, 17 }, + /* 3143 */ { MAD_F(0x059eb7f7) /* 0.351249662 */, 17 }, + /* 3144 */ { MAD_F(0x059f5438) /* 0.351398678 */, 17 }, + /* 3145 */ { MAD_F(0x059ff07e) /* 0.351547710 */, 17 }, + /* 3146 */ { MAD_F(0x05a08cc7) /* 0.351696758 */, 17 }, + /* 3147 */ { MAD_F(0x05a12915) /* 0.351845821 */, 17 }, + /* 3148 */ { MAD_F(0x05a1c567) /* 0.351994901 */, 17 }, + /* 3149 */ { MAD_F(0x05a261be) /* 0.352143996 */, 17 }, + /* 3150 */ { MAD_F(0x05a2fe18) /* 0.352293107 */, 17 }, + /* 3151 */ { MAD_F(0x05a39a77) /* 0.352442233 */, 17 }, + + /* 3152 */ { MAD_F(0x05a436da) /* 0.352591376 */, 17 }, + /* 3153 */ { MAD_F(0x05a4d342) /* 0.352740534 */, 17 }, + /* 3154 */ { MAD_F(0x05a56fad) /* 0.352889708 */, 17 }, + /* 3155 */ { MAD_F(0x05a60c1d) /* 0.353038898 */, 17 }, + /* 3156 */ { MAD_F(0x05a6a891) /* 0.353188103 */, 17 }, + /* 3157 */ { MAD_F(0x05a7450a) /* 0.353337325 */, 17 }, + /* 3158 */ { MAD_F(0x05a7e186) /* 0.353486562 */, 17 }, + /* 3159 */ { MAD_F(0x05a87e07) /* 0.353635814 */, 17 }, + /* 3160 */ { MAD_F(0x05a91a8c) /* 0.353785083 */, 17 }, + /* 3161 */ { MAD_F(0x05a9b715) /* 0.353934367 */, 17 }, + /* 3162 */ { MAD_F(0x05aa53a2) /* 0.354083667 */, 17 }, + /* 3163 */ { MAD_F(0x05aaf034) /* 0.354232983 */, 17 }, + /* 3164 */ { MAD_F(0x05ab8cca) /* 0.354382314 */, 17 }, + /* 3165 */ { MAD_F(0x05ac2964) /* 0.354531662 */, 17 }, + /* 3166 */ { MAD_F(0x05acc602) /* 0.354681025 */, 17 }, + /* 3167 */ { MAD_F(0x05ad62a5) /* 0.354830403 */, 17 }, + + /* 3168 */ { MAD_F(0x05adff4c) /* 0.354979798 */, 17 }, + /* 3169 */ { MAD_F(0x05ae9bf7) /* 0.355129208 */, 17 }, + /* 3170 */ { MAD_F(0x05af38a6) /* 0.355278634 */, 17 }, + /* 3171 */ { MAD_F(0x05afd559) /* 0.355428075 */, 17 }, + /* 3172 */ { MAD_F(0x05b07211) /* 0.355577533 */, 17 }, + /* 3173 */ { MAD_F(0x05b10ecd) /* 0.355727006 */, 17 }, + /* 3174 */ { MAD_F(0x05b1ab8d) /* 0.355876494 */, 17 }, + /* 3175 */ { MAD_F(0x05b24851) /* 0.356025999 */, 17 }, + /* 3176 */ { MAD_F(0x05b2e51a) /* 0.356175519 */, 17 }, + /* 3177 */ { MAD_F(0x05b381e6) /* 0.356325054 */, 17 }, + /* 3178 */ { MAD_F(0x05b41eb7) /* 0.356474606 */, 17 }, + /* 3179 */ { MAD_F(0x05b4bb8c) /* 0.356624173 */, 17 }, + /* 3180 */ { MAD_F(0x05b55866) /* 0.356773756 */, 17 }, + /* 3181 */ { MAD_F(0x05b5f543) /* 0.356923354 */, 17 }, + /* 3182 */ { MAD_F(0x05b69225) /* 0.357072969 */, 17 }, + /* 3183 */ { MAD_F(0x05b72f0b) /* 0.357222598 */, 17 }, + + /* 3184 */ { MAD_F(0x05b7cbf5) /* 0.357372244 */, 17 }, + /* 3185 */ { MAD_F(0x05b868e3) /* 0.357521905 */, 17 }, + /* 3186 */ { MAD_F(0x05b905d6) /* 0.357671582 */, 17 }, + /* 3187 */ { MAD_F(0x05b9a2cd) /* 0.357821275 */, 17 }, + /* 3188 */ { MAD_F(0x05ba3fc8) /* 0.357970983 */, 17 }, + /* 3189 */ { MAD_F(0x05badcc7) /* 0.358120707 */, 17 }, + /* 3190 */ { MAD_F(0x05bb79ca) /* 0.358270446 */, 17 }, + /* 3191 */ { MAD_F(0x05bc16d2) /* 0.358420201 */, 17 }, + /* 3192 */ { MAD_F(0x05bcb3de) /* 0.358569972 */, 17 }, + /* 3193 */ { MAD_F(0x05bd50ee) /* 0.358719758 */, 17 }, + /* 3194 */ { MAD_F(0x05bdee02) /* 0.358869560 */, 17 }, + /* 3195 */ { MAD_F(0x05be8b1a) /* 0.359019378 */, 17 }, + /* 3196 */ { MAD_F(0x05bf2837) /* 0.359169211 */, 17 }, + /* 3197 */ { MAD_F(0x05bfc558) /* 0.359319060 */, 17 }, + /* 3198 */ { MAD_F(0x05c0627d) /* 0.359468925 */, 17 }, + /* 3199 */ { MAD_F(0x05c0ffa6) /* 0.359618805 */, 17 }, + + /* 3200 */ { MAD_F(0x05c19cd3) /* 0.359768701 */, 17 }, + /* 3201 */ { MAD_F(0x05c23a05) /* 0.359918612 */, 17 }, + /* 3202 */ { MAD_F(0x05c2d73a) /* 0.360068540 */, 17 }, + /* 3203 */ { MAD_F(0x05c37474) /* 0.360218482 */, 17 }, + /* 3204 */ { MAD_F(0x05c411b2) /* 0.360368440 */, 17 }, + /* 3205 */ { MAD_F(0x05c4aef5) /* 0.360518414 */, 17 }, + /* 3206 */ { MAD_F(0x05c54c3b) /* 0.360668404 */, 17 }, + /* 3207 */ { MAD_F(0x05c5e986) /* 0.360818409 */, 17 }, + /* 3208 */ { MAD_F(0x05c686d5) /* 0.360968429 */, 17 }, + /* 3209 */ { MAD_F(0x05c72428) /* 0.361118466 */, 17 }, + /* 3210 */ { MAD_F(0x05c7c17f) /* 0.361268517 */, 17 }, + /* 3211 */ { MAD_F(0x05c85eda) /* 0.361418585 */, 17 }, + /* 3212 */ { MAD_F(0x05c8fc3a) /* 0.361568668 */, 17 }, + /* 3213 */ { MAD_F(0x05c9999e) /* 0.361718766 */, 17 }, + /* 3214 */ { MAD_F(0x05ca3706) /* 0.361868881 */, 17 }, + /* 3215 */ { MAD_F(0x05cad472) /* 0.362019010 */, 17 }, + + /* 3216 */ { MAD_F(0x05cb71e2) /* 0.362169156 */, 17 }, + /* 3217 */ { MAD_F(0x05cc0f57) /* 0.362319316 */, 17 }, + /* 3218 */ { MAD_F(0x05ccaccf) /* 0.362469493 */, 17 }, + /* 3219 */ { MAD_F(0x05cd4a4c) /* 0.362619685 */, 17 }, + /* 3220 */ { MAD_F(0x05cde7cd) /* 0.362769892 */, 17 }, + /* 3221 */ { MAD_F(0x05ce8552) /* 0.362920115 */, 17 }, + /* 3222 */ { MAD_F(0x05cf22dc) /* 0.363070354 */, 17 }, + /* 3223 */ { MAD_F(0x05cfc069) /* 0.363220608 */, 17 }, + /* 3224 */ { MAD_F(0x05d05dfb) /* 0.363370878 */, 17 }, + /* 3225 */ { MAD_F(0x05d0fb91) /* 0.363521163 */, 17 }, + /* 3226 */ { MAD_F(0x05d1992b) /* 0.363671464 */, 17 }, + /* 3227 */ { MAD_F(0x05d236c9) /* 0.363821780 */, 17 }, + /* 3228 */ { MAD_F(0x05d2d46c) /* 0.363972112 */, 17 }, + /* 3229 */ { MAD_F(0x05d37212) /* 0.364122459 */, 17 }, + /* 3230 */ { MAD_F(0x05d40fbd) /* 0.364272822 */, 17 }, + /* 3231 */ { MAD_F(0x05d4ad6c) /* 0.364423200 */, 17 }, + + /* 3232 */ { MAD_F(0x05d54b1f) /* 0.364573594 */, 17 }, + /* 3233 */ { MAD_F(0x05d5e8d6) /* 0.364724004 */, 17 }, + /* 3234 */ { MAD_F(0x05d68691) /* 0.364874429 */, 17 }, + /* 3235 */ { MAD_F(0x05d72451) /* 0.365024869 */, 17 }, + /* 3236 */ { MAD_F(0x05d7c215) /* 0.365175325 */, 17 }, + /* 3237 */ { MAD_F(0x05d85fdc) /* 0.365325796 */, 17 }, + /* 3238 */ { MAD_F(0x05d8fda8) /* 0.365476283 */, 17 }, + /* 3239 */ { MAD_F(0x05d99b79) /* 0.365626786 */, 17 }, + /* 3240 */ { MAD_F(0x05da394d) /* 0.365777304 */, 17 }, + /* 3241 */ { MAD_F(0x05dad726) /* 0.365927837 */, 17 }, + /* 3242 */ { MAD_F(0x05db7502) /* 0.366078386 */, 17 }, + /* 3243 */ { MAD_F(0x05dc12e3) /* 0.366228950 */, 17 }, + /* 3244 */ { MAD_F(0x05dcb0c8) /* 0.366379530 */, 17 }, + /* 3245 */ { MAD_F(0x05dd4eb1) /* 0.366530125 */, 17 }, + /* 3246 */ { MAD_F(0x05ddec9e) /* 0.366680736 */, 17 }, + /* 3247 */ { MAD_F(0x05de8a90) /* 0.366831362 */, 17 }, + + /* 3248 */ { MAD_F(0x05df2885) /* 0.366982004 */, 17 }, + /* 3249 */ { MAD_F(0x05dfc67f) /* 0.367132661 */, 17 }, + /* 3250 */ { MAD_F(0x05e0647d) /* 0.367283334 */, 17 }, + /* 3251 */ { MAD_F(0x05e1027f) /* 0.367434022 */, 17 }, + /* 3252 */ { MAD_F(0x05e1a085) /* 0.367584725 */, 17 }, + /* 3253 */ { MAD_F(0x05e23e8f) /* 0.367735444 */, 17 }, + /* 3254 */ { MAD_F(0x05e2dc9e) /* 0.367886179 */, 17 }, + /* 3255 */ { MAD_F(0x05e37ab0) /* 0.368036929 */, 17 }, + /* 3256 */ { MAD_F(0x05e418c7) /* 0.368187694 */, 17 }, + /* 3257 */ { MAD_F(0x05e4b6e2) /* 0.368338475 */, 17 }, + /* 3258 */ { MAD_F(0x05e55501) /* 0.368489271 */, 17 }, + /* 3259 */ { MAD_F(0x05e5f324) /* 0.368640082 */, 17 }, + /* 3260 */ { MAD_F(0x05e6914c) /* 0.368790909 */, 17 }, + /* 3261 */ { MAD_F(0x05e72f77) /* 0.368941752 */, 17 }, + /* 3262 */ { MAD_F(0x05e7cda7) /* 0.369092610 */, 17 }, + /* 3263 */ { MAD_F(0x05e86bda) /* 0.369243483 */, 17 }, + + /* 3264 */ { MAD_F(0x05e90a12) /* 0.369394372 */, 17 }, + /* 3265 */ { MAD_F(0x05e9a84e) /* 0.369545276 */, 17 }, + /* 3266 */ { MAD_F(0x05ea468e) /* 0.369696195 */, 17 }, + /* 3267 */ { MAD_F(0x05eae4d3) /* 0.369847130 */, 17 }, + /* 3268 */ { MAD_F(0x05eb831b) /* 0.369998080 */, 17 }, + /* 3269 */ { MAD_F(0x05ec2168) /* 0.370149046 */, 17 }, + /* 3270 */ { MAD_F(0x05ecbfb8) /* 0.370300027 */, 17 }, + /* 3271 */ { MAD_F(0x05ed5e0d) /* 0.370451024 */, 17 }, + /* 3272 */ { MAD_F(0x05edfc66) /* 0.370602036 */, 17 }, + /* 3273 */ { MAD_F(0x05ee9ac3) /* 0.370753063 */, 17 }, + /* 3274 */ { MAD_F(0x05ef3924) /* 0.370904105 */, 17 }, + /* 3275 */ { MAD_F(0x05efd78a) /* 0.371055163 */, 17 }, + /* 3276 */ { MAD_F(0x05f075f3) /* 0.371206237 */, 17 }, + /* 3277 */ { MAD_F(0x05f11461) /* 0.371357326 */, 17 }, + /* 3278 */ { MAD_F(0x05f1b2d3) /* 0.371508430 */, 17 }, + /* 3279 */ { MAD_F(0x05f25148) /* 0.371659549 */, 17 }, + + /* 3280 */ { MAD_F(0x05f2efc2) /* 0.371810684 */, 17 }, + /* 3281 */ { MAD_F(0x05f38e40) /* 0.371961834 */, 17 }, + /* 3282 */ { MAD_F(0x05f42cc3) /* 0.372113000 */, 17 }, + /* 3283 */ { MAD_F(0x05f4cb49) /* 0.372264181 */, 17 }, + /* 3284 */ { MAD_F(0x05f569d3) /* 0.372415377 */, 17 }, + /* 3285 */ { MAD_F(0x05f60862) /* 0.372566589 */, 17 }, + /* 3286 */ { MAD_F(0x05f6a6f5) /* 0.372717816 */, 17 }, + /* 3287 */ { MAD_F(0x05f7458b) /* 0.372869058 */, 17 }, + /* 3288 */ { MAD_F(0x05f7e426) /* 0.373020316 */, 17 }, + /* 3289 */ { MAD_F(0x05f882c5) /* 0.373171589 */, 17 }, + /* 3290 */ { MAD_F(0x05f92169) /* 0.373322877 */, 17 }, + /* 3291 */ { MAD_F(0x05f9c010) /* 0.373474181 */, 17 }, + /* 3292 */ { MAD_F(0x05fa5ebb) /* 0.373625500 */, 17 }, + /* 3293 */ { MAD_F(0x05fafd6b) /* 0.373776834 */, 17 }, + /* 3294 */ { MAD_F(0x05fb9c1e) /* 0.373928184 */, 17 }, + /* 3295 */ { MAD_F(0x05fc3ad6) /* 0.374079549 */, 17 }, + + /* 3296 */ { MAD_F(0x05fcd992) /* 0.374230929 */, 17 }, + /* 3297 */ { MAD_F(0x05fd7852) /* 0.374382325 */, 17 }, + /* 3298 */ { MAD_F(0x05fe1716) /* 0.374533735 */, 17 }, + /* 3299 */ { MAD_F(0x05feb5de) /* 0.374685162 */, 17 }, + /* 3300 */ { MAD_F(0x05ff54aa) /* 0.374836603 */, 17 }, + /* 3301 */ { MAD_F(0x05fff37b) /* 0.374988060 */, 17 }, + /* 3302 */ { MAD_F(0x0600924f) /* 0.375139532 */, 17 }, + /* 3303 */ { MAD_F(0x06013128) /* 0.375291019 */, 17 }, + /* 3304 */ { MAD_F(0x0601d004) /* 0.375442522 */, 17 }, + /* 3305 */ { MAD_F(0x06026ee5) /* 0.375594040 */, 17 }, + /* 3306 */ { MAD_F(0x06030dca) /* 0.375745573 */, 17 }, + /* 3307 */ { MAD_F(0x0603acb3) /* 0.375897122 */, 17 }, + /* 3308 */ { MAD_F(0x06044ba0) /* 0.376048685 */, 17 }, + /* 3309 */ { MAD_F(0x0604ea91) /* 0.376200265 */, 17 }, + /* 3310 */ { MAD_F(0x06058987) /* 0.376351859 */, 17 }, + /* 3311 */ { MAD_F(0x06062880) /* 0.376503468 */, 17 }, + + /* 3312 */ { MAD_F(0x0606c77d) /* 0.376655093 */, 17 }, + /* 3313 */ { MAD_F(0x0607667f) /* 0.376806733 */, 17 }, + /* 3314 */ { MAD_F(0x06080585) /* 0.376958389 */, 17 }, + /* 3315 */ { MAD_F(0x0608a48f) /* 0.377110059 */, 17 }, + /* 3316 */ { MAD_F(0x0609439c) /* 0.377261745 */, 17 }, + /* 3317 */ { MAD_F(0x0609e2ae) /* 0.377413446 */, 17 }, + /* 3318 */ { MAD_F(0x060a81c4) /* 0.377565163 */, 17 }, + /* 3319 */ { MAD_F(0x060b20df) /* 0.377716894 */, 17 }, + /* 3320 */ { MAD_F(0x060bbffd) /* 0.377868641 */, 17 }, + /* 3321 */ { MAD_F(0x060c5f1f) /* 0.378020403 */, 17 }, + /* 3322 */ { MAD_F(0x060cfe46) /* 0.378172181 */, 17 }, + /* 3323 */ { MAD_F(0x060d9d70) /* 0.378323973 */, 17 }, + /* 3324 */ { MAD_F(0x060e3c9f) /* 0.378475781 */, 17 }, + /* 3325 */ { MAD_F(0x060edbd1) /* 0.378627604 */, 17 }, + /* 3326 */ { MAD_F(0x060f7b08) /* 0.378779442 */, 17 }, + /* 3327 */ { MAD_F(0x06101a43) /* 0.378931296 */, 17 }, + + /* 3328 */ { MAD_F(0x0610b982) /* 0.379083164 */, 17 }, + /* 3329 */ { MAD_F(0x061158c5) /* 0.379235048 */, 17 }, + /* 3330 */ { MAD_F(0x0611f80c) /* 0.379386947 */, 17 }, + /* 3331 */ { MAD_F(0x06129757) /* 0.379538862 */, 17 }, + /* 3332 */ { MAD_F(0x061336a6) /* 0.379690791 */, 17 }, + /* 3333 */ { MAD_F(0x0613d5fa) /* 0.379842736 */, 17 }, + /* 3334 */ { MAD_F(0x06147551) /* 0.379994696 */, 17 }, + /* 3335 */ { MAD_F(0x061514ad) /* 0.380146671 */, 17 }, + /* 3336 */ { MAD_F(0x0615b40c) /* 0.380298661 */, 17 }, + /* 3337 */ { MAD_F(0x06165370) /* 0.380450666 */, 17 }, + /* 3338 */ { MAD_F(0x0616f2d8) /* 0.380602687 */, 17 }, + /* 3339 */ { MAD_F(0x06179243) /* 0.380754723 */, 17 }, + /* 3340 */ { MAD_F(0x061831b3) /* 0.380906774 */, 17 }, + /* 3341 */ { MAD_F(0x0618d127) /* 0.381058840 */, 17 }, + /* 3342 */ { MAD_F(0x0619709f) /* 0.381210921 */, 17 }, + /* 3343 */ { MAD_F(0x061a101b) /* 0.381363018 */, 17 }, + + /* 3344 */ { MAD_F(0x061aaf9c) /* 0.381515130 */, 17 }, + /* 3345 */ { MAD_F(0x061b4f20) /* 0.381667257 */, 17 }, + /* 3346 */ { MAD_F(0x061beea8) /* 0.381819399 */, 17 }, + /* 3347 */ { MAD_F(0x061c8e34) /* 0.381971556 */, 17 }, + /* 3348 */ { MAD_F(0x061d2dc5) /* 0.382123728 */, 17 }, + /* 3349 */ { MAD_F(0x061dcd59) /* 0.382275916 */, 17 }, + /* 3350 */ { MAD_F(0x061e6cf2) /* 0.382428118 */, 17 }, + /* 3351 */ { MAD_F(0x061f0c8f) /* 0.382580336 */, 17 }, + /* 3352 */ { MAD_F(0x061fac2f) /* 0.382732569 */, 17 }, + /* 3353 */ { MAD_F(0x06204bd4) /* 0.382884817 */, 17 }, + /* 3354 */ { MAD_F(0x0620eb7d) /* 0.383037080 */, 17 }, + /* 3355 */ { MAD_F(0x06218b2a) /* 0.383189358 */, 17 }, + /* 3356 */ { MAD_F(0x06222adb) /* 0.383341652 */, 17 }, + /* 3357 */ { MAD_F(0x0622ca90) /* 0.383493960 */, 17 }, + /* 3358 */ { MAD_F(0x06236a49) /* 0.383646284 */, 17 }, + /* 3359 */ { MAD_F(0x06240a06) /* 0.383798623 */, 17 }, + + /* 3360 */ { MAD_F(0x0624a9c7) /* 0.383950977 */, 17 }, + /* 3361 */ { MAD_F(0x0625498d) /* 0.384103346 */, 17 }, + /* 3362 */ { MAD_F(0x0625e956) /* 0.384255730 */, 17 }, + /* 3363 */ { MAD_F(0x06268923) /* 0.384408129 */, 17 }, + /* 3364 */ { MAD_F(0x062728f5) /* 0.384560544 */, 17 }, + /* 3365 */ { MAD_F(0x0627c8ca) /* 0.384712973 */, 17 }, + /* 3366 */ { MAD_F(0x062868a4) /* 0.384865418 */, 17 }, + /* 3367 */ { MAD_F(0x06290881) /* 0.385017878 */, 17 }, + /* 3368 */ { MAD_F(0x0629a863) /* 0.385170352 */, 17 }, + /* 3369 */ { MAD_F(0x062a4849) /* 0.385322842 */, 17 }, + /* 3370 */ { MAD_F(0x062ae832) /* 0.385475347 */, 17 }, + /* 3371 */ { MAD_F(0x062b8820) /* 0.385627867 */, 17 }, + /* 3372 */ { MAD_F(0x062c2812) /* 0.385780402 */, 17 }, + /* 3373 */ { MAD_F(0x062cc808) /* 0.385932953 */, 17 }, + /* 3374 */ { MAD_F(0x062d6802) /* 0.386085518 */, 17 }, + /* 3375 */ { MAD_F(0x062e0800) /* 0.386238098 */, 17 }, + + /* 3376 */ { MAD_F(0x062ea802) /* 0.386390694 */, 17 }, + /* 3377 */ { MAD_F(0x062f4808) /* 0.386543304 */, 17 }, + /* 3378 */ { MAD_F(0x062fe812) /* 0.386695930 */, 17 }, + /* 3379 */ { MAD_F(0x06308820) /* 0.386848570 */, 17 }, + /* 3380 */ { MAD_F(0x06312832) /* 0.387001226 */, 17 }, + /* 3381 */ { MAD_F(0x0631c849) /* 0.387153897 */, 17 }, + /* 3382 */ { MAD_F(0x06326863) /* 0.387306582 */, 17 }, + /* 3383 */ { MAD_F(0x06330881) /* 0.387459283 */, 17 }, + /* 3384 */ { MAD_F(0x0633a8a3) /* 0.387611999 */, 17 }, + /* 3385 */ { MAD_F(0x063448ca) /* 0.387764730 */, 17 }, + /* 3386 */ { MAD_F(0x0634e8f4) /* 0.387917476 */, 17 }, + /* 3387 */ { MAD_F(0x06358923) /* 0.388070237 */, 17 }, + /* 3388 */ { MAD_F(0x06362955) /* 0.388223013 */, 17 }, + /* 3389 */ { MAD_F(0x0636c98c) /* 0.388375804 */, 17 }, + /* 3390 */ { MAD_F(0x063769c6) /* 0.388528610 */, 17 }, + /* 3391 */ { MAD_F(0x06380a05) /* 0.388681431 */, 17 }, + + /* 3392 */ { MAD_F(0x0638aa48) /* 0.388834268 */, 17 }, + /* 3393 */ { MAD_F(0x06394a8e) /* 0.388987119 */, 17 }, + /* 3394 */ { MAD_F(0x0639ead9) /* 0.389139985 */, 17 }, + /* 3395 */ { MAD_F(0x063a8b28) /* 0.389292866 */, 17 }, + /* 3396 */ { MAD_F(0x063b2b7b) /* 0.389445762 */, 17 }, + /* 3397 */ { MAD_F(0x063bcbd1) /* 0.389598674 */, 17 }, + /* 3398 */ { MAD_F(0x063c6c2c) /* 0.389751600 */, 17 }, + /* 3399 */ { MAD_F(0x063d0c8b) /* 0.389904541 */, 17 }, + /* 3400 */ { MAD_F(0x063dacee) /* 0.390057497 */, 17 }, + /* 3401 */ { MAD_F(0x063e4d55) /* 0.390210468 */, 17 }, + /* 3402 */ { MAD_F(0x063eedc0) /* 0.390363455 */, 17 }, + /* 3403 */ { MAD_F(0x063f8e2f) /* 0.390516456 */, 17 }, + /* 3404 */ { MAD_F(0x06402ea2) /* 0.390669472 */, 17 }, + /* 3405 */ { MAD_F(0x0640cf19) /* 0.390822503 */, 17 }, + /* 3406 */ { MAD_F(0x06416f94) /* 0.390975549 */, 17 }, + /* 3407 */ { MAD_F(0x06421013) /* 0.391128611 */, 17 }, + + /* 3408 */ { MAD_F(0x0642b096) /* 0.391281687 */, 17 }, + /* 3409 */ { MAD_F(0x0643511d) /* 0.391434778 */, 17 }, + /* 3410 */ { MAD_F(0x0643f1a8) /* 0.391587884 */, 17 }, + /* 3411 */ { MAD_F(0x06449237) /* 0.391741005 */, 17 }, + /* 3412 */ { MAD_F(0x064532ca) /* 0.391894141 */, 17 }, + /* 3413 */ { MAD_F(0x0645d361) /* 0.392047292 */, 17 }, + /* 3414 */ { MAD_F(0x064673fc) /* 0.392200458 */, 17 }, + /* 3415 */ { MAD_F(0x0647149c) /* 0.392353638 */, 17 }, + /* 3416 */ { MAD_F(0x0647b53f) /* 0.392506834 */, 17 }, + /* 3417 */ { MAD_F(0x064855e6) /* 0.392660045 */, 17 }, + /* 3418 */ { MAD_F(0x0648f691) /* 0.392813271 */, 17 }, + /* 3419 */ { MAD_F(0x06499740) /* 0.392966511 */, 17 }, + /* 3420 */ { MAD_F(0x064a37f4) /* 0.393119767 */, 17 }, + /* 3421 */ { MAD_F(0x064ad8ab) /* 0.393273038 */, 17 }, + /* 3422 */ { MAD_F(0x064b7966) /* 0.393426323 */, 17 }, + /* 3423 */ { MAD_F(0x064c1a25) /* 0.393579623 */, 17 }, + + /* 3424 */ { MAD_F(0x064cbae9) /* 0.393732939 */, 17 }, + /* 3425 */ { MAD_F(0x064d5bb0) /* 0.393886269 */, 17 }, + /* 3426 */ { MAD_F(0x064dfc7b) /* 0.394039614 */, 17 }, + /* 3427 */ { MAD_F(0x064e9d4b) /* 0.394192974 */, 17 }, + /* 3428 */ { MAD_F(0x064f3e1e) /* 0.394346349 */, 17 }, + /* 3429 */ { MAD_F(0x064fdef5) /* 0.394499739 */, 17 }, + /* 3430 */ { MAD_F(0x06507fd0) /* 0.394653144 */, 17 }, + /* 3431 */ { MAD_F(0x065120b0) /* 0.394806564 */, 17 }, + /* 3432 */ { MAD_F(0x0651c193) /* 0.394959999 */, 17 }, + /* 3433 */ { MAD_F(0x0652627a) /* 0.395113448 */, 17 }, + /* 3434 */ { MAD_F(0x06530366) /* 0.395266913 */, 17 }, + /* 3435 */ { MAD_F(0x0653a455) /* 0.395420392 */, 17 }, + /* 3436 */ { MAD_F(0x06544548) /* 0.395573886 */, 17 }, + /* 3437 */ { MAD_F(0x0654e640) /* 0.395727395 */, 17 }, + /* 3438 */ { MAD_F(0x0655873b) /* 0.395880919 */, 17 }, + /* 3439 */ { MAD_F(0x0656283a) /* 0.396034458 */, 17 }, + + /* 3440 */ { MAD_F(0x0656c93d) /* 0.396188012 */, 17 }, + /* 3441 */ { MAD_F(0x06576a45) /* 0.396341581 */, 17 }, + /* 3442 */ { MAD_F(0x06580b50) /* 0.396495164 */, 17 }, + /* 3443 */ { MAD_F(0x0658ac5f) /* 0.396648763 */, 17 }, + /* 3444 */ { MAD_F(0x06594d73) /* 0.396802376 */, 17 }, + /* 3445 */ { MAD_F(0x0659ee8a) /* 0.396956004 */, 17 }, + /* 3446 */ { MAD_F(0x065a8fa5) /* 0.397109647 */, 17 }, + /* 3447 */ { MAD_F(0x065b30c4) /* 0.397263305 */, 17 }, + /* 3448 */ { MAD_F(0x065bd1e7) /* 0.397416978 */, 17 }, + /* 3449 */ { MAD_F(0x065c730f) /* 0.397570666 */, 17 }, + /* 3450 */ { MAD_F(0x065d143a) /* 0.397724368 */, 17 }, + /* 3451 */ { MAD_F(0x065db569) /* 0.397878085 */, 17 }, + /* 3452 */ { MAD_F(0x065e569c) /* 0.398031818 */, 17 }, + /* 3453 */ { MAD_F(0x065ef7d3) /* 0.398185565 */, 17 }, + /* 3454 */ { MAD_F(0x065f990e) /* 0.398339326 */, 17 }, + /* 3455 */ { MAD_F(0x06603a4e) /* 0.398493103 */, 17 }, + + /* 3456 */ { MAD_F(0x0660db91) /* 0.398646895 */, 17 }, + /* 3457 */ { MAD_F(0x06617cd8) /* 0.398800701 */, 17 }, + /* 3458 */ { MAD_F(0x06621e23) /* 0.398954522 */, 17 }, + /* 3459 */ { MAD_F(0x0662bf72) /* 0.399108358 */, 17 }, + /* 3460 */ { MAD_F(0x066360c5) /* 0.399262209 */, 17 }, + /* 3461 */ { MAD_F(0x0664021c) /* 0.399416075 */, 17 }, + /* 3462 */ { MAD_F(0x0664a377) /* 0.399569955 */, 17 }, + /* 3463 */ { MAD_F(0x066544d6) /* 0.399723851 */, 17 }, + /* 3464 */ { MAD_F(0x0665e639) /* 0.399877761 */, 17 }, + /* 3465 */ { MAD_F(0x066687a0) /* 0.400031686 */, 17 }, + /* 3466 */ { MAD_F(0x0667290b) /* 0.400185625 */, 17 }, + /* 3467 */ { MAD_F(0x0667ca79) /* 0.400339580 */, 17 }, + /* 3468 */ { MAD_F(0x06686bec) /* 0.400493549 */, 17 }, + /* 3469 */ { MAD_F(0x06690d63) /* 0.400647534 */, 17 }, + /* 3470 */ { MAD_F(0x0669aede) /* 0.400801533 */, 17 }, + /* 3471 */ { MAD_F(0x066a505d) /* 0.400955546 */, 17 }, + + /* 3472 */ { MAD_F(0x066af1df) /* 0.401109575 */, 17 }, + /* 3473 */ { MAD_F(0x066b9366) /* 0.401263618 */, 17 }, + /* 3474 */ { MAD_F(0x066c34f1) /* 0.401417676 */, 17 }, + /* 3475 */ { MAD_F(0x066cd67f) /* 0.401571749 */, 17 }, + /* 3476 */ { MAD_F(0x066d7812) /* 0.401725837 */, 17 }, + /* 3477 */ { MAD_F(0x066e19a9) /* 0.401879939 */, 17 }, + /* 3478 */ { MAD_F(0x066ebb43) /* 0.402034056 */, 17 }, + /* 3479 */ { MAD_F(0x066f5ce2) /* 0.402188188 */, 17 }, + /* 3480 */ { MAD_F(0x066ffe84) /* 0.402342335 */, 17 }, + /* 3481 */ { MAD_F(0x0670a02a) /* 0.402496497 */, 17 }, + /* 3482 */ { MAD_F(0x067141d5) /* 0.402650673 */, 17 }, + /* 3483 */ { MAD_F(0x0671e383) /* 0.402804864 */, 17 }, + /* 3484 */ { MAD_F(0x06728535) /* 0.402959070 */, 17 }, + /* 3485 */ { MAD_F(0x067326ec) /* 0.403113291 */, 17 }, + /* 3486 */ { MAD_F(0x0673c8a6) /* 0.403267526 */, 17 }, + /* 3487 */ { MAD_F(0x06746a64) /* 0.403421776 */, 17 }, + + /* 3488 */ { MAD_F(0x06750c26) /* 0.403576041 */, 17 }, + /* 3489 */ { MAD_F(0x0675adec) /* 0.403730320 */, 17 }, + /* 3490 */ { MAD_F(0x06764fb6) /* 0.403884615 */, 17 }, + /* 3491 */ { MAD_F(0x0676f184) /* 0.404038924 */, 17 }, + /* 3492 */ { MAD_F(0x06779356) /* 0.404193247 */, 17 }, + /* 3493 */ { MAD_F(0x0678352c) /* 0.404347586 */, 17 }, + /* 3494 */ { MAD_F(0x0678d706) /* 0.404501939 */, 17 }, + /* 3495 */ { MAD_F(0x067978e4) /* 0.404656307 */, 17 }, + /* 3496 */ { MAD_F(0x067a1ac6) /* 0.404810690 */, 17 }, + /* 3497 */ { MAD_F(0x067abcac) /* 0.404965087 */, 17 }, + /* 3498 */ { MAD_F(0x067b5e95) /* 0.405119499 */, 17 }, + /* 3499 */ { MAD_F(0x067c0083) /* 0.405273926 */, 17 }, + /* 3500 */ { MAD_F(0x067ca275) /* 0.405428368 */, 17 }, + /* 3501 */ { MAD_F(0x067d446a) /* 0.405582824 */, 17 }, + /* 3502 */ { MAD_F(0x067de664) /* 0.405737295 */, 17 }, + /* 3503 */ { MAD_F(0x067e8861) /* 0.405891781 */, 17 }, + + /* 3504 */ { MAD_F(0x067f2a62) /* 0.406046281 */, 17 }, + /* 3505 */ { MAD_F(0x067fcc68) /* 0.406200796 */, 17 }, + /* 3506 */ { MAD_F(0x06806e71) /* 0.406355326 */, 17 }, + /* 3507 */ { MAD_F(0x0681107e) /* 0.406509870 */, 17 }, + /* 3508 */ { MAD_F(0x0681b28f) /* 0.406664429 */, 17 }, + /* 3509 */ { MAD_F(0x068254a4) /* 0.406819003 */, 17 }, + /* 3510 */ { MAD_F(0x0682f6bd) /* 0.406973592 */, 17 }, + /* 3511 */ { MAD_F(0x068398da) /* 0.407128195 */, 17 }, + /* 3512 */ { MAD_F(0x06843afb) /* 0.407282813 */, 17 }, + /* 3513 */ { MAD_F(0x0684dd20) /* 0.407437445 */, 17 }, + /* 3514 */ { MAD_F(0x06857f49) /* 0.407592093 */, 17 }, + /* 3515 */ { MAD_F(0x06862176) /* 0.407746754 */, 17 }, + /* 3516 */ { MAD_F(0x0686c3a6) /* 0.407901431 */, 17 }, + /* 3517 */ { MAD_F(0x068765db) /* 0.408056122 */, 17 }, + /* 3518 */ { MAD_F(0x06880814) /* 0.408210828 */, 17 }, + /* 3519 */ { MAD_F(0x0688aa50) /* 0.408365549 */, 17 }, + + /* 3520 */ { MAD_F(0x06894c90) /* 0.408520284 */, 17 }, + /* 3521 */ { MAD_F(0x0689eed5) /* 0.408675034 */, 17 }, + /* 3522 */ { MAD_F(0x068a911d) /* 0.408829798 */, 17 }, + /* 3523 */ { MAD_F(0x068b3369) /* 0.408984577 */, 17 }, + /* 3524 */ { MAD_F(0x068bd5b9) /* 0.409139371 */, 17 }, + /* 3525 */ { MAD_F(0x068c780e) /* 0.409294180 */, 17 }, + /* 3526 */ { MAD_F(0x068d1a66) /* 0.409449003 */, 17 }, + /* 3527 */ { MAD_F(0x068dbcc1) /* 0.409603840 */, 17 }, + /* 3528 */ { MAD_F(0x068e5f21) /* 0.409758693 */, 17 }, + /* 3529 */ { MAD_F(0x068f0185) /* 0.409913560 */, 17 }, + /* 3530 */ { MAD_F(0x068fa3ed) /* 0.410068441 */, 17 }, + /* 3531 */ { MAD_F(0x06904658) /* 0.410223338 */, 17 }, + /* 3532 */ { MAD_F(0x0690e8c8) /* 0.410378249 */, 17 }, + /* 3533 */ { MAD_F(0x06918b3c) /* 0.410533174 */, 17 }, + /* 3534 */ { MAD_F(0x06922db3) /* 0.410688114 */, 17 }, + /* 3535 */ { MAD_F(0x0692d02e) /* 0.410843069 */, 17 }, + + /* 3536 */ { MAD_F(0x069372ae) /* 0.410998038 */, 17 }, + /* 3537 */ { MAD_F(0x06941531) /* 0.411153022 */, 17 }, + /* 3538 */ { MAD_F(0x0694b7b8) /* 0.411308021 */, 17 }, + /* 3539 */ { MAD_F(0x06955a43) /* 0.411463034 */, 17 }, + /* 3540 */ { MAD_F(0x0695fcd2) /* 0.411618062 */, 17 }, + /* 3541 */ { MAD_F(0x06969f65) /* 0.411773104 */, 17 }, + /* 3542 */ { MAD_F(0x069741fb) /* 0.411928161 */, 17 }, + /* 3543 */ { MAD_F(0x0697e496) /* 0.412083232 */, 17 }, + /* 3544 */ { MAD_F(0x06988735) /* 0.412238319 */, 17 }, + /* 3545 */ { MAD_F(0x069929d7) /* 0.412393419 */, 17 }, + /* 3546 */ { MAD_F(0x0699cc7e) /* 0.412548535 */, 17 }, + /* 3547 */ { MAD_F(0x069a6f28) /* 0.412703664 */, 17 }, + /* 3548 */ { MAD_F(0x069b11d6) /* 0.412858809 */, 17 }, + /* 3549 */ { MAD_F(0x069bb489) /* 0.413013968 */, 17 }, + /* 3550 */ { MAD_F(0x069c573f) /* 0.413169142 */, 17 }, + /* 3551 */ { MAD_F(0x069cf9f9) /* 0.413324330 */, 17 }, + + /* 3552 */ { MAD_F(0x069d9cb7) /* 0.413479532 */, 17 }, + /* 3553 */ { MAD_F(0x069e3f78) /* 0.413634750 */, 17 }, + /* 3554 */ { MAD_F(0x069ee23e) /* 0.413789982 */, 17 }, + /* 3555 */ { MAD_F(0x069f8508) /* 0.413945228 */, 17 }, + /* 3556 */ { MAD_F(0x06a027d5) /* 0.414100489 */, 17 }, + /* 3557 */ { MAD_F(0x06a0caa7) /* 0.414255765 */, 17 }, + /* 3558 */ { MAD_F(0x06a16d7c) /* 0.414411055 */, 17 }, + /* 3559 */ { MAD_F(0x06a21055) /* 0.414566359 */, 17 }, + /* 3560 */ { MAD_F(0x06a2b333) /* 0.414721679 */, 17 }, + /* 3561 */ { MAD_F(0x06a35614) /* 0.414877012 */, 17 }, + /* 3562 */ { MAD_F(0x06a3f8f9) /* 0.415032361 */, 17 }, + /* 3563 */ { MAD_F(0x06a49be2) /* 0.415187723 */, 17 }, + /* 3564 */ { MAD_F(0x06a53ece) /* 0.415343101 */, 17 }, + /* 3565 */ { MAD_F(0x06a5e1bf) /* 0.415498493 */, 17 }, + /* 3566 */ { MAD_F(0x06a684b4) /* 0.415653899 */, 17 }, + /* 3567 */ { MAD_F(0x06a727ac) /* 0.415809320 */, 17 }, + + /* 3568 */ { MAD_F(0x06a7caa9) /* 0.415964756 */, 17 }, + /* 3569 */ { MAD_F(0x06a86da9) /* 0.416120206 */, 17 }, + /* 3570 */ { MAD_F(0x06a910ad) /* 0.416275670 */, 17 }, + /* 3571 */ { MAD_F(0x06a9b3b5) /* 0.416431149 */, 17 }, + /* 3572 */ { MAD_F(0x06aa56c1) /* 0.416586643 */, 17 }, + /* 3573 */ { MAD_F(0x06aaf9d1) /* 0.416742151 */, 17 }, + /* 3574 */ { MAD_F(0x06ab9ce5) /* 0.416897673 */, 17 }, + /* 3575 */ { MAD_F(0x06ac3ffc) /* 0.417053210 */, 17 }, + /* 3576 */ { MAD_F(0x06ace318) /* 0.417208762 */, 17 }, + /* 3577 */ { MAD_F(0x06ad8637) /* 0.417364328 */, 17 }, + /* 3578 */ { MAD_F(0x06ae295b) /* 0.417519909 */, 17 }, + /* 3579 */ { MAD_F(0x06aecc82) /* 0.417675504 */, 17 }, + /* 3580 */ { MAD_F(0x06af6fad) /* 0.417831113 */, 17 }, + /* 3581 */ { MAD_F(0x06b012dc) /* 0.417986737 */, 17 }, + /* 3582 */ { MAD_F(0x06b0b60f) /* 0.418142376 */, 17 }, + /* 3583 */ { MAD_F(0x06b15946) /* 0.418298029 */, 17 }, + + /* 3584 */ { MAD_F(0x06b1fc81) /* 0.418453696 */, 17 }, + /* 3585 */ { MAD_F(0x06b29fbf) /* 0.418609378 */, 17 }, + /* 3586 */ { MAD_F(0x06b34302) /* 0.418765075 */, 17 }, + /* 3587 */ { MAD_F(0x06b3e648) /* 0.418920786 */, 17 }, + /* 3588 */ { MAD_F(0x06b48992) /* 0.419076511 */, 17 }, + /* 3589 */ { MAD_F(0x06b52ce0) /* 0.419232251 */, 17 }, + /* 3590 */ { MAD_F(0x06b5d032) /* 0.419388005 */, 17 }, + /* 3591 */ { MAD_F(0x06b67388) /* 0.419543774 */, 17 }, + /* 3592 */ { MAD_F(0x06b716e2) /* 0.419699557 */, 17 }, + /* 3593 */ { MAD_F(0x06b7ba3f) /* 0.419855355 */, 17 }, + /* 3594 */ { MAD_F(0x06b85da1) /* 0.420011167 */, 17 }, + /* 3595 */ { MAD_F(0x06b90106) /* 0.420166994 */, 17 }, + /* 3596 */ { MAD_F(0x06b9a470) /* 0.420322835 */, 17 }, + /* 3597 */ { MAD_F(0x06ba47dd) /* 0.420478690 */, 17 }, + /* 3598 */ { MAD_F(0x06baeb4e) /* 0.420634560 */, 17 }, + /* 3599 */ { MAD_F(0x06bb8ec3) /* 0.420790445 */, 17 }, + + /* 3600 */ { MAD_F(0x06bc323b) /* 0.420946343 */, 17 }, + /* 3601 */ { MAD_F(0x06bcd5b8) /* 0.421102257 */, 17 }, + /* 3602 */ { MAD_F(0x06bd7939) /* 0.421258184 */, 17 }, + /* 3603 */ { MAD_F(0x06be1cbd) /* 0.421414127 */, 17 }, + /* 3604 */ { MAD_F(0x06bec045) /* 0.421570083 */, 17 }, + /* 3605 */ { MAD_F(0x06bf63d1) /* 0.421726054 */, 17 }, + /* 3606 */ { MAD_F(0x06c00761) /* 0.421882040 */, 17 }, + /* 3607 */ { MAD_F(0x06c0aaf5) /* 0.422038039 */, 17 }, + /* 3608 */ { MAD_F(0x06c14e8d) /* 0.422194054 */, 17 }, + /* 3609 */ { MAD_F(0x06c1f229) /* 0.422350082 */, 17 }, + /* 3610 */ { MAD_F(0x06c295c8) /* 0.422506125 */, 17 }, + /* 3611 */ { MAD_F(0x06c3396c) /* 0.422662183 */, 17 }, + /* 3612 */ { MAD_F(0x06c3dd13) /* 0.422818255 */, 17 }, + /* 3613 */ { MAD_F(0x06c480be) /* 0.422974341 */, 17 }, + /* 3614 */ { MAD_F(0x06c5246d) /* 0.423130442 */, 17 }, + /* 3615 */ { MAD_F(0x06c5c820) /* 0.423286557 */, 17 }, + + /* 3616 */ { MAD_F(0x06c66bd6) /* 0.423442686 */, 17 }, + /* 3617 */ { MAD_F(0x06c70f91) /* 0.423598830 */, 17 }, + /* 3618 */ { MAD_F(0x06c7b34f) /* 0.423754988 */, 17 }, + /* 3619 */ { MAD_F(0x06c85712) /* 0.423911161 */, 17 }, + /* 3620 */ { MAD_F(0x06c8fad8) /* 0.424067348 */, 17 }, + /* 3621 */ { MAD_F(0x06c99ea2) /* 0.424223550 */, 17 }, + /* 3622 */ { MAD_F(0x06ca4270) /* 0.424379765 */, 17 }, + /* 3623 */ { MAD_F(0x06cae641) /* 0.424535996 */, 17 }, + /* 3624 */ { MAD_F(0x06cb8a17) /* 0.424692240 */, 17 }, + /* 3625 */ { MAD_F(0x06cc2df0) /* 0.424848499 */, 17 }, + /* 3626 */ { MAD_F(0x06ccd1ce) /* 0.425004772 */, 17 }, + /* 3627 */ { MAD_F(0x06cd75af) /* 0.425161060 */, 17 }, + /* 3628 */ { MAD_F(0x06ce1994) /* 0.425317362 */, 17 }, + /* 3629 */ { MAD_F(0x06cebd7d) /* 0.425473678 */, 17 }, + /* 3630 */ { MAD_F(0x06cf6169) /* 0.425630009 */, 17 }, + /* 3631 */ { MAD_F(0x06d0055a) /* 0.425786354 */, 17 }, + + /* 3632 */ { MAD_F(0x06d0a94e) /* 0.425942714 */, 17 }, + /* 3633 */ { MAD_F(0x06d14d47) /* 0.426099088 */, 17 }, + /* 3634 */ { MAD_F(0x06d1f143) /* 0.426255476 */, 17 }, + /* 3635 */ { MAD_F(0x06d29543) /* 0.426411878 */, 17 }, + /* 3636 */ { MAD_F(0x06d33947) /* 0.426568295 */, 17 }, + /* 3637 */ { MAD_F(0x06d3dd4e) /* 0.426724726 */, 17 }, + /* 3638 */ { MAD_F(0x06d4815a) /* 0.426881172 */, 17 }, + /* 3639 */ { MAD_F(0x06d52569) /* 0.427037632 */, 17 }, + /* 3640 */ { MAD_F(0x06d5c97c) /* 0.427194106 */, 17 }, + /* 3641 */ { MAD_F(0x06d66d93) /* 0.427350594 */, 17 }, + /* 3642 */ { MAD_F(0x06d711ae) /* 0.427507097 */, 17 }, + /* 3643 */ { MAD_F(0x06d7b5cd) /* 0.427663614 */, 17 }, + /* 3644 */ { MAD_F(0x06d859f0) /* 0.427820146 */, 17 }, + /* 3645 */ { MAD_F(0x06d8fe16) /* 0.427976692 */, 17 }, + /* 3646 */ { MAD_F(0x06d9a240) /* 0.428133252 */, 17 }, + /* 3647 */ { MAD_F(0x06da466f) /* 0.428289826 */, 17 }, + + /* 3648 */ { MAD_F(0x06daeaa1) /* 0.428446415 */, 17 }, + /* 3649 */ { MAD_F(0x06db8ed6) /* 0.428603018 */, 17 }, + /* 3650 */ { MAD_F(0x06dc3310) /* 0.428759635 */, 17 }, + /* 3651 */ { MAD_F(0x06dcd74d) /* 0.428916267 */, 17 }, + /* 3652 */ { MAD_F(0x06dd7b8f) /* 0.429072913 */, 17 }, + /* 3653 */ { MAD_F(0x06de1fd4) /* 0.429229573 */, 17 }, + /* 3654 */ { MAD_F(0x06dec41d) /* 0.429386248 */, 17 }, + /* 3655 */ { MAD_F(0x06df686a) /* 0.429542937 */, 17 }, + /* 3656 */ { MAD_F(0x06e00cbb) /* 0.429699640 */, 17 }, + /* 3657 */ { MAD_F(0x06e0b10f) /* 0.429856357 */, 17 }, + /* 3658 */ { MAD_F(0x06e15567) /* 0.430013089 */, 17 }, + /* 3659 */ { MAD_F(0x06e1f9c4) /* 0.430169835 */, 17 }, + /* 3660 */ { MAD_F(0x06e29e24) /* 0.430326595 */, 17 }, + /* 3661 */ { MAD_F(0x06e34287) /* 0.430483370 */, 17 }, + /* 3662 */ { MAD_F(0x06e3e6ef) /* 0.430640159 */, 17 }, + /* 3663 */ { MAD_F(0x06e48b5b) /* 0.430796962 */, 17 }, + + /* 3664 */ { MAD_F(0x06e52fca) /* 0.430953779 */, 17 }, + /* 3665 */ { MAD_F(0x06e5d43d) /* 0.431110611 */, 17 }, + /* 3666 */ { MAD_F(0x06e678b4) /* 0.431267457 */, 17 }, + /* 3667 */ { MAD_F(0x06e71d2f) /* 0.431424317 */, 17 }, + /* 3668 */ { MAD_F(0x06e7c1ae) /* 0.431581192 */, 17 }, + /* 3669 */ { MAD_F(0x06e86630) /* 0.431738080 */, 17 }, + /* 3670 */ { MAD_F(0x06e90ab7) /* 0.431894983 */, 17 }, + /* 3671 */ { MAD_F(0x06e9af41) /* 0.432051900 */, 17 }, + /* 3672 */ { MAD_F(0x06ea53cf) /* 0.432208832 */, 17 }, + /* 3673 */ { MAD_F(0x06eaf860) /* 0.432365778 */, 17 }, + /* 3674 */ { MAD_F(0x06eb9cf6) /* 0.432522737 */, 17 }, + /* 3675 */ { MAD_F(0x06ec418f) /* 0.432679712 */, 17 }, + /* 3676 */ { MAD_F(0x06ece62d) /* 0.432836700 */, 17 }, + /* 3677 */ { MAD_F(0x06ed8ace) /* 0.432993703 */, 17 }, + /* 3678 */ { MAD_F(0x06ee2f73) /* 0.433150720 */, 17 }, + /* 3679 */ { MAD_F(0x06eed41b) /* 0.433307751 */, 17 }, + + /* 3680 */ { MAD_F(0x06ef78c8) /* 0.433464796 */, 17 }, + /* 3681 */ { MAD_F(0x06f01d78) /* 0.433621856 */, 17 }, + /* 3682 */ { MAD_F(0x06f0c22c) /* 0.433778929 */, 17 }, + /* 3683 */ { MAD_F(0x06f166e4) /* 0.433936017 */, 17 }, + /* 3684 */ { MAD_F(0x06f20ba0) /* 0.434093120 */, 17 }, + /* 3685 */ { MAD_F(0x06f2b060) /* 0.434250236 */, 17 }, + /* 3686 */ { MAD_F(0x06f35523) /* 0.434407367 */, 17 }, + /* 3687 */ { MAD_F(0x06f3f9eb) /* 0.434564512 */, 17 }, + /* 3688 */ { MAD_F(0x06f49eb6) /* 0.434721671 */, 17 }, + /* 3689 */ { MAD_F(0x06f54385) /* 0.434878844 */, 17 }, + /* 3690 */ { MAD_F(0x06f5e857) /* 0.435036032 */, 17 }, + /* 3691 */ { MAD_F(0x06f68d2e) /* 0.435193233 */, 17 }, + /* 3692 */ { MAD_F(0x06f73208) /* 0.435350449 */, 17 }, + /* 3693 */ { MAD_F(0x06f7d6e6) /* 0.435507679 */, 17 }, + /* 3694 */ { MAD_F(0x06f87bc8) /* 0.435664924 */, 17 }, + /* 3695 */ { MAD_F(0x06f920ae) /* 0.435822182 */, 17 }, + + /* 3696 */ { MAD_F(0x06f9c597) /* 0.435979455 */, 17 }, + /* 3697 */ { MAD_F(0x06fa6a85) /* 0.436136741 */, 17 }, + /* 3698 */ { MAD_F(0x06fb0f76) /* 0.436294042 */, 17 }, + /* 3699 */ { MAD_F(0x06fbb46b) /* 0.436451358 */, 17 }, + /* 3700 */ { MAD_F(0x06fc5964) /* 0.436608687 */, 17 }, + /* 3701 */ { MAD_F(0x06fcfe60) /* 0.436766031 */, 17 }, + /* 3702 */ { MAD_F(0x06fda361) /* 0.436923388 */, 17 }, + /* 3703 */ { MAD_F(0x06fe4865) /* 0.437080760 */, 17 }, + /* 3704 */ { MAD_F(0x06feed6d) /* 0.437238146 */, 17 }, + /* 3705 */ { MAD_F(0x06ff9279) /* 0.437395547 */, 17 }, + /* 3706 */ { MAD_F(0x07003788) /* 0.437552961 */, 17 }, + /* 3707 */ { MAD_F(0x0700dc9c) /* 0.437710389 */, 17 }, + /* 3708 */ { MAD_F(0x070181b3) /* 0.437867832 */, 17 }, + /* 3709 */ { MAD_F(0x070226ce) /* 0.438025289 */, 17 }, + /* 3710 */ { MAD_F(0x0702cbed) /* 0.438182760 */, 17 }, + /* 3711 */ { MAD_F(0x0703710f) /* 0.438340245 */, 17 }, + + /* 3712 */ { MAD_F(0x07041636) /* 0.438497744 */, 17 }, + /* 3713 */ { MAD_F(0x0704bb60) /* 0.438655258 */, 17 }, + /* 3714 */ { MAD_F(0x0705608e) /* 0.438812785 */, 17 }, + /* 3715 */ { MAD_F(0x070605c0) /* 0.438970327 */, 17 }, + /* 3716 */ { MAD_F(0x0706aaf5) /* 0.439127883 */, 17 }, + /* 3717 */ { MAD_F(0x0707502f) /* 0.439285453 */, 17 }, + /* 3718 */ { MAD_F(0x0707f56c) /* 0.439443037 */, 17 }, + /* 3719 */ { MAD_F(0x07089aad) /* 0.439600635 */, 17 }, + /* 3720 */ { MAD_F(0x07093ff2) /* 0.439758248 */, 17 }, + /* 3721 */ { MAD_F(0x0709e53a) /* 0.439915874 */, 17 }, + /* 3722 */ { MAD_F(0x070a8a86) /* 0.440073515 */, 17 }, + /* 3723 */ { MAD_F(0x070b2fd7) /* 0.440231170 */, 17 }, + /* 3724 */ { MAD_F(0x070bd52a) /* 0.440388839 */, 17 }, + /* 3725 */ { MAD_F(0x070c7a82) /* 0.440546522 */, 17 }, + /* 3726 */ { MAD_F(0x070d1fde) /* 0.440704219 */, 17 }, + /* 3727 */ { MAD_F(0x070dc53d) /* 0.440861930 */, 17 }, + + /* 3728 */ { MAD_F(0x070e6aa0) /* 0.441019655 */, 17 }, + /* 3729 */ { MAD_F(0x070f1007) /* 0.441177395 */, 17 }, + /* 3730 */ { MAD_F(0x070fb571) /* 0.441335148 */, 17 }, + /* 3731 */ { MAD_F(0x07105ae0) /* 0.441492916 */, 17 }, + /* 3732 */ { MAD_F(0x07110052) /* 0.441650697 */, 17 }, + /* 3733 */ { MAD_F(0x0711a5c8) /* 0.441808493 */, 17 }, + /* 3734 */ { MAD_F(0x07124b42) /* 0.441966303 */, 17 }, + /* 3735 */ { MAD_F(0x0712f0bf) /* 0.442124127 */, 17 }, + /* 3736 */ { MAD_F(0x07139641) /* 0.442281965 */, 17 }, + /* 3737 */ { MAD_F(0x07143bc6) /* 0.442439817 */, 17 }, + /* 3738 */ { MAD_F(0x0714e14f) /* 0.442597683 */, 17 }, + /* 3739 */ { MAD_F(0x071586db) /* 0.442755564 */, 17 }, + /* 3740 */ { MAD_F(0x07162c6c) /* 0.442913458 */, 17 }, + /* 3741 */ { MAD_F(0x0716d200) /* 0.443071366 */, 17 }, + /* 3742 */ { MAD_F(0x07177798) /* 0.443229289 */, 17 }, + /* 3743 */ { MAD_F(0x07181d34) /* 0.443387226 */, 17 }, + + /* 3744 */ { MAD_F(0x0718c2d3) /* 0.443545176 */, 17 }, + /* 3745 */ { MAD_F(0x07196877) /* 0.443703141 */, 17 }, + /* 3746 */ { MAD_F(0x071a0e1e) /* 0.443861120 */, 17 }, + /* 3747 */ { MAD_F(0x071ab3c9) /* 0.444019113 */, 17 }, + /* 3748 */ { MAD_F(0x071b5977) /* 0.444177119 */, 17 }, + /* 3749 */ { MAD_F(0x071bff2a) /* 0.444335140 */, 17 }, + /* 3750 */ { MAD_F(0x071ca4e0) /* 0.444493175 */, 17 }, + /* 3751 */ { MAD_F(0x071d4a9a) /* 0.444651224 */, 17 }, + /* 3752 */ { MAD_F(0x071df058) /* 0.444809288 */, 17 }, + /* 3753 */ { MAD_F(0x071e9619) /* 0.444967365 */, 17 }, + /* 3754 */ { MAD_F(0x071f3bde) /* 0.445125456 */, 17 }, + /* 3755 */ { MAD_F(0x071fe1a8) /* 0.445283561 */, 17 }, + /* 3756 */ { MAD_F(0x07208774) /* 0.445441680 */, 17 }, + /* 3757 */ { MAD_F(0x07212d45) /* 0.445599814 */, 17 }, + /* 3758 */ { MAD_F(0x0721d319) /* 0.445757961 */, 17 }, + /* 3759 */ { MAD_F(0x072278f1) /* 0.445916122 */, 17 }, + + /* 3760 */ { MAD_F(0x07231ecd) /* 0.446074298 */, 17 }, + /* 3761 */ { MAD_F(0x0723c4ad) /* 0.446232487 */, 17 }, + /* 3762 */ { MAD_F(0x07246a90) /* 0.446390690 */, 17 }, + /* 3763 */ { MAD_F(0x07251077) /* 0.446548908 */, 17 }, + /* 3764 */ { MAD_F(0x0725b662) /* 0.446707139 */, 17 }, + /* 3765 */ { MAD_F(0x07265c51) /* 0.446865385 */, 17 }, + /* 3766 */ { MAD_F(0x07270244) /* 0.447023644 */, 17 }, + /* 3767 */ { MAD_F(0x0727a83a) /* 0.447181918 */, 17 }, + /* 3768 */ { MAD_F(0x07284e34) /* 0.447340205 */, 17 }, + /* 3769 */ { MAD_F(0x0728f431) /* 0.447498507 */, 17 }, + /* 3770 */ { MAD_F(0x07299a33) /* 0.447656822 */, 17 }, + /* 3771 */ { MAD_F(0x072a4038) /* 0.447815152 */, 17 }, + /* 3772 */ { MAD_F(0x072ae641) /* 0.447973495 */, 17 }, + /* 3773 */ { MAD_F(0x072b8c4e) /* 0.448131853 */, 17 }, + /* 3774 */ { MAD_F(0x072c325e) /* 0.448290224 */, 17 }, + /* 3775 */ { MAD_F(0x072cd873) /* 0.448448609 */, 17 }, + + /* 3776 */ { MAD_F(0x072d7e8b) /* 0.448607009 */, 17 }, + /* 3777 */ { MAD_F(0x072e24a7) /* 0.448765422 */, 17 }, + /* 3778 */ { MAD_F(0x072ecac6) /* 0.448923850 */, 17 }, + /* 3779 */ { MAD_F(0x072f70e9) /* 0.449082291 */, 17 }, + /* 3780 */ { MAD_F(0x07301710) /* 0.449240746 */, 17 }, + /* 3781 */ { MAD_F(0x0730bd3b) /* 0.449399216 */, 17 }, + /* 3782 */ { MAD_F(0x0731636a) /* 0.449557699 */, 17 }, + /* 3783 */ { MAD_F(0x0732099c) /* 0.449716196 */, 17 }, + /* 3784 */ { MAD_F(0x0732afd2) /* 0.449874708 */, 17 }, + /* 3785 */ { MAD_F(0x0733560c) /* 0.450033233 */, 17 }, + /* 3786 */ { MAD_F(0x0733fc49) /* 0.450191772 */, 17 }, + /* 3787 */ { MAD_F(0x0734a28b) /* 0.450350325 */, 17 }, + /* 3788 */ { MAD_F(0x073548d0) /* 0.450508892 */, 17 }, + /* 3789 */ { MAD_F(0x0735ef18) /* 0.450667473 */, 17 }, + /* 3790 */ { MAD_F(0x07369565) /* 0.450826068 */, 17 }, + /* 3791 */ { MAD_F(0x07373bb5) /* 0.450984677 */, 17 }, + + /* 3792 */ { MAD_F(0x0737e209) /* 0.451143300 */, 17 }, + /* 3793 */ { MAD_F(0x07388861) /* 0.451301937 */, 17 }, + /* 3794 */ { MAD_F(0x07392ebc) /* 0.451460588 */, 17 }, + /* 3795 */ { MAD_F(0x0739d51c) /* 0.451619252 */, 17 }, + /* 3796 */ { MAD_F(0x073a7b7f) /* 0.451777931 */, 17 }, + /* 3797 */ { MAD_F(0x073b21e5) /* 0.451936623 */, 17 }, + /* 3798 */ { MAD_F(0x073bc850) /* 0.452095330 */, 17 }, + /* 3799 */ { MAD_F(0x073c6ebe) /* 0.452254050 */, 17 }, + /* 3800 */ { MAD_F(0x073d1530) /* 0.452412785 */, 17 }, + /* 3801 */ { MAD_F(0x073dbba6) /* 0.452571533 */, 17 }, + /* 3802 */ { MAD_F(0x073e621f) /* 0.452730295 */, 17 }, + /* 3803 */ { MAD_F(0x073f089c) /* 0.452889071 */, 17 }, + /* 3804 */ { MAD_F(0x073faf1d) /* 0.453047861 */, 17 }, + /* 3805 */ { MAD_F(0x074055a2) /* 0.453206665 */, 17 }, + /* 3806 */ { MAD_F(0x0740fc2a) /* 0.453365483 */, 17 }, + /* 3807 */ { MAD_F(0x0741a2b6) /* 0.453524315 */, 17 }, + + /* 3808 */ { MAD_F(0x07424946) /* 0.453683161 */, 17 }, + /* 3809 */ { MAD_F(0x0742efd9) /* 0.453842020 */, 17 }, + /* 3810 */ { MAD_F(0x07439671) /* 0.454000894 */, 17 }, + /* 3811 */ { MAD_F(0x07443d0c) /* 0.454159781 */, 17 }, + /* 3812 */ { MAD_F(0x0744e3aa) /* 0.454318683 */, 17 }, + /* 3813 */ { MAD_F(0x07458a4d) /* 0.454477598 */, 17 }, + /* 3814 */ { MAD_F(0x074630f3) /* 0.454636527 */, 17 }, + /* 3815 */ { MAD_F(0x0746d79d) /* 0.454795470 */, 17 }, + /* 3816 */ { MAD_F(0x07477e4b) /* 0.454954427 */, 17 }, + /* 3817 */ { MAD_F(0x074824fc) /* 0.455113397 */, 17 }, + /* 3818 */ { MAD_F(0x0748cbb1) /* 0.455272382 */, 17 }, + /* 3819 */ { MAD_F(0x0749726a) /* 0.455431381 */, 17 }, + /* 3820 */ { MAD_F(0x074a1927) /* 0.455590393 */, 17 }, + /* 3821 */ { MAD_F(0x074abfe7) /* 0.455749419 */, 17 }, + /* 3822 */ { MAD_F(0x074b66ab) /* 0.455908459 */, 17 }, + /* 3823 */ { MAD_F(0x074c0d73) /* 0.456067513 */, 17 }, + + /* 3824 */ { MAD_F(0x074cb43e) /* 0.456226581 */, 17 }, + /* 3825 */ { MAD_F(0x074d5b0d) /* 0.456385663 */, 17 }, + /* 3826 */ { MAD_F(0x074e01e0) /* 0.456544759 */, 17 }, + /* 3827 */ { MAD_F(0x074ea8b7) /* 0.456703868 */, 17 }, + /* 3828 */ { MAD_F(0x074f4f91) /* 0.456862992 */, 17 }, + /* 3829 */ { MAD_F(0x074ff66f) /* 0.457022129 */, 17 }, + /* 3830 */ { MAD_F(0x07509d51) /* 0.457181280 */, 17 }, + /* 3831 */ { MAD_F(0x07514437) /* 0.457340445 */, 17 }, + /* 3832 */ { MAD_F(0x0751eb20) /* 0.457499623 */, 17 }, + /* 3833 */ { MAD_F(0x0752920d) /* 0.457658816 */, 17 }, + /* 3834 */ { MAD_F(0x075338fd) /* 0.457818022 */, 17 }, + /* 3835 */ { MAD_F(0x0753dff2) /* 0.457977243 */, 17 }, + /* 3836 */ { MAD_F(0x075486ea) /* 0.458136477 */, 17 }, + /* 3837 */ { MAD_F(0x07552de6) /* 0.458295725 */, 17 }, + /* 3838 */ { MAD_F(0x0755d4e5) /* 0.458454987 */, 17 }, + /* 3839 */ { MAD_F(0x07567be8) /* 0.458614262 */, 17 }, + + /* 3840 */ { MAD_F(0x075722ef) /* 0.458773552 */, 17 }, + /* 3841 */ { MAD_F(0x0757c9fa) /* 0.458932855 */, 17 }, + /* 3842 */ { MAD_F(0x07587108) /* 0.459092172 */, 17 }, + /* 3843 */ { MAD_F(0x0759181a) /* 0.459251503 */, 17 }, + /* 3844 */ { MAD_F(0x0759bf30) /* 0.459410848 */, 17 }, + /* 3845 */ { MAD_F(0x075a664a) /* 0.459570206 */, 17 }, + /* 3846 */ { MAD_F(0x075b0d67) /* 0.459729579 */, 17 }, + /* 3847 */ { MAD_F(0x075bb488) /* 0.459888965 */, 17 }, + /* 3848 */ { MAD_F(0x075c5bac) /* 0.460048365 */, 17 }, + /* 3849 */ { MAD_F(0x075d02d5) /* 0.460207779 */, 17 }, + /* 3850 */ { MAD_F(0x075daa01) /* 0.460367206 */, 17 }, + /* 3851 */ { MAD_F(0x075e5130) /* 0.460526648 */, 17 }, + /* 3852 */ { MAD_F(0x075ef864) /* 0.460686103 */, 17 }, + /* 3853 */ { MAD_F(0x075f9f9b) /* 0.460845572 */, 17 }, + /* 3854 */ { MAD_F(0x076046d6) /* 0.461005055 */, 17 }, + /* 3855 */ { MAD_F(0x0760ee14) /* 0.461164552 */, 17 }, + + /* 3856 */ { MAD_F(0x07619557) /* 0.461324062 */, 17 }, + /* 3857 */ { MAD_F(0x07623c9d) /* 0.461483586 */, 17 }, + /* 3858 */ { MAD_F(0x0762e3e6) /* 0.461643124 */, 17 }, + /* 3859 */ { MAD_F(0x07638b34) /* 0.461802676 */, 17 }, + /* 3860 */ { MAD_F(0x07643285) /* 0.461962242 */, 17 }, + /* 3861 */ { MAD_F(0x0764d9d9) /* 0.462121821 */, 17 }, + /* 3862 */ { MAD_F(0x07658132) /* 0.462281414 */, 17 }, + /* 3863 */ { MAD_F(0x0766288e) /* 0.462441021 */, 17 }, + /* 3864 */ { MAD_F(0x0766cfee) /* 0.462600642 */, 17 }, + /* 3865 */ { MAD_F(0x07677751) /* 0.462760276 */, 17 }, + /* 3866 */ { MAD_F(0x07681eb9) /* 0.462919924 */, 17 }, + /* 3867 */ { MAD_F(0x0768c624) /* 0.463079586 */, 17 }, + /* 3868 */ { MAD_F(0x07696d92) /* 0.463239262 */, 17 }, + /* 3869 */ { MAD_F(0x076a1505) /* 0.463398951 */, 17 }, + /* 3870 */ { MAD_F(0x076abc7b) /* 0.463558655 */, 17 }, + /* 3871 */ { MAD_F(0x076b63f4) /* 0.463718372 */, 17 }, + + /* 3872 */ { MAD_F(0x076c0b72) /* 0.463878102 */, 17 }, + /* 3873 */ { MAD_F(0x076cb2f3) /* 0.464037847 */, 17 }, + /* 3874 */ { MAD_F(0x076d5a78) /* 0.464197605 */, 17 }, + /* 3875 */ { MAD_F(0x076e0200) /* 0.464357377 */, 17 }, + /* 3876 */ { MAD_F(0x076ea98c) /* 0.464517163 */, 17 }, + /* 3877 */ { MAD_F(0x076f511c) /* 0.464676962 */, 17 }, + /* 3878 */ { MAD_F(0x076ff8b0) /* 0.464836776 */, 17 }, + /* 3879 */ { MAD_F(0x0770a047) /* 0.464996603 */, 17 }, + /* 3880 */ { MAD_F(0x077147e2) /* 0.465156443 */, 17 }, + /* 3881 */ { MAD_F(0x0771ef80) /* 0.465316298 */, 17 }, + /* 3882 */ { MAD_F(0x07729723) /* 0.465476166 */, 17 }, + /* 3883 */ { MAD_F(0x07733ec9) /* 0.465636048 */, 17 }, + /* 3884 */ { MAD_F(0x0773e672) /* 0.465795943 */, 17 }, + /* 3885 */ { MAD_F(0x07748e20) /* 0.465955853 */, 17 }, + /* 3886 */ { MAD_F(0x077535d1) /* 0.466115776 */, 17 }, + /* 3887 */ { MAD_F(0x0775dd85) /* 0.466275713 */, 17 }, + + /* 3888 */ { MAD_F(0x0776853e) /* 0.466435663 */, 17 }, + /* 3889 */ { MAD_F(0x07772cfa) /* 0.466595627 */, 17 }, + /* 3890 */ { MAD_F(0x0777d4ba) /* 0.466755605 */, 17 }, + /* 3891 */ { MAD_F(0x07787c7d) /* 0.466915597 */, 17 }, + /* 3892 */ { MAD_F(0x07792444) /* 0.467075602 */, 17 }, + /* 3893 */ { MAD_F(0x0779cc0f) /* 0.467235621 */, 17 }, + /* 3894 */ { MAD_F(0x077a73dd) /* 0.467395654 */, 17 }, + /* 3895 */ { MAD_F(0x077b1baf) /* 0.467555701 */, 17 }, + /* 3896 */ { MAD_F(0x077bc385) /* 0.467715761 */, 17 }, + /* 3897 */ { MAD_F(0x077c6b5f) /* 0.467875835 */, 17 }, + /* 3898 */ { MAD_F(0x077d133c) /* 0.468035922 */, 17 }, + /* 3899 */ { MAD_F(0x077dbb1d) /* 0.468196023 */, 17 }, + /* 3900 */ { MAD_F(0x077e6301) /* 0.468356138 */, 17 }, + /* 3901 */ { MAD_F(0x077f0ae9) /* 0.468516267 */, 17 }, + /* 3902 */ { MAD_F(0x077fb2d5) /* 0.468676409 */, 17 }, + /* 3903 */ { MAD_F(0x07805ac5) /* 0.468836565 */, 17 }, + + /* 3904 */ { MAD_F(0x078102b8) /* 0.468996735 */, 17 }, + /* 3905 */ { MAD_F(0x0781aaaf) /* 0.469156918 */, 17 }, + /* 3906 */ { MAD_F(0x078252aa) /* 0.469317115 */, 17 }, + /* 3907 */ { MAD_F(0x0782faa8) /* 0.469477326 */, 17 }, + /* 3908 */ { MAD_F(0x0783a2aa) /* 0.469637550 */, 17 }, + /* 3909 */ { MAD_F(0x07844aaf) /* 0.469797788 */, 17 }, + /* 3910 */ { MAD_F(0x0784f2b8) /* 0.469958040 */, 17 }, + /* 3911 */ { MAD_F(0x07859ac5) /* 0.470118305 */, 17 }, + /* 3912 */ { MAD_F(0x078642d6) /* 0.470278584 */, 17 }, + /* 3913 */ { MAD_F(0x0786eaea) /* 0.470438877 */, 17 }, + /* 3914 */ { MAD_F(0x07879302) /* 0.470599183 */, 17 }, + /* 3915 */ { MAD_F(0x07883b1e) /* 0.470759503 */, 17 }, + /* 3916 */ { MAD_F(0x0788e33d) /* 0.470919836 */, 17 }, + /* 3917 */ { MAD_F(0x07898b60) /* 0.471080184 */, 17 }, + /* 3918 */ { MAD_F(0x078a3386) /* 0.471240545 */, 17 }, + /* 3919 */ { MAD_F(0x078adbb0) /* 0.471400919 */, 17 }, + + /* 3920 */ { MAD_F(0x078b83de) /* 0.471561307 */, 17 }, + /* 3921 */ { MAD_F(0x078c2c10) /* 0.471721709 */, 17 }, + /* 3922 */ { MAD_F(0x078cd445) /* 0.471882125 */, 17 }, + /* 3923 */ { MAD_F(0x078d7c7e) /* 0.472042554 */, 17 }, + /* 3924 */ { MAD_F(0x078e24ba) /* 0.472202996 */, 17 }, + /* 3925 */ { MAD_F(0x078eccfb) /* 0.472363453 */, 17 }, + /* 3926 */ { MAD_F(0x078f753e) /* 0.472523923 */, 17 }, + /* 3927 */ { MAD_F(0x07901d86) /* 0.472684406 */, 17 }, + /* 3928 */ { MAD_F(0x0790c5d1) /* 0.472844904 */, 17 }, + /* 3929 */ { MAD_F(0x07916e20) /* 0.473005414 */, 17 }, + /* 3930 */ { MAD_F(0x07921672) /* 0.473165939 */, 17 }, + /* 3931 */ { MAD_F(0x0792bec8) /* 0.473326477 */, 17 }, + /* 3932 */ { MAD_F(0x07936722) /* 0.473487029 */, 17 }, + /* 3933 */ { MAD_F(0x07940f80) /* 0.473647594 */, 17 }, + /* 3934 */ { MAD_F(0x0794b7e1) /* 0.473808173 */, 17 }, + /* 3935 */ { MAD_F(0x07956045) /* 0.473968765 */, 17 }, + + /* 3936 */ { MAD_F(0x079608ae) /* 0.474129372 */, 17 }, + /* 3937 */ { MAD_F(0x0796b11a) /* 0.474289991 */, 17 }, + /* 3938 */ { MAD_F(0x0797598a) /* 0.474450625 */, 17 }, + /* 3939 */ { MAD_F(0x079801fd) /* 0.474611272 */, 17 }, + /* 3940 */ { MAD_F(0x0798aa74) /* 0.474771932 */, 17 }, + /* 3941 */ { MAD_F(0x079952ee) /* 0.474932606 */, 17 }, + /* 3942 */ { MAD_F(0x0799fb6d) /* 0.475093294 */, 17 }, + /* 3943 */ { MAD_F(0x079aa3ef) /* 0.475253995 */, 17 }, + /* 3944 */ { MAD_F(0x079b4c74) /* 0.475414710 */, 17 }, + /* 3945 */ { MAD_F(0x079bf4fd) /* 0.475575439 */, 17 }, + /* 3946 */ { MAD_F(0x079c9d8a) /* 0.475736181 */, 17 }, + /* 3947 */ { MAD_F(0x079d461b) /* 0.475896936 */, 17 }, + /* 3948 */ { MAD_F(0x079deeaf) /* 0.476057705 */, 17 }, + /* 3949 */ { MAD_F(0x079e9747) /* 0.476218488 */, 17 }, + /* 3950 */ { MAD_F(0x079f3fe2) /* 0.476379285 */, 17 }, + /* 3951 */ { MAD_F(0x079fe881) /* 0.476540095 */, 17 }, + + /* 3952 */ { MAD_F(0x07a09124) /* 0.476700918 */, 17 }, + /* 3953 */ { MAD_F(0x07a139ca) /* 0.476861755 */, 17 }, + /* 3954 */ { MAD_F(0x07a1e274) /* 0.477022606 */, 17 }, + /* 3955 */ { MAD_F(0x07a28b22) /* 0.477183470 */, 17 }, + /* 3956 */ { MAD_F(0x07a333d3) /* 0.477344348 */, 17 }, + /* 3957 */ { MAD_F(0x07a3dc88) /* 0.477505239 */, 17 }, + /* 3958 */ { MAD_F(0x07a48541) /* 0.477666144 */, 17 }, + /* 3959 */ { MAD_F(0x07a52dfd) /* 0.477827062 */, 17 }, + /* 3960 */ { MAD_F(0x07a5d6bd) /* 0.477987994 */, 17 }, + /* 3961 */ { MAD_F(0x07a67f80) /* 0.478148940 */, 17 }, + /* 3962 */ { MAD_F(0x07a72847) /* 0.478309899 */, 17 }, + /* 3963 */ { MAD_F(0x07a7d112) /* 0.478470871 */, 17 }, + /* 3964 */ { MAD_F(0x07a879e1) /* 0.478631857 */, 17 }, + /* 3965 */ { MAD_F(0x07a922b3) /* 0.478792857 */, 17 }, + /* 3966 */ { MAD_F(0x07a9cb88) /* 0.478953870 */, 17 }, + /* 3967 */ { MAD_F(0x07aa7462) /* 0.479114897 */, 17 }, + + /* 3968 */ { MAD_F(0x07ab1d3e) /* 0.479275937 */, 17 }, + /* 3969 */ { MAD_F(0x07abc61f) /* 0.479436991 */, 17 }, + /* 3970 */ { MAD_F(0x07ac6f03) /* 0.479598058 */, 17 }, + /* 3971 */ { MAD_F(0x07ad17eb) /* 0.479759139 */, 17 }, + /* 3972 */ { MAD_F(0x07adc0d6) /* 0.479920233 */, 17 }, + /* 3973 */ { MAD_F(0x07ae69c6) /* 0.480081341 */, 17 }, + /* 3974 */ { MAD_F(0x07af12b8) /* 0.480242463 */, 17 }, + /* 3975 */ { MAD_F(0x07afbbaf) /* 0.480403598 */, 17 }, + /* 3976 */ { MAD_F(0x07b064a8) /* 0.480564746 */, 17 }, + /* 3977 */ { MAD_F(0x07b10da6) /* 0.480725908 */, 17 }, + /* 3978 */ { MAD_F(0x07b1b6a7) /* 0.480887083 */, 17 }, + /* 3979 */ { MAD_F(0x07b25fac) /* 0.481048272 */, 17 }, + /* 3980 */ { MAD_F(0x07b308b5) /* 0.481209475 */, 17 }, + /* 3981 */ { MAD_F(0x07b3b1c1) /* 0.481370691 */, 17 }, + /* 3982 */ { MAD_F(0x07b45ad0) /* 0.481531920 */, 17 }, + /* 3983 */ { MAD_F(0x07b503e4) /* 0.481693163 */, 17 }, + + /* 3984 */ { MAD_F(0x07b5acfb) /* 0.481854420 */, 17 }, + /* 3985 */ { MAD_F(0x07b65615) /* 0.482015690 */, 17 }, + /* 3986 */ { MAD_F(0x07b6ff33) /* 0.482176973 */, 17 }, + /* 3987 */ { MAD_F(0x07b7a855) /* 0.482338270 */, 17 }, + /* 3988 */ { MAD_F(0x07b8517b) /* 0.482499580 */, 17 }, + /* 3989 */ { MAD_F(0x07b8faa4) /* 0.482660904 */, 17 }, + /* 3990 */ { MAD_F(0x07b9a3d0) /* 0.482822242 */, 17 }, + /* 3991 */ { MAD_F(0x07ba4d01) /* 0.482983592 */, 17 }, + /* 3992 */ { MAD_F(0x07baf635) /* 0.483144957 */, 17 }, + /* 3993 */ { MAD_F(0x07bb9f6c) /* 0.483306335 */, 17 }, + /* 3994 */ { MAD_F(0x07bc48a7) /* 0.483467726 */, 17 }, + /* 3995 */ { MAD_F(0x07bcf1e6) /* 0.483629131 */, 17 }, + /* 3996 */ { MAD_F(0x07bd9b28) /* 0.483790549 */, 17 }, + /* 3997 */ { MAD_F(0x07be446e) /* 0.483951980 */, 17 }, + /* 3998 */ { MAD_F(0x07beedb8) /* 0.484113426 */, 17 }, + /* 3999 */ { MAD_F(0x07bf9705) /* 0.484274884 */, 17 }, + + /* 4000 */ { MAD_F(0x07c04056) /* 0.484436356 */, 17 }, + /* 4001 */ { MAD_F(0x07c0e9aa) /* 0.484597842 */, 17 }, + /* 4002 */ { MAD_F(0x07c19302) /* 0.484759341 */, 17 }, + /* 4003 */ { MAD_F(0x07c23c5e) /* 0.484920853 */, 17 }, + /* 4004 */ { MAD_F(0x07c2e5bd) /* 0.485082379 */, 17 }, + /* 4005 */ { MAD_F(0x07c38f20) /* 0.485243918 */, 17 }, + /* 4006 */ { MAD_F(0x07c43887) /* 0.485405471 */, 17 }, + /* 4007 */ { MAD_F(0x07c4e1f1) /* 0.485567037 */, 17 }, + /* 4008 */ { MAD_F(0x07c58b5f) /* 0.485728617 */, 17 }, + /* 4009 */ { MAD_F(0x07c634d0) /* 0.485890210 */, 17 }, + /* 4010 */ { MAD_F(0x07c6de45) /* 0.486051817 */, 17 }, + /* 4011 */ { MAD_F(0x07c787bd) /* 0.486213436 */, 17 }, + /* 4012 */ { MAD_F(0x07c83139) /* 0.486375070 */, 17 }, + /* 4013 */ { MAD_F(0x07c8dab9) /* 0.486536717 */, 17 }, + /* 4014 */ { MAD_F(0x07c9843c) /* 0.486698377 */, 17 }, + /* 4015 */ { MAD_F(0x07ca2dc3) /* 0.486860051 */, 17 }, + + /* 4016 */ { MAD_F(0x07cad74e) /* 0.487021738 */, 17 }, + /* 4017 */ { MAD_F(0x07cb80dc) /* 0.487183438 */, 17 }, + /* 4018 */ { MAD_F(0x07cc2a6e) /* 0.487345152 */, 17 }, + /* 4019 */ { MAD_F(0x07ccd403) /* 0.487506879 */, 17 }, + /* 4020 */ { MAD_F(0x07cd7d9c) /* 0.487668620 */, 17 }, + /* 4021 */ { MAD_F(0x07ce2739) /* 0.487830374 */, 17 }, + /* 4022 */ { MAD_F(0x07ced0d9) /* 0.487992142 */, 17 }, + /* 4023 */ { MAD_F(0x07cf7a7d) /* 0.488153923 */, 17 }, + /* 4024 */ { MAD_F(0x07d02424) /* 0.488315717 */, 17 }, + /* 4025 */ { MAD_F(0x07d0cdcf) /* 0.488477525 */, 17 }, + /* 4026 */ { MAD_F(0x07d1777e) /* 0.488639346 */, 17 }, + /* 4027 */ { MAD_F(0x07d22130) /* 0.488801181 */, 17 }, + /* 4028 */ { MAD_F(0x07d2cae5) /* 0.488963029 */, 17 }, + /* 4029 */ { MAD_F(0x07d3749f) /* 0.489124890 */, 17 }, + /* 4030 */ { MAD_F(0x07d41e5c) /* 0.489286765 */, 17 }, + /* 4031 */ { MAD_F(0x07d4c81c) /* 0.489448653 */, 17 }, + + /* 4032 */ { MAD_F(0x07d571e0) /* 0.489610555 */, 17 }, + /* 4033 */ { MAD_F(0x07d61ba8) /* 0.489772470 */, 17 }, + /* 4034 */ { MAD_F(0x07d6c573) /* 0.489934398 */, 17 }, + /* 4035 */ { MAD_F(0x07d76f42) /* 0.490096340 */, 17 }, + /* 4036 */ { MAD_F(0x07d81915) /* 0.490258295 */, 17 }, + /* 4037 */ { MAD_F(0x07d8c2eb) /* 0.490420263 */, 17 }, + /* 4038 */ { MAD_F(0x07d96cc4) /* 0.490582245 */, 17 }, + /* 4039 */ { MAD_F(0x07da16a2) /* 0.490744240 */, 17 }, + /* 4040 */ { MAD_F(0x07dac083) /* 0.490906249 */, 17 }, + /* 4041 */ { MAD_F(0x07db6a67) /* 0.491068271 */, 17 }, + /* 4042 */ { MAD_F(0x07dc144f) /* 0.491230306 */, 17 }, + /* 4043 */ { MAD_F(0x07dcbe3b) /* 0.491392355 */, 17 }, + /* 4044 */ { MAD_F(0x07dd682a) /* 0.491554417 */, 17 }, + /* 4045 */ { MAD_F(0x07de121d) /* 0.491716492 */, 17 }, + /* 4046 */ { MAD_F(0x07debc13) /* 0.491878581 */, 17 }, + /* 4047 */ { MAD_F(0x07df660d) /* 0.492040683 */, 17 }, + + /* 4048 */ { MAD_F(0x07e0100a) /* 0.492202799 */, 17 }, + /* 4049 */ { MAD_F(0x07e0ba0c) /* 0.492364928 */, 17 }, + /* 4050 */ { MAD_F(0x07e16410) /* 0.492527070 */, 17 }, + /* 4051 */ { MAD_F(0x07e20e19) /* 0.492689225 */, 17 }, + /* 4052 */ { MAD_F(0x07e2b824) /* 0.492851394 */, 17 }, + /* 4053 */ { MAD_F(0x07e36234) /* 0.493013576 */, 17 }, + /* 4054 */ { MAD_F(0x07e40c47) /* 0.493175772 */, 17 }, + /* 4055 */ { MAD_F(0x07e4b65e) /* 0.493337981 */, 17 }, + /* 4056 */ { MAD_F(0x07e56078) /* 0.493500203 */, 17 }, + /* 4057 */ { MAD_F(0x07e60a95) /* 0.493662438 */, 17 }, + /* 4058 */ { MAD_F(0x07e6b4b7) /* 0.493824687 */, 17 }, + /* 4059 */ { MAD_F(0x07e75edc) /* 0.493986949 */, 17 }, + /* 4060 */ { MAD_F(0x07e80904) /* 0.494149225 */, 17 }, + /* 4061 */ { MAD_F(0x07e8b330) /* 0.494311514 */, 17 }, + /* 4062 */ { MAD_F(0x07e95d60) /* 0.494473816 */, 17 }, + /* 4063 */ { MAD_F(0x07ea0793) /* 0.494636131 */, 17 }, + + /* 4064 */ { MAD_F(0x07eab1ca) /* 0.494798460 */, 17 }, + /* 4065 */ { MAD_F(0x07eb5c04) /* 0.494960802 */, 17 }, + /* 4066 */ { MAD_F(0x07ec0642) /* 0.495123158 */, 17 }, + /* 4067 */ { MAD_F(0x07ecb084) /* 0.495285526 */, 17 }, + /* 4068 */ { MAD_F(0x07ed5ac9) /* 0.495447908 */, 17 }, + /* 4069 */ { MAD_F(0x07ee0512) /* 0.495610304 */, 17 }, + /* 4070 */ { MAD_F(0x07eeaf5e) /* 0.495772712 */, 17 }, + /* 4071 */ { MAD_F(0x07ef59ae) /* 0.495935134 */, 17 }, + /* 4072 */ { MAD_F(0x07f00401) /* 0.496097570 */, 17 }, + /* 4073 */ { MAD_F(0x07f0ae58) /* 0.496260018 */, 17 }, + /* 4074 */ { MAD_F(0x07f158b3) /* 0.496422480 */, 17 }, + /* 4075 */ { MAD_F(0x07f20311) /* 0.496584955 */, 17 }, + /* 4076 */ { MAD_F(0x07f2ad72) /* 0.496747444 */, 17 }, + /* 4077 */ { MAD_F(0x07f357d8) /* 0.496909945 */, 17 }, + /* 4078 */ { MAD_F(0x07f40240) /* 0.497072460 */, 17 }, + /* 4079 */ { MAD_F(0x07f4acad) /* 0.497234989 */, 17 }, + + /* 4080 */ { MAD_F(0x07f5571d) /* 0.497397530 */, 17 }, + /* 4081 */ { MAD_F(0x07f60190) /* 0.497560085 */, 17 }, + /* 4082 */ { MAD_F(0x07f6ac07) /* 0.497722653 */, 17 }, + /* 4083 */ { MAD_F(0x07f75682) /* 0.497885235 */, 17 }, + /* 4084 */ { MAD_F(0x07f80100) /* 0.498047829 */, 17 }, + /* 4085 */ { MAD_F(0x07f8ab82) /* 0.498210437 */, 17 }, + /* 4086 */ { MAD_F(0x07f95607) /* 0.498373058 */, 17 }, + /* 4087 */ { MAD_F(0x07fa0090) /* 0.498535693 */, 17 }, + /* 4088 */ { MAD_F(0x07faab1c) /* 0.498698341 */, 17 }, + /* 4089 */ { MAD_F(0x07fb55ac) /* 0.498861002 */, 17 }, + /* 4090 */ { MAD_F(0x07fc0040) /* 0.499023676 */, 17 }, + /* 4091 */ { MAD_F(0x07fcaad7) /* 0.499186364 */, 17 }, + /* 4092 */ { MAD_F(0x07fd5572) /* 0.499349064 */, 17 }, + /* 4093 */ { MAD_F(0x07fe0010) /* 0.499511778 */, 17 }, + /* 4094 */ { MAD_F(0x07feaab2) /* 0.499674506 */, 17 }, + /* 4095 */ { MAD_F(0x07ff5557) /* 0.499837246 */, 17 }, + + /* 4096 */ { MAD_F(0x04000000) /* 0.250000000 */, 18 }, + /* 4097 */ { MAD_F(0x04005556) /* 0.250081384 */, 18 }, + /* 4098 */ { MAD_F(0x0400aaae) /* 0.250162774 */, 18 }, + /* 4099 */ { MAD_F(0x04010008) /* 0.250244170 */, 18 }, + /* 4100 */ { MAD_F(0x04015563) /* 0.250325574 */, 18 }, + /* 4101 */ { MAD_F(0x0401aac1) /* 0.250406984 */, 18 }, + /* 4102 */ { MAD_F(0x04020020) /* 0.250488400 */, 18 }, + /* 4103 */ { MAD_F(0x04025581) /* 0.250569824 */, 18 }, + /* 4104 */ { MAD_F(0x0402aae3) /* 0.250651254 */, 18 }, + /* 4105 */ { MAD_F(0x04030048) /* 0.250732690 */, 18 }, + /* 4106 */ { MAD_F(0x040355ae) /* 0.250814133 */, 18 }, + /* 4107 */ { MAD_F(0x0403ab16) /* 0.250895583 */, 18 }, + /* 4108 */ { MAD_F(0x04040080) /* 0.250977039 */, 18 }, + /* 4109 */ { MAD_F(0x040455eb) /* 0.251058502 */, 18 }, + /* 4110 */ { MAD_F(0x0404ab59) /* 0.251139971 */, 18 }, + /* 4111 */ { MAD_F(0x040500c8) /* 0.251221448 */, 18 }, + + /* 4112 */ { MAD_F(0x04055638) /* 0.251302930 */, 18 }, + /* 4113 */ { MAD_F(0x0405abab) /* 0.251384420 */, 18 }, + /* 4114 */ { MAD_F(0x0406011f) /* 0.251465916 */, 18 }, + /* 4115 */ { MAD_F(0x04065696) /* 0.251547418 */, 18 }, + /* 4116 */ { MAD_F(0x0406ac0e) /* 0.251628927 */, 18 }, + /* 4117 */ { MAD_F(0x04070187) /* 0.251710443 */, 18 }, + /* 4118 */ { MAD_F(0x04075703) /* 0.251791965 */, 18 }, + /* 4119 */ { MAD_F(0x0407ac80) /* 0.251873494 */, 18 }, + /* 4120 */ { MAD_F(0x040801ff) /* 0.251955030 */, 18 }, + /* 4121 */ { MAD_F(0x04085780) /* 0.252036572 */, 18 }, + /* 4122 */ { MAD_F(0x0408ad02) /* 0.252118121 */, 18 }, + /* 4123 */ { MAD_F(0x04090287) /* 0.252199676 */, 18 }, + /* 4124 */ { MAD_F(0x0409580d) /* 0.252281238 */, 18 }, + /* 4125 */ { MAD_F(0x0409ad95) /* 0.252362807 */, 18 }, + /* 4126 */ { MAD_F(0x040a031e) /* 0.252444382 */, 18 }, + /* 4127 */ { MAD_F(0x040a58aa) /* 0.252525963 */, 18 }, + + /* 4128 */ { MAD_F(0x040aae37) /* 0.252607552 */, 18 }, + /* 4129 */ { MAD_F(0x040b03c6) /* 0.252689147 */, 18 }, + /* 4130 */ { MAD_F(0x040b5957) /* 0.252770748 */, 18 }, + /* 4131 */ { MAD_F(0x040baee9) /* 0.252852356 */, 18 }, + /* 4132 */ { MAD_F(0x040c047e) /* 0.252933971 */, 18 }, + /* 4133 */ { MAD_F(0x040c5a14) /* 0.253015592 */, 18 }, + /* 4134 */ { MAD_F(0x040cafab) /* 0.253097220 */, 18 }, + /* 4135 */ { MAD_F(0x040d0545) /* 0.253178854 */, 18 }, + /* 4136 */ { MAD_F(0x040d5ae0) /* 0.253260495 */, 18 }, + /* 4137 */ { MAD_F(0x040db07d) /* 0.253342143 */, 18 }, + /* 4138 */ { MAD_F(0x040e061c) /* 0.253423797 */, 18 }, + /* 4139 */ { MAD_F(0x040e5bbd) /* 0.253505457 */, 18 }, + /* 4140 */ { MAD_F(0x040eb15f) /* 0.253587125 */, 18 }, + /* 4141 */ { MAD_F(0x040f0703) /* 0.253668799 */, 18 }, + /* 4142 */ { MAD_F(0x040f5ca9) /* 0.253750479 */, 18 }, + /* 4143 */ { MAD_F(0x040fb251) /* 0.253832166 */, 18 }, + + /* 4144 */ { MAD_F(0x041007fa) /* 0.253913860 */, 18 }, + /* 4145 */ { MAD_F(0x04105da6) /* 0.253995560 */, 18 }, + /* 4146 */ { MAD_F(0x0410b353) /* 0.254077266 */, 18 }, + /* 4147 */ { MAD_F(0x04110901) /* 0.254158980 */, 18 }, + /* 4148 */ { MAD_F(0x04115eb2) /* 0.254240700 */, 18 }, + /* 4149 */ { MAD_F(0x0411b464) /* 0.254322426 */, 18 }, + /* 4150 */ { MAD_F(0x04120a18) /* 0.254404159 */, 18 }, + /* 4151 */ { MAD_F(0x04125fce) /* 0.254485899 */, 18 }, + /* 4152 */ { MAD_F(0x0412b586) /* 0.254567645 */, 18 }, + /* 4153 */ { MAD_F(0x04130b3f) /* 0.254649397 */, 18 }, + /* 4154 */ { MAD_F(0x041360fa) /* 0.254731157 */, 18 }, + /* 4155 */ { MAD_F(0x0413b6b7) /* 0.254812922 */, 18 }, + /* 4156 */ { MAD_F(0x04140c75) /* 0.254894695 */, 18 }, + /* 4157 */ { MAD_F(0x04146236) /* 0.254976474 */, 18 }, + /* 4158 */ { MAD_F(0x0414b7f8) /* 0.255058259 */, 18 }, + /* 4159 */ { MAD_F(0x04150dbc) /* 0.255140051 */, 18 }, + + /* 4160 */ { MAD_F(0x04156381) /* 0.255221850 */, 18 }, + /* 4161 */ { MAD_F(0x0415b949) /* 0.255303655 */, 18 }, + /* 4162 */ { MAD_F(0x04160f12) /* 0.255385467 */, 18 }, + /* 4163 */ { MAD_F(0x041664dd) /* 0.255467285 */, 18 }, + /* 4164 */ { MAD_F(0x0416baaa) /* 0.255549110 */, 18 }, + /* 4165 */ { MAD_F(0x04171078) /* 0.255630941 */, 18 }, + /* 4166 */ { MAD_F(0x04176648) /* 0.255712779 */, 18 }, + /* 4167 */ { MAD_F(0x0417bc1a) /* 0.255794624 */, 18 }, + /* 4168 */ { MAD_F(0x041811ee) /* 0.255876475 */, 18 }, + /* 4169 */ { MAD_F(0x041867c3) /* 0.255958332 */, 18 }, + /* 4170 */ { MAD_F(0x0418bd9b) /* 0.256040196 */, 18 }, + /* 4171 */ { MAD_F(0x04191374) /* 0.256122067 */, 18 }, + /* 4172 */ { MAD_F(0x0419694e) /* 0.256203944 */, 18 }, + /* 4173 */ { MAD_F(0x0419bf2b) /* 0.256285828 */, 18 }, + /* 4174 */ { MAD_F(0x041a1509) /* 0.256367718 */, 18 }, + /* 4175 */ { MAD_F(0x041a6ae9) /* 0.256449615 */, 18 }, + + /* 4176 */ { MAD_F(0x041ac0cb) /* 0.256531518 */, 18 }, + /* 4177 */ { MAD_F(0x041b16ae) /* 0.256613428 */, 18 }, + /* 4178 */ { MAD_F(0x041b6c94) /* 0.256695344 */, 18 }, + /* 4179 */ { MAD_F(0x041bc27b) /* 0.256777267 */, 18 }, + /* 4180 */ { MAD_F(0x041c1863) /* 0.256859197 */, 18 }, + /* 4181 */ { MAD_F(0x041c6e4e) /* 0.256941133 */, 18 }, + /* 4182 */ { MAD_F(0x041cc43a) /* 0.257023076 */, 18 }, + /* 4183 */ { MAD_F(0x041d1a28) /* 0.257105025 */, 18 }, + /* 4184 */ { MAD_F(0x041d7018) /* 0.257186980 */, 18 }, + /* 4185 */ { MAD_F(0x041dc60a) /* 0.257268942 */, 18 }, + /* 4186 */ { MAD_F(0x041e1bfd) /* 0.257350911 */, 18 }, + /* 4187 */ { MAD_F(0x041e71f2) /* 0.257432886 */, 18 }, + /* 4188 */ { MAD_F(0x041ec7e9) /* 0.257514868 */, 18 }, + /* 4189 */ { MAD_F(0x041f1de1) /* 0.257596856 */, 18 }, + /* 4190 */ { MAD_F(0x041f73dc) /* 0.257678851 */, 18 }, + /* 4191 */ { MAD_F(0x041fc9d8) /* 0.257760852 */, 18 }, + + /* 4192 */ { MAD_F(0x04201fd5) /* 0.257842860 */, 18 }, + /* 4193 */ { MAD_F(0x042075d5) /* 0.257924875 */, 18 }, + /* 4194 */ { MAD_F(0x0420cbd6) /* 0.258006895 */, 18 }, + /* 4195 */ { MAD_F(0x042121d9) /* 0.258088923 */, 18 }, + /* 4196 */ { MAD_F(0x042177de) /* 0.258170957 */, 18 }, + /* 4197 */ { MAD_F(0x0421cde5) /* 0.258252997 */, 18 }, + /* 4198 */ { MAD_F(0x042223ed) /* 0.258335044 */, 18 }, + /* 4199 */ { MAD_F(0x042279f7) /* 0.258417097 */, 18 }, + /* 4200 */ { MAD_F(0x0422d003) /* 0.258499157 */, 18 }, + /* 4201 */ { MAD_F(0x04232611) /* 0.258581224 */, 18 }, + /* 4202 */ { MAD_F(0x04237c20) /* 0.258663297 */, 18 }, + /* 4203 */ { MAD_F(0x0423d231) /* 0.258745376 */, 18 }, + /* 4204 */ { MAD_F(0x04242844) /* 0.258827462 */, 18 }, + /* 4205 */ { MAD_F(0x04247e58) /* 0.258909555 */, 18 }, + /* 4206 */ { MAD_F(0x0424d46e) /* 0.258991654 */, 18 }, + /* 4207 */ { MAD_F(0x04252a87) /* 0.259073760 */, 18 }, + + /* 4208 */ { MAD_F(0x042580a0) /* 0.259155872 */, 18 }, + /* 4209 */ { MAD_F(0x0425d6bc) /* 0.259237990 */, 18 }, + /* 4210 */ { MAD_F(0x04262cd9) /* 0.259320115 */, 18 }, + /* 4211 */ { MAD_F(0x042682f8) /* 0.259402247 */, 18 }, + /* 4212 */ { MAD_F(0x0426d919) /* 0.259484385 */, 18 }, + /* 4213 */ { MAD_F(0x04272f3b) /* 0.259566529 */, 18 }, + /* 4214 */ { MAD_F(0x04278560) /* 0.259648680 */, 18 }, + /* 4215 */ { MAD_F(0x0427db86) /* 0.259730838 */, 18 }, + /* 4216 */ { MAD_F(0x042831ad) /* 0.259813002 */, 18 }, + /* 4217 */ { MAD_F(0x042887d7) /* 0.259895173 */, 18 }, + /* 4218 */ { MAD_F(0x0428de02) /* 0.259977350 */, 18 }, + /* 4219 */ { MAD_F(0x0429342f) /* 0.260059533 */, 18 }, + /* 4220 */ { MAD_F(0x04298a5e) /* 0.260141723 */, 18 }, + /* 4221 */ { MAD_F(0x0429e08e) /* 0.260223920 */, 18 }, + /* 4222 */ { MAD_F(0x042a36c0) /* 0.260306123 */, 18 }, + /* 4223 */ { MAD_F(0x042a8cf4) /* 0.260388332 */, 18 }, + + /* 4224 */ { MAD_F(0x042ae32a) /* 0.260470548 */, 18 }, + /* 4225 */ { MAD_F(0x042b3962) /* 0.260552771 */, 18 }, + /* 4226 */ { MAD_F(0x042b8f9b) /* 0.260635000 */, 18 }, + /* 4227 */ { MAD_F(0x042be5d6) /* 0.260717235 */, 18 }, + /* 4228 */ { MAD_F(0x042c3c12) /* 0.260799477 */, 18 }, + /* 4229 */ { MAD_F(0x042c9251) /* 0.260881725 */, 18 }, + /* 4230 */ { MAD_F(0x042ce891) /* 0.260963980 */, 18 }, + /* 4231 */ { MAD_F(0x042d3ed3) /* 0.261046242 */, 18 }, + /* 4232 */ { MAD_F(0x042d9516) /* 0.261128510 */, 18 }, + /* 4233 */ { MAD_F(0x042deb5c) /* 0.261210784 */, 18 }, + /* 4234 */ { MAD_F(0x042e41a3) /* 0.261293065 */, 18 }, + /* 4235 */ { MAD_F(0x042e97ec) /* 0.261375352 */, 18 }, + /* 4236 */ { MAD_F(0x042eee36) /* 0.261457646 */, 18 }, + /* 4237 */ { MAD_F(0x042f4482) /* 0.261539946 */, 18 }, + /* 4238 */ { MAD_F(0x042f9ad1) /* 0.261622253 */, 18 }, + /* 4239 */ { MAD_F(0x042ff120) /* 0.261704566 */, 18 }, + + /* 4240 */ { MAD_F(0x04304772) /* 0.261786886 */, 18 }, + /* 4241 */ { MAD_F(0x04309dc5) /* 0.261869212 */, 18 }, + /* 4242 */ { MAD_F(0x0430f41a) /* 0.261951545 */, 18 }, + /* 4243 */ { MAD_F(0x04314a71) /* 0.262033884 */, 18 }, + /* 4244 */ { MAD_F(0x0431a0c9) /* 0.262116229 */, 18 }, + /* 4245 */ { MAD_F(0x0431f723) /* 0.262198581 */, 18 }, + /* 4246 */ { MAD_F(0x04324d7f) /* 0.262280940 */, 18 }, + /* 4247 */ { MAD_F(0x0432a3dd) /* 0.262363305 */, 18 }, + /* 4248 */ { MAD_F(0x0432fa3d) /* 0.262445676 */, 18 }, + /* 4249 */ { MAD_F(0x0433509e) /* 0.262528054 */, 18 }, + /* 4250 */ { MAD_F(0x0433a701) /* 0.262610438 */, 18 }, + /* 4251 */ { MAD_F(0x0433fd65) /* 0.262692829 */, 18 }, + /* 4252 */ { MAD_F(0x043453cc) /* 0.262775227 */, 18 }, + /* 4253 */ { MAD_F(0x0434aa34) /* 0.262857630 */, 18 }, + /* 4254 */ { MAD_F(0x0435009d) /* 0.262940040 */, 18 }, + /* 4255 */ { MAD_F(0x04355709) /* 0.263022457 */, 18 }, + + /* 4256 */ { MAD_F(0x0435ad76) /* 0.263104880 */, 18 }, + /* 4257 */ { MAD_F(0x043603e5) /* 0.263187310 */, 18 }, + /* 4258 */ { MAD_F(0x04365a56) /* 0.263269746 */, 18 }, + /* 4259 */ { MAD_F(0x0436b0c9) /* 0.263352188 */, 18 }, + /* 4260 */ { MAD_F(0x0437073d) /* 0.263434637 */, 18 }, + /* 4261 */ { MAD_F(0x04375db3) /* 0.263517093 */, 18 }, + /* 4262 */ { MAD_F(0x0437b42a) /* 0.263599554 */, 18 }, + /* 4263 */ { MAD_F(0x04380aa4) /* 0.263682023 */, 18 }, + /* 4264 */ { MAD_F(0x0438611f) /* 0.263764497 */, 18 }, + /* 4265 */ { MAD_F(0x0438b79c) /* 0.263846979 */, 18 }, + /* 4266 */ { MAD_F(0x04390e1a) /* 0.263929466 */, 18 }, + /* 4267 */ { MAD_F(0x0439649b) /* 0.264011960 */, 18 }, + /* 4268 */ { MAD_F(0x0439bb1d) /* 0.264094461 */, 18 }, + /* 4269 */ { MAD_F(0x043a11a1) /* 0.264176968 */, 18 }, + /* 4270 */ { MAD_F(0x043a6826) /* 0.264259481 */, 18 }, + /* 4271 */ { MAD_F(0x043abead) /* 0.264342001 */, 18 }, + + /* 4272 */ { MAD_F(0x043b1536) /* 0.264424527 */, 18 }, + /* 4273 */ { MAD_F(0x043b6bc1) /* 0.264507060 */, 18 }, + /* 4274 */ { MAD_F(0x043bc24d) /* 0.264589599 */, 18 }, + /* 4275 */ { MAD_F(0x043c18dc) /* 0.264672145 */, 18 }, + /* 4276 */ { MAD_F(0x043c6f6c) /* 0.264754697 */, 18 }, + /* 4277 */ { MAD_F(0x043cc5fd) /* 0.264837255 */, 18 }, + /* 4278 */ { MAD_F(0x043d1c91) /* 0.264919820 */, 18 }, + /* 4279 */ { MAD_F(0x043d7326) /* 0.265002392 */, 18 }, + /* 4280 */ { MAD_F(0x043dc9bc) /* 0.265084969 */, 18 }, + /* 4281 */ { MAD_F(0x043e2055) /* 0.265167554 */, 18 }, + /* 4282 */ { MAD_F(0x043e76ef) /* 0.265250144 */, 18 }, + /* 4283 */ { MAD_F(0x043ecd8b) /* 0.265332741 */, 18 }, + /* 4284 */ { MAD_F(0x043f2429) /* 0.265415345 */, 18 }, + /* 4285 */ { MAD_F(0x043f7ac8) /* 0.265497955 */, 18 }, + /* 4286 */ { MAD_F(0x043fd169) /* 0.265580571 */, 18 }, + /* 4287 */ { MAD_F(0x0440280c) /* 0.265663194 */, 18 }, + + /* 4288 */ { MAD_F(0x04407eb1) /* 0.265745823 */, 18 }, + /* 4289 */ { MAD_F(0x0440d557) /* 0.265828459 */, 18 }, + /* 4290 */ { MAD_F(0x04412bff) /* 0.265911101 */, 18 }, + /* 4291 */ { MAD_F(0x044182a9) /* 0.265993749 */, 18 }, + /* 4292 */ { MAD_F(0x0441d955) /* 0.266076404 */, 18 }, + /* 4293 */ { MAD_F(0x04423002) /* 0.266159065 */, 18 }, + /* 4294 */ { MAD_F(0x044286b1) /* 0.266241733 */, 18 }, + /* 4295 */ { MAD_F(0x0442dd61) /* 0.266324407 */, 18 }, + /* 4296 */ { MAD_F(0x04433414) /* 0.266407088 */, 18 }, + /* 4297 */ { MAD_F(0x04438ac8) /* 0.266489775 */, 18 }, + /* 4298 */ { MAD_F(0x0443e17e) /* 0.266572468 */, 18 }, + /* 4299 */ { MAD_F(0x04443835) /* 0.266655168 */, 18 }, + /* 4300 */ { MAD_F(0x04448eef) /* 0.266737874 */, 18 }, + /* 4301 */ { MAD_F(0x0444e5aa) /* 0.266820587 */, 18 }, + /* 4302 */ { MAD_F(0x04453c66) /* 0.266903306 */, 18 }, + /* 4303 */ { MAD_F(0x04459325) /* 0.266986031 */, 18 }, + + /* 4304 */ { MAD_F(0x0445e9e5) /* 0.267068763 */, 18 }, + /* 4305 */ { MAD_F(0x044640a7) /* 0.267151501 */, 18 }, + /* 4306 */ { MAD_F(0x0446976a) /* 0.267234246 */, 18 }, + /* 4307 */ { MAD_F(0x0446ee30) /* 0.267316997 */, 18 }, + /* 4308 */ { MAD_F(0x044744f7) /* 0.267399755 */, 18 }, + /* 4309 */ { MAD_F(0x04479bc0) /* 0.267482518 */, 18 }, + /* 4310 */ { MAD_F(0x0447f28a) /* 0.267565289 */, 18 }, + /* 4311 */ { MAD_F(0x04484956) /* 0.267648065 */, 18 }, + /* 4312 */ { MAD_F(0x0448a024) /* 0.267730848 */, 18 }, + /* 4313 */ { MAD_F(0x0448f6f4) /* 0.267813638 */, 18 }, + /* 4314 */ { MAD_F(0x04494dc5) /* 0.267896434 */, 18 }, + /* 4315 */ { MAD_F(0x0449a498) /* 0.267979236 */, 18 }, + /* 4316 */ { MAD_F(0x0449fb6d) /* 0.268062045 */, 18 }, + /* 4317 */ { MAD_F(0x044a5243) /* 0.268144860 */, 18 }, + /* 4318 */ { MAD_F(0x044aa91c) /* 0.268227681 */, 18 }, + /* 4319 */ { MAD_F(0x044afff6) /* 0.268310509 */, 18 }, + + /* 4320 */ { MAD_F(0x044b56d1) /* 0.268393343 */, 18 }, + /* 4321 */ { MAD_F(0x044badaf) /* 0.268476184 */, 18 }, + /* 4322 */ { MAD_F(0x044c048e) /* 0.268559031 */, 18 }, + /* 4323 */ { MAD_F(0x044c5b6f) /* 0.268641885 */, 18 }, + /* 4324 */ { MAD_F(0x044cb251) /* 0.268724744 */, 18 }, + /* 4325 */ { MAD_F(0x044d0935) /* 0.268807611 */, 18 }, + /* 4326 */ { MAD_F(0x044d601b) /* 0.268890483 */, 18 }, + /* 4327 */ { MAD_F(0x044db703) /* 0.268973362 */, 18 }, + /* 4328 */ { MAD_F(0x044e0dec) /* 0.269056248 */, 18 }, + /* 4329 */ { MAD_F(0x044e64d7) /* 0.269139139 */, 18 }, + /* 4330 */ { MAD_F(0x044ebbc4) /* 0.269222037 */, 18 }, + /* 4331 */ { MAD_F(0x044f12b3) /* 0.269304942 */, 18 }, + /* 4332 */ { MAD_F(0x044f69a3) /* 0.269387853 */, 18 }, + /* 4333 */ { MAD_F(0x044fc095) /* 0.269470770 */, 18 }, + /* 4334 */ { MAD_F(0x04501788) /* 0.269553694 */, 18 }, + /* 4335 */ { MAD_F(0x04506e7e) /* 0.269636624 */, 18 }, + + /* 4336 */ { MAD_F(0x0450c575) /* 0.269719560 */, 18 }, + /* 4337 */ { MAD_F(0x04511c6e) /* 0.269802503 */, 18 }, + /* 4338 */ { MAD_F(0x04517368) /* 0.269885452 */, 18 }, + /* 4339 */ { MAD_F(0x0451ca64) /* 0.269968408 */, 18 }, + /* 4340 */ { MAD_F(0x04522162) /* 0.270051370 */, 18 }, + /* 4341 */ { MAD_F(0x04527862) /* 0.270134338 */, 18 }, + /* 4342 */ { MAD_F(0x0452cf63) /* 0.270217312 */, 18 }, + /* 4343 */ { MAD_F(0x04532666) /* 0.270300293 */, 18 }, + /* 4344 */ { MAD_F(0x04537d6b) /* 0.270383281 */, 18 }, + /* 4345 */ { MAD_F(0x0453d472) /* 0.270466275 */, 18 }, + /* 4346 */ { MAD_F(0x04542b7a) /* 0.270549275 */, 18 }, + /* 4347 */ { MAD_F(0x04548284) /* 0.270632281 */, 18 }, + /* 4348 */ { MAD_F(0x0454d98f) /* 0.270715294 */, 18 }, + /* 4349 */ { MAD_F(0x0455309c) /* 0.270798313 */, 18 }, + /* 4350 */ { MAD_F(0x045587ab) /* 0.270881339 */, 18 }, + /* 4351 */ { MAD_F(0x0455debc) /* 0.270964371 */, 18 }, + + /* 4352 */ { MAD_F(0x045635cf) /* 0.271047409 */, 18 }, + /* 4353 */ { MAD_F(0x04568ce3) /* 0.271130454 */, 18 }, + /* 4354 */ { MAD_F(0x0456e3f9) /* 0.271213505 */, 18 }, + /* 4355 */ { MAD_F(0x04573b10) /* 0.271296562 */, 18 }, + /* 4356 */ { MAD_F(0x04579229) /* 0.271379626 */, 18 }, + /* 4357 */ { MAD_F(0x0457e944) /* 0.271462696 */, 18 }, + /* 4358 */ { MAD_F(0x04584061) /* 0.271545772 */, 18 }, + /* 4359 */ { MAD_F(0x0458977f) /* 0.271628855 */, 18 }, + /* 4360 */ { MAD_F(0x0458ee9f) /* 0.271711944 */, 18 }, + /* 4361 */ { MAD_F(0x045945c1) /* 0.271795040 */, 18 }, + /* 4362 */ { MAD_F(0x04599ce5) /* 0.271878142 */, 18 }, + /* 4363 */ { MAD_F(0x0459f40a) /* 0.271961250 */, 18 }, + /* 4364 */ { MAD_F(0x045a4b31) /* 0.272044365 */, 18 }, + /* 4365 */ { MAD_F(0x045aa259) /* 0.272127486 */, 18 }, + /* 4366 */ { MAD_F(0x045af984) /* 0.272210613 */, 18 }, + /* 4367 */ { MAD_F(0x045b50b0) /* 0.272293746 */, 18 }, + + /* 4368 */ { MAD_F(0x045ba7dd) /* 0.272376886 */, 18 }, + /* 4369 */ { MAD_F(0x045bff0d) /* 0.272460033 */, 18 }, + /* 4370 */ { MAD_F(0x045c563e) /* 0.272543185 */, 18 }, + /* 4371 */ { MAD_F(0x045cad71) /* 0.272626344 */, 18 }, + /* 4372 */ { MAD_F(0x045d04a5) /* 0.272709510 */, 18 }, + /* 4373 */ { MAD_F(0x045d5bdc) /* 0.272792681 */, 18 }, + /* 4374 */ { MAD_F(0x045db313) /* 0.272875859 */, 18 }, + /* 4375 */ { MAD_F(0x045e0a4d) /* 0.272959044 */, 18 }, + /* 4376 */ { MAD_F(0x045e6188) /* 0.273042234 */, 18 }, + /* 4377 */ { MAD_F(0x045eb8c5) /* 0.273125431 */, 18 }, + /* 4378 */ { MAD_F(0x045f1004) /* 0.273208635 */, 18 }, + /* 4379 */ { MAD_F(0x045f6745) /* 0.273291844 */, 18 }, + /* 4380 */ { MAD_F(0x045fbe87) /* 0.273375060 */, 18 }, + /* 4381 */ { MAD_F(0x046015cb) /* 0.273458283 */, 18 }, + /* 4382 */ { MAD_F(0x04606d10) /* 0.273541511 */, 18 }, + /* 4383 */ { MAD_F(0x0460c457) /* 0.273624747 */, 18 }, + + /* 4384 */ { MAD_F(0x04611ba0) /* 0.273707988 */, 18 }, + /* 4385 */ { MAD_F(0x046172eb) /* 0.273791236 */, 18 }, + /* 4386 */ { MAD_F(0x0461ca37) /* 0.273874490 */, 18 }, + /* 4387 */ { MAD_F(0x04622185) /* 0.273957750 */, 18 }, + /* 4388 */ { MAD_F(0x046278d5) /* 0.274041017 */, 18 }, + /* 4389 */ { MAD_F(0x0462d026) /* 0.274124290 */, 18 }, + /* 4390 */ { MAD_F(0x0463277a) /* 0.274207569 */, 18 }, + /* 4391 */ { MAD_F(0x04637ece) /* 0.274290855 */, 18 }, + /* 4392 */ { MAD_F(0x0463d625) /* 0.274374147 */, 18 }, + /* 4393 */ { MAD_F(0x04642d7d) /* 0.274457445 */, 18 }, + /* 4394 */ { MAD_F(0x046484d7) /* 0.274540749 */, 18 }, + /* 4395 */ { MAD_F(0x0464dc33) /* 0.274624060 */, 18 }, + /* 4396 */ { MAD_F(0x04653390) /* 0.274707378 */, 18 }, + /* 4397 */ { MAD_F(0x04658aef) /* 0.274790701 */, 18 }, + /* 4398 */ { MAD_F(0x0465e250) /* 0.274874031 */, 18 }, + /* 4399 */ { MAD_F(0x046639b2) /* 0.274957367 */, 18 }, + + /* 4400 */ { MAD_F(0x04669116) /* 0.275040710 */, 18 }, + /* 4401 */ { MAD_F(0x0466e87c) /* 0.275124059 */, 18 }, + /* 4402 */ { MAD_F(0x04673fe3) /* 0.275207414 */, 18 }, + /* 4403 */ { MAD_F(0x0467974d) /* 0.275290775 */, 18 }, + /* 4404 */ { MAD_F(0x0467eeb7) /* 0.275374143 */, 18 }, + /* 4405 */ { MAD_F(0x04684624) /* 0.275457517 */, 18 }, + /* 4406 */ { MAD_F(0x04689d92) /* 0.275540897 */, 18 }, + /* 4407 */ { MAD_F(0x0468f502) /* 0.275624284 */, 18 }, + /* 4408 */ { MAD_F(0x04694c74) /* 0.275707677 */, 18 }, + /* 4409 */ { MAD_F(0x0469a3e7) /* 0.275791076 */, 18 }, + /* 4410 */ { MAD_F(0x0469fb5c) /* 0.275874482 */, 18 }, + /* 4411 */ { MAD_F(0x046a52d3) /* 0.275957894 */, 18 }, + /* 4412 */ { MAD_F(0x046aaa4b) /* 0.276041312 */, 18 }, + /* 4413 */ { MAD_F(0x046b01c5) /* 0.276124737 */, 18 }, + /* 4414 */ { MAD_F(0x046b5941) /* 0.276208167 */, 18 }, + /* 4415 */ { MAD_F(0x046bb0bf) /* 0.276291605 */, 18 }, + + /* 4416 */ { MAD_F(0x046c083e) /* 0.276375048 */, 18 }, + /* 4417 */ { MAD_F(0x046c5fbf) /* 0.276458498 */, 18 }, + /* 4418 */ { MAD_F(0x046cb741) /* 0.276541954 */, 18 }, + /* 4419 */ { MAD_F(0x046d0ec5) /* 0.276625416 */, 18 }, + /* 4420 */ { MAD_F(0x046d664b) /* 0.276708885 */, 18 }, + /* 4421 */ { MAD_F(0x046dbdd3) /* 0.276792360 */, 18 }, + /* 4422 */ { MAD_F(0x046e155c) /* 0.276875841 */, 18 }, + /* 4423 */ { MAD_F(0x046e6ce7) /* 0.276959328 */, 18 }, + /* 4424 */ { MAD_F(0x046ec474) /* 0.277042822 */, 18 }, + /* 4425 */ { MAD_F(0x046f1c02) /* 0.277126322 */, 18 }, + /* 4426 */ { MAD_F(0x046f7392) /* 0.277209829 */, 18 }, + /* 4427 */ { MAD_F(0x046fcb24) /* 0.277293341 */, 18 }, + /* 4428 */ { MAD_F(0x047022b8) /* 0.277376860 */, 18 }, + /* 4429 */ { MAD_F(0x04707a4d) /* 0.277460385 */, 18 }, + /* 4430 */ { MAD_F(0x0470d1e4) /* 0.277543917 */, 18 }, + /* 4431 */ { MAD_F(0x0471297c) /* 0.277627455 */, 18 }, + + /* 4432 */ { MAD_F(0x04718116) /* 0.277710999 */, 18 }, + /* 4433 */ { MAD_F(0x0471d8b2) /* 0.277794549 */, 18 }, + /* 4434 */ { MAD_F(0x04723050) /* 0.277878106 */, 18 }, + /* 4435 */ { MAD_F(0x047287ef) /* 0.277961669 */, 18 }, + /* 4436 */ { MAD_F(0x0472df90) /* 0.278045238 */, 18 }, + /* 4437 */ { MAD_F(0x04733733) /* 0.278128813 */, 18 }, + /* 4438 */ { MAD_F(0x04738ed7) /* 0.278212395 */, 18 }, + /* 4439 */ { MAD_F(0x0473e67d) /* 0.278295983 */, 18 }, + /* 4440 */ { MAD_F(0x04743e25) /* 0.278379578 */, 18 }, + /* 4441 */ { MAD_F(0x047495ce) /* 0.278463178 */, 18 }, + /* 4442 */ { MAD_F(0x0474ed79) /* 0.278546785 */, 18 }, + /* 4443 */ { MAD_F(0x04754526) /* 0.278630398 */, 18 }, + /* 4444 */ { MAD_F(0x04759cd4) /* 0.278714018 */, 18 }, + /* 4445 */ { MAD_F(0x0475f484) /* 0.278797643 */, 18 }, + /* 4446 */ { MAD_F(0x04764c36) /* 0.278881275 */, 18 }, + /* 4447 */ { MAD_F(0x0476a3ea) /* 0.278964914 */, 18 }, + + /* 4448 */ { MAD_F(0x0476fb9f) /* 0.279048558 */, 18 }, + /* 4449 */ { MAD_F(0x04775356) /* 0.279132209 */, 18 }, + /* 4450 */ { MAD_F(0x0477ab0e) /* 0.279215866 */, 18 }, + /* 4451 */ { MAD_F(0x047802c8) /* 0.279299529 */, 18 }, + /* 4452 */ { MAD_F(0x04785a84) /* 0.279383199 */, 18 }, + /* 4453 */ { MAD_F(0x0478b242) /* 0.279466875 */, 18 }, + /* 4454 */ { MAD_F(0x04790a01) /* 0.279550557 */, 18 }, + /* 4455 */ { MAD_F(0x047961c2) /* 0.279634245 */, 18 }, + /* 4456 */ { MAD_F(0x0479b984) /* 0.279717940 */, 18 }, + /* 4457 */ { MAD_F(0x047a1149) /* 0.279801641 */, 18 }, + /* 4458 */ { MAD_F(0x047a690f) /* 0.279885348 */, 18 }, + /* 4459 */ { MAD_F(0x047ac0d6) /* 0.279969061 */, 18 }, + /* 4460 */ { MAD_F(0x047b18a0) /* 0.280052781 */, 18 }, + /* 4461 */ { MAD_F(0x047b706b) /* 0.280136507 */, 18 }, + /* 4462 */ { MAD_F(0x047bc837) /* 0.280220239 */, 18 }, + /* 4463 */ { MAD_F(0x047c2006) /* 0.280303978 */, 18 }, + + /* 4464 */ { MAD_F(0x047c77d6) /* 0.280387722 */, 18 }, + /* 4465 */ { MAD_F(0x047ccfa8) /* 0.280471473 */, 18 }, + /* 4466 */ { MAD_F(0x047d277b) /* 0.280555230 */, 18 }, + /* 4467 */ { MAD_F(0x047d7f50) /* 0.280638994 */, 18 }, + /* 4468 */ { MAD_F(0x047dd727) /* 0.280722764 */, 18 }, + /* 4469 */ { MAD_F(0x047e2eff) /* 0.280806540 */, 18 }, + /* 4470 */ { MAD_F(0x047e86d9) /* 0.280890322 */, 18 }, + /* 4471 */ { MAD_F(0x047edeb5) /* 0.280974110 */, 18 }, + /* 4472 */ { MAD_F(0x047f3693) /* 0.281057905 */, 18 }, + /* 4473 */ { MAD_F(0x047f8e72) /* 0.281141706 */, 18 }, + /* 4474 */ { MAD_F(0x047fe653) /* 0.281225513 */, 18 }, + /* 4475 */ { MAD_F(0x04803e35) /* 0.281309326 */, 18 }, + /* 4476 */ { MAD_F(0x04809619) /* 0.281393146 */, 18 }, + /* 4477 */ { MAD_F(0x0480edff) /* 0.281476972 */, 18 }, + /* 4478 */ { MAD_F(0x048145e7) /* 0.281560804 */, 18 }, + /* 4479 */ { MAD_F(0x04819dd0) /* 0.281644643 */, 18 }, + + /* 4480 */ { MAD_F(0x0481f5bb) /* 0.281728487 */, 18 }, + /* 4481 */ { MAD_F(0x04824da7) /* 0.281812338 */, 18 }, + /* 4482 */ { MAD_F(0x0482a595) /* 0.281896195 */, 18 }, + /* 4483 */ { MAD_F(0x0482fd85) /* 0.281980059 */, 18 }, + /* 4484 */ { MAD_F(0x04835577) /* 0.282063928 */, 18 }, + /* 4485 */ { MAD_F(0x0483ad6a) /* 0.282147804 */, 18 }, + /* 4486 */ { MAD_F(0x0484055f) /* 0.282231686 */, 18 }, + /* 4487 */ { MAD_F(0x04845d56) /* 0.282315574 */, 18 }, + /* 4488 */ { MAD_F(0x0484b54e) /* 0.282399469 */, 18 }, + /* 4489 */ { MAD_F(0x04850d48) /* 0.282483370 */, 18 }, + /* 4490 */ { MAD_F(0x04856544) /* 0.282567277 */, 18 }, + /* 4491 */ { MAD_F(0x0485bd41) /* 0.282651190 */, 18 }, + /* 4492 */ { MAD_F(0x04861540) /* 0.282735109 */, 18 }, + /* 4493 */ { MAD_F(0x04866d40) /* 0.282819035 */, 18 }, + /* 4494 */ { MAD_F(0x0486c543) /* 0.282902967 */, 18 }, + /* 4495 */ { MAD_F(0x04871d47) /* 0.282986905 */, 18 }, + + /* 4496 */ { MAD_F(0x0487754c) /* 0.283070849 */, 18 }, + /* 4497 */ { MAD_F(0x0487cd54) /* 0.283154800 */, 18 }, + /* 4498 */ { MAD_F(0x0488255d) /* 0.283238757 */, 18 }, + /* 4499 */ { MAD_F(0x04887d67) /* 0.283322720 */, 18 }, + /* 4500 */ { MAD_F(0x0488d574) /* 0.283406689 */, 18 }, + /* 4501 */ { MAD_F(0x04892d82) /* 0.283490665 */, 18 }, + /* 4502 */ { MAD_F(0x04898591) /* 0.283574646 */, 18 }, + /* 4503 */ { MAD_F(0x0489dda3) /* 0.283658634 */, 18 }, + /* 4504 */ { MAD_F(0x048a35b6) /* 0.283742628 */, 18 }, + /* 4505 */ { MAD_F(0x048a8dca) /* 0.283826629 */, 18 }, + /* 4506 */ { MAD_F(0x048ae5e1) /* 0.283910635 */, 18 }, + /* 4507 */ { MAD_F(0x048b3df9) /* 0.283994648 */, 18 }, + /* 4508 */ { MAD_F(0x048b9612) /* 0.284078667 */, 18 }, + /* 4509 */ { MAD_F(0x048bee2e) /* 0.284162692 */, 18 }, + /* 4510 */ { MAD_F(0x048c464b) /* 0.284246723 */, 18 }, + /* 4511 */ { MAD_F(0x048c9e69) /* 0.284330761 */, 18 }, + + /* 4512 */ { MAD_F(0x048cf68a) /* 0.284414805 */, 18 }, + /* 4513 */ { MAD_F(0x048d4eac) /* 0.284498855 */, 18 }, + /* 4514 */ { MAD_F(0x048da6cf) /* 0.284582911 */, 18 }, + /* 4515 */ { MAD_F(0x048dfef5) /* 0.284666974 */, 18 }, + /* 4516 */ { MAD_F(0x048e571c) /* 0.284751042 */, 18 }, + /* 4517 */ { MAD_F(0x048eaf44) /* 0.284835117 */, 18 }, + /* 4518 */ { MAD_F(0x048f076f) /* 0.284919198 */, 18 }, + /* 4519 */ { MAD_F(0x048f5f9b) /* 0.285003285 */, 18 }, + /* 4520 */ { MAD_F(0x048fb7c8) /* 0.285087379 */, 18 }, + /* 4521 */ { MAD_F(0x04900ff8) /* 0.285171479 */, 18 }, + /* 4522 */ { MAD_F(0x04906829) /* 0.285255584 */, 18 }, + /* 4523 */ { MAD_F(0x0490c05b) /* 0.285339697 */, 18 }, + /* 4524 */ { MAD_F(0x04911890) /* 0.285423815 */, 18 }, + /* 4525 */ { MAD_F(0x049170c6) /* 0.285507939 */, 18 }, + /* 4526 */ { MAD_F(0x0491c8fd) /* 0.285592070 */, 18 }, + /* 4527 */ { MAD_F(0x04922137) /* 0.285676207 */, 18 }, + + /* 4528 */ { MAD_F(0x04927972) /* 0.285760350 */, 18 }, + /* 4529 */ { MAD_F(0x0492d1ae) /* 0.285844499 */, 18 }, + /* 4530 */ { MAD_F(0x049329ed) /* 0.285928655 */, 18 }, + /* 4531 */ { MAD_F(0x0493822c) /* 0.286012816 */, 18 }, + /* 4532 */ { MAD_F(0x0493da6e) /* 0.286096984 */, 18 }, + /* 4533 */ { MAD_F(0x049432b1) /* 0.286181158 */, 18 }, + /* 4534 */ { MAD_F(0x04948af6) /* 0.286265338 */, 18 }, + /* 4535 */ { MAD_F(0x0494e33d) /* 0.286349525 */, 18 }, + /* 4536 */ { MAD_F(0x04953b85) /* 0.286433717 */, 18 }, + /* 4537 */ { MAD_F(0x049593cf) /* 0.286517916 */, 18 }, + /* 4538 */ { MAD_F(0x0495ec1b) /* 0.286602121 */, 18 }, + /* 4539 */ { MAD_F(0x04964468) /* 0.286686332 */, 18 }, + /* 4540 */ { MAD_F(0x04969cb7) /* 0.286770550 */, 18 }, + /* 4541 */ { MAD_F(0x0496f508) /* 0.286854773 */, 18 }, + /* 4542 */ { MAD_F(0x04974d5a) /* 0.286939003 */, 18 }, + /* 4543 */ { MAD_F(0x0497a5ae) /* 0.287023239 */, 18 }, + + /* 4544 */ { MAD_F(0x0497fe03) /* 0.287107481 */, 18 }, + /* 4545 */ { MAD_F(0x0498565a) /* 0.287191729 */, 18 }, + /* 4546 */ { MAD_F(0x0498aeb3) /* 0.287275983 */, 18 }, + /* 4547 */ { MAD_F(0x0499070e) /* 0.287360244 */, 18 }, + /* 4548 */ { MAD_F(0x04995f6a) /* 0.287444511 */, 18 }, + /* 4549 */ { MAD_F(0x0499b7c8) /* 0.287528784 */, 18 }, + /* 4550 */ { MAD_F(0x049a1027) /* 0.287613063 */, 18 }, + /* 4551 */ { MAD_F(0x049a6889) /* 0.287697348 */, 18 }, + /* 4552 */ { MAD_F(0x049ac0eb) /* 0.287781640 */, 18 }, + /* 4553 */ { MAD_F(0x049b1950) /* 0.287865937 */, 18 }, + /* 4554 */ { MAD_F(0x049b71b6) /* 0.287950241 */, 18 }, + /* 4555 */ { MAD_F(0x049bca1e) /* 0.288034551 */, 18 }, + /* 4556 */ { MAD_F(0x049c2287) /* 0.288118867 */, 18 }, + /* 4557 */ { MAD_F(0x049c7af2) /* 0.288203190 */, 18 }, + /* 4558 */ { MAD_F(0x049cd35f) /* 0.288287518 */, 18 }, + /* 4559 */ { MAD_F(0x049d2bce) /* 0.288371853 */, 18 }, + + /* 4560 */ { MAD_F(0x049d843e) /* 0.288456194 */, 18 }, + /* 4561 */ { MAD_F(0x049ddcaf) /* 0.288540541 */, 18 }, + /* 4562 */ { MAD_F(0x049e3523) /* 0.288624894 */, 18 }, + /* 4563 */ { MAD_F(0x049e8d98) /* 0.288709253 */, 18 }, + /* 4564 */ { MAD_F(0x049ee60e) /* 0.288793619 */, 18 }, + /* 4565 */ { MAD_F(0x049f3e87) /* 0.288877990 */, 18 }, + /* 4566 */ { MAD_F(0x049f9701) /* 0.288962368 */, 18 }, + /* 4567 */ { MAD_F(0x049fef7c) /* 0.289046752 */, 18 }, + /* 4568 */ { MAD_F(0x04a047fa) /* 0.289131142 */, 18 }, + /* 4569 */ { MAD_F(0x04a0a079) /* 0.289215538 */, 18 }, + /* 4570 */ { MAD_F(0x04a0f8f9) /* 0.289299941 */, 18 }, + /* 4571 */ { MAD_F(0x04a1517c) /* 0.289384349 */, 18 }, + /* 4572 */ { MAD_F(0x04a1a9ff) /* 0.289468764 */, 18 }, + /* 4573 */ { MAD_F(0x04a20285) /* 0.289553185 */, 18 }, + /* 4574 */ { MAD_F(0x04a25b0c) /* 0.289637612 */, 18 }, + /* 4575 */ { MAD_F(0x04a2b395) /* 0.289722045 */, 18 }, + + /* 4576 */ { MAD_F(0x04a30c20) /* 0.289806485 */, 18 }, + /* 4577 */ { MAD_F(0x04a364ac) /* 0.289890930 */, 18 }, + /* 4578 */ { MAD_F(0x04a3bd3a) /* 0.289975382 */, 18 }, + /* 4579 */ { MAD_F(0x04a415c9) /* 0.290059840 */, 18 }, + /* 4580 */ { MAD_F(0x04a46e5a) /* 0.290144304 */, 18 }, + /* 4581 */ { MAD_F(0x04a4c6ed) /* 0.290228774 */, 18 }, + /* 4582 */ { MAD_F(0x04a51f81) /* 0.290313250 */, 18 }, + /* 4583 */ { MAD_F(0x04a57818) /* 0.290397733 */, 18 }, + /* 4584 */ { MAD_F(0x04a5d0af) /* 0.290482221 */, 18 }, + /* 4585 */ { MAD_F(0x04a62949) /* 0.290566716 */, 18 }, + /* 4586 */ { MAD_F(0x04a681e4) /* 0.290651217 */, 18 }, + /* 4587 */ { MAD_F(0x04a6da80) /* 0.290735724 */, 18 }, + /* 4588 */ { MAD_F(0x04a7331f) /* 0.290820237 */, 18 }, + /* 4589 */ { MAD_F(0x04a78bbf) /* 0.290904756 */, 18 }, + /* 4590 */ { MAD_F(0x04a7e460) /* 0.290989281 */, 18 }, + /* 4591 */ { MAD_F(0x04a83d03) /* 0.291073813 */, 18 }, + + /* 4592 */ { MAD_F(0x04a895a8) /* 0.291158351 */, 18 }, + /* 4593 */ { MAD_F(0x04a8ee4f) /* 0.291242894 */, 18 }, + /* 4594 */ { MAD_F(0x04a946f7) /* 0.291327444 */, 18 }, + /* 4595 */ { MAD_F(0x04a99fa1) /* 0.291412001 */, 18 }, + /* 4596 */ { MAD_F(0x04a9f84c) /* 0.291496563 */, 18 }, + /* 4597 */ { MAD_F(0x04aa50fa) /* 0.291581131 */, 18 }, + /* 4598 */ { MAD_F(0x04aaa9a8) /* 0.291665706 */, 18 }, + /* 4599 */ { MAD_F(0x04ab0259) /* 0.291750286 */, 18 }, + /* 4600 */ { MAD_F(0x04ab5b0b) /* 0.291834873 */, 18 }, + /* 4601 */ { MAD_F(0x04abb3bf) /* 0.291919466 */, 18 }, + /* 4602 */ { MAD_F(0x04ac0c74) /* 0.292004065 */, 18 }, + /* 4603 */ { MAD_F(0x04ac652b) /* 0.292088670 */, 18 }, + /* 4604 */ { MAD_F(0x04acbde4) /* 0.292173281 */, 18 }, + /* 4605 */ { MAD_F(0x04ad169e) /* 0.292257899 */, 18 }, + /* 4606 */ { MAD_F(0x04ad6f5a) /* 0.292342522 */, 18 }, + /* 4607 */ { MAD_F(0x04adc818) /* 0.292427152 */, 18 }, + + /* 4608 */ { MAD_F(0x04ae20d7) /* 0.292511788 */, 18 }, + /* 4609 */ { MAD_F(0x04ae7998) /* 0.292596430 */, 18 }, + /* 4610 */ { MAD_F(0x04aed25a) /* 0.292681078 */, 18 }, + /* 4611 */ { MAD_F(0x04af2b1e) /* 0.292765732 */, 18 }, + /* 4612 */ { MAD_F(0x04af83e4) /* 0.292850392 */, 18 }, + /* 4613 */ { MAD_F(0x04afdcac) /* 0.292935058 */, 18 }, + /* 4614 */ { MAD_F(0x04b03575) /* 0.293019731 */, 18 }, + /* 4615 */ { MAD_F(0x04b08e40) /* 0.293104409 */, 18 }, + /* 4616 */ { MAD_F(0x04b0e70c) /* 0.293189094 */, 18 }, + /* 4617 */ { MAD_F(0x04b13fda) /* 0.293273785 */, 18 }, + /* 4618 */ { MAD_F(0x04b198aa) /* 0.293358482 */, 18 }, + /* 4619 */ { MAD_F(0x04b1f17b) /* 0.293443185 */, 18 }, + /* 4620 */ { MAD_F(0x04b24a4e) /* 0.293527894 */, 18 }, + /* 4621 */ { MAD_F(0x04b2a322) /* 0.293612609 */, 18 }, + /* 4622 */ { MAD_F(0x04b2fbf9) /* 0.293697331 */, 18 }, + /* 4623 */ { MAD_F(0x04b354d1) /* 0.293782058 */, 18 }, + + /* 4624 */ { MAD_F(0x04b3adaa) /* 0.293866792 */, 18 }, + /* 4625 */ { MAD_F(0x04b40685) /* 0.293951532 */, 18 }, + /* 4626 */ { MAD_F(0x04b45f62) /* 0.294036278 */, 18 }, + /* 4627 */ { MAD_F(0x04b4b840) /* 0.294121029 */, 18 }, + /* 4628 */ { MAD_F(0x04b51120) /* 0.294205788 */, 18 }, + /* 4629 */ { MAD_F(0x04b56a02) /* 0.294290552 */, 18 }, + /* 4630 */ { MAD_F(0x04b5c2e6) /* 0.294375322 */, 18 }, + /* 4631 */ { MAD_F(0x04b61bcb) /* 0.294460098 */, 18 }, + /* 4632 */ { MAD_F(0x04b674b1) /* 0.294544881 */, 18 }, + /* 4633 */ { MAD_F(0x04b6cd99) /* 0.294629669 */, 18 }, + /* 4634 */ { MAD_F(0x04b72683) /* 0.294714464 */, 18 }, + /* 4635 */ { MAD_F(0x04b77f6f) /* 0.294799265 */, 18 }, + /* 4636 */ { MAD_F(0x04b7d85c) /* 0.294884072 */, 18 }, + /* 4637 */ { MAD_F(0x04b8314b) /* 0.294968885 */, 18 }, + /* 4638 */ { MAD_F(0x04b88a3b) /* 0.295053704 */, 18 }, + /* 4639 */ { MAD_F(0x04b8e32d) /* 0.295138529 */, 18 }, + + /* 4640 */ { MAD_F(0x04b93c21) /* 0.295223360 */, 18 }, + /* 4641 */ { MAD_F(0x04b99516) /* 0.295308197 */, 18 }, + /* 4642 */ { MAD_F(0x04b9ee0d) /* 0.295393041 */, 18 }, + /* 4643 */ { MAD_F(0x04ba4706) /* 0.295477890 */, 18 }, + /* 4644 */ { MAD_F(0x04baa000) /* 0.295562746 */, 18 }, + /* 4645 */ { MAD_F(0x04baf8fc) /* 0.295647608 */, 18 }, + /* 4646 */ { MAD_F(0x04bb51fa) /* 0.295732476 */, 18 }, + /* 4647 */ { MAD_F(0x04bbaaf9) /* 0.295817349 */, 18 }, + /* 4648 */ { MAD_F(0x04bc03fa) /* 0.295902229 */, 18 }, + /* 4649 */ { MAD_F(0x04bc5cfc) /* 0.295987115 */, 18 }, + /* 4650 */ { MAD_F(0x04bcb600) /* 0.296072008 */, 18 }, + /* 4651 */ { MAD_F(0x04bd0f06) /* 0.296156906 */, 18 }, + /* 4652 */ { MAD_F(0x04bd680d) /* 0.296241810 */, 18 }, + /* 4653 */ { MAD_F(0x04bdc116) /* 0.296326721 */, 18 }, + /* 4654 */ { MAD_F(0x04be1a21) /* 0.296411637 */, 18 }, + /* 4655 */ { MAD_F(0x04be732d) /* 0.296496560 */, 18 }, + + /* 4656 */ { MAD_F(0x04becc3b) /* 0.296581488 */, 18 }, + /* 4657 */ { MAD_F(0x04bf254a) /* 0.296666423 */, 18 }, + /* 4658 */ { MAD_F(0x04bf7e5b) /* 0.296751364 */, 18 }, + /* 4659 */ { MAD_F(0x04bfd76e) /* 0.296836311 */, 18 }, + /* 4660 */ { MAD_F(0x04c03083) /* 0.296921264 */, 18 }, + /* 4661 */ { MAD_F(0x04c08999) /* 0.297006223 */, 18 }, + /* 4662 */ { MAD_F(0x04c0e2b0) /* 0.297091188 */, 18 }, + /* 4663 */ { MAD_F(0x04c13bca) /* 0.297176159 */, 18 }, + /* 4664 */ { MAD_F(0x04c194e4) /* 0.297261136 */, 18 }, + /* 4665 */ { MAD_F(0x04c1ee01) /* 0.297346120 */, 18 }, + /* 4666 */ { MAD_F(0x04c2471f) /* 0.297431109 */, 18 }, + /* 4667 */ { MAD_F(0x04c2a03f) /* 0.297516105 */, 18 }, + /* 4668 */ { MAD_F(0x04c2f960) /* 0.297601106 */, 18 }, + /* 4669 */ { MAD_F(0x04c35283) /* 0.297686114 */, 18 }, + /* 4670 */ { MAD_F(0x04c3aba8) /* 0.297771128 */, 18 }, + /* 4671 */ { MAD_F(0x04c404ce) /* 0.297856147 */, 18 }, + + /* 4672 */ { MAD_F(0x04c45df6) /* 0.297941173 */, 18 }, + /* 4673 */ { MAD_F(0x04c4b720) /* 0.298026205 */, 18 }, + /* 4674 */ { MAD_F(0x04c5104b) /* 0.298111243 */, 18 }, + /* 4675 */ { MAD_F(0x04c56978) /* 0.298196287 */, 18 }, + /* 4676 */ { MAD_F(0x04c5c2a7) /* 0.298281337 */, 18 }, + /* 4677 */ { MAD_F(0x04c61bd7) /* 0.298366393 */, 18 }, + /* 4678 */ { MAD_F(0x04c67508) /* 0.298451456 */, 18 }, + /* 4679 */ { MAD_F(0x04c6ce3c) /* 0.298536524 */, 18 }, + /* 4680 */ { MAD_F(0x04c72771) /* 0.298621598 */, 18 }, + /* 4681 */ { MAD_F(0x04c780a7) /* 0.298706679 */, 18 }, + /* 4682 */ { MAD_F(0x04c7d9df) /* 0.298791765 */, 18 }, + /* 4683 */ { MAD_F(0x04c83319) /* 0.298876858 */, 18 }, + /* 4684 */ { MAD_F(0x04c88c55) /* 0.298961956 */, 18 }, + /* 4685 */ { MAD_F(0x04c8e592) /* 0.299047061 */, 18 }, + /* 4686 */ { MAD_F(0x04c93ed1) /* 0.299132172 */, 18 }, + /* 4687 */ { MAD_F(0x04c99811) /* 0.299217288 */, 18 }, + + /* 4688 */ { MAD_F(0x04c9f153) /* 0.299302411 */, 18 }, + /* 4689 */ { MAD_F(0x04ca4a97) /* 0.299387540 */, 18 }, + /* 4690 */ { MAD_F(0x04caa3dc) /* 0.299472675 */, 18 }, + /* 4691 */ { MAD_F(0x04cafd23) /* 0.299557816 */, 18 }, + /* 4692 */ { MAD_F(0x04cb566b) /* 0.299642963 */, 18 }, + /* 4693 */ { MAD_F(0x04cbafb5) /* 0.299728116 */, 18 }, + /* 4694 */ { MAD_F(0x04cc0901) /* 0.299813275 */, 18 }, + /* 4695 */ { MAD_F(0x04cc624e) /* 0.299898440 */, 18 }, + /* 4696 */ { MAD_F(0x04ccbb9d) /* 0.299983611 */, 18 }, + /* 4697 */ { MAD_F(0x04cd14ee) /* 0.300068789 */, 18 }, + /* 4698 */ { MAD_F(0x04cd6e40) /* 0.300153972 */, 18 }, + /* 4699 */ { MAD_F(0x04cdc794) /* 0.300239161 */, 18 }, + /* 4700 */ { MAD_F(0x04ce20e9) /* 0.300324357 */, 18 }, + /* 4701 */ { MAD_F(0x04ce7a40) /* 0.300409558 */, 18 }, + /* 4702 */ { MAD_F(0x04ced399) /* 0.300494765 */, 18 }, + /* 4703 */ { MAD_F(0x04cf2cf3) /* 0.300579979 */, 18 }, + + /* 4704 */ { MAD_F(0x04cf864f) /* 0.300665198 */, 18 }, + /* 4705 */ { MAD_F(0x04cfdfad) /* 0.300750424 */, 18 }, + /* 4706 */ { MAD_F(0x04d0390c) /* 0.300835656 */, 18 }, + /* 4707 */ { MAD_F(0x04d0926d) /* 0.300920893 */, 18 }, + /* 4708 */ { MAD_F(0x04d0ebcf) /* 0.301006137 */, 18 }, + /* 4709 */ { MAD_F(0x04d14533) /* 0.301091387 */, 18 }, + /* 4710 */ { MAD_F(0x04d19e99) /* 0.301176643 */, 18 }, + /* 4711 */ { MAD_F(0x04d1f800) /* 0.301261904 */, 18 }, + /* 4712 */ { MAD_F(0x04d25169) /* 0.301347172 */, 18 }, + /* 4713 */ { MAD_F(0x04d2aad4) /* 0.301432446 */, 18 }, + /* 4714 */ { MAD_F(0x04d30440) /* 0.301517726 */, 18 }, + /* 4715 */ { MAD_F(0x04d35dae) /* 0.301603012 */, 18 }, + /* 4716 */ { MAD_F(0x04d3b71d) /* 0.301688304 */, 18 }, + /* 4717 */ { MAD_F(0x04d4108e) /* 0.301773602 */, 18 }, + /* 4718 */ { MAD_F(0x04d46a01) /* 0.301858906 */, 18 }, + /* 4719 */ { MAD_F(0x04d4c375) /* 0.301944216 */, 18 }, + + /* 4720 */ { MAD_F(0x04d51ceb) /* 0.302029532 */, 18 }, + /* 4721 */ { MAD_F(0x04d57662) /* 0.302114854 */, 18 }, + /* 4722 */ { MAD_F(0x04d5cfdb) /* 0.302200182 */, 18 }, + /* 4723 */ { MAD_F(0x04d62956) /* 0.302285516 */, 18 }, + /* 4724 */ { MAD_F(0x04d682d2) /* 0.302370856 */, 18 }, + /* 4725 */ { MAD_F(0x04d6dc50) /* 0.302456203 */, 18 }, + /* 4726 */ { MAD_F(0x04d735d0) /* 0.302541555 */, 18 }, + /* 4727 */ { MAD_F(0x04d78f51) /* 0.302626913 */, 18 }, + /* 4728 */ { MAD_F(0x04d7e8d4) /* 0.302712277 */, 18 }, + /* 4729 */ { MAD_F(0x04d84258) /* 0.302797648 */, 18 }, + /* 4730 */ { MAD_F(0x04d89bde) /* 0.302883024 */, 18 }, + /* 4731 */ { MAD_F(0x04d8f566) /* 0.302968406 */, 18 }, + /* 4732 */ { MAD_F(0x04d94eef) /* 0.303053794 */, 18 }, + /* 4733 */ { MAD_F(0x04d9a87a) /* 0.303139189 */, 18 }, + /* 4734 */ { MAD_F(0x04da0207) /* 0.303224589 */, 18 }, + /* 4735 */ { MAD_F(0x04da5b95) /* 0.303309995 */, 18 }, + + /* 4736 */ { MAD_F(0x04dab524) /* 0.303395408 */, 18 }, + /* 4737 */ { MAD_F(0x04db0eb6) /* 0.303480826 */, 18 }, + /* 4738 */ { MAD_F(0x04db6849) /* 0.303566251 */, 18 }, + /* 4739 */ { MAD_F(0x04dbc1dd) /* 0.303651681 */, 18 }, + /* 4740 */ { MAD_F(0x04dc1b73) /* 0.303737117 */, 18 }, + /* 4741 */ { MAD_F(0x04dc750b) /* 0.303822560 */, 18 }, + /* 4742 */ { MAD_F(0x04dccea5) /* 0.303908008 */, 18 }, + /* 4743 */ { MAD_F(0x04dd2840) /* 0.303993463 */, 18 }, + /* 4744 */ { MAD_F(0x04dd81dc) /* 0.304078923 */, 18 }, + /* 4745 */ { MAD_F(0x04dddb7a) /* 0.304164390 */, 18 }, + /* 4746 */ { MAD_F(0x04de351a) /* 0.304249862 */, 18 }, + /* 4747 */ { MAD_F(0x04de8ebc) /* 0.304335340 */, 18 }, + /* 4748 */ { MAD_F(0x04dee85f) /* 0.304420825 */, 18 }, + /* 4749 */ { MAD_F(0x04df4203) /* 0.304506315 */, 18 }, + /* 4750 */ { MAD_F(0x04df9baa) /* 0.304591812 */, 18 }, + /* 4751 */ { MAD_F(0x04dff552) /* 0.304677314 */, 18 }, + + /* 4752 */ { MAD_F(0x04e04efb) /* 0.304762823 */, 18 }, + /* 4753 */ { MAD_F(0x04e0a8a6) /* 0.304848337 */, 18 }, + /* 4754 */ { MAD_F(0x04e10253) /* 0.304933858 */, 18 }, + /* 4755 */ { MAD_F(0x04e15c01) /* 0.305019384 */, 18 }, + /* 4756 */ { MAD_F(0x04e1b5b1) /* 0.305104917 */, 18 }, + /* 4757 */ { MAD_F(0x04e20f63) /* 0.305190455 */, 18 }, + /* 4758 */ { MAD_F(0x04e26916) /* 0.305275999 */, 18 }, + /* 4759 */ { MAD_F(0x04e2c2cb) /* 0.305361550 */, 18 }, + /* 4760 */ { MAD_F(0x04e31c81) /* 0.305447106 */, 18 }, + /* 4761 */ { MAD_F(0x04e37639) /* 0.305532669 */, 18 }, + /* 4762 */ { MAD_F(0x04e3cff3) /* 0.305618237 */, 18 }, + /* 4763 */ { MAD_F(0x04e429ae) /* 0.305703811 */, 18 }, + /* 4764 */ { MAD_F(0x04e4836b) /* 0.305789392 */, 18 }, + /* 4765 */ { MAD_F(0x04e4dd29) /* 0.305874978 */, 18 }, + /* 4766 */ { MAD_F(0x04e536e9) /* 0.305960571 */, 18 }, + /* 4767 */ { MAD_F(0x04e590ab) /* 0.306046169 */, 18 }, + + /* 4768 */ { MAD_F(0x04e5ea6e) /* 0.306131773 */, 18 }, + /* 4769 */ { MAD_F(0x04e64433) /* 0.306217383 */, 18 }, + /* 4770 */ { MAD_F(0x04e69df9) /* 0.306303000 */, 18 }, + /* 4771 */ { MAD_F(0x04e6f7c1) /* 0.306388622 */, 18 }, + /* 4772 */ { MAD_F(0x04e7518b) /* 0.306474250 */, 18 }, + /* 4773 */ { MAD_F(0x04e7ab56) /* 0.306559885 */, 18 }, + /* 4774 */ { MAD_F(0x04e80523) /* 0.306645525 */, 18 }, + /* 4775 */ { MAD_F(0x04e85ef2) /* 0.306731171 */, 18 }, + /* 4776 */ { MAD_F(0x04e8b8c2) /* 0.306816823 */, 18 }, + /* 4777 */ { MAD_F(0x04e91293) /* 0.306902481 */, 18 }, + /* 4778 */ { MAD_F(0x04e96c67) /* 0.306988145 */, 18 }, + /* 4779 */ { MAD_F(0x04e9c63b) /* 0.307073816 */, 18 }, + /* 4780 */ { MAD_F(0x04ea2012) /* 0.307159492 */, 18 }, + /* 4781 */ { MAD_F(0x04ea79ea) /* 0.307245174 */, 18 }, + /* 4782 */ { MAD_F(0x04ead3c4) /* 0.307330862 */, 18 }, + /* 4783 */ { MAD_F(0x04eb2d9f) /* 0.307416556 */, 18 }, + + /* 4784 */ { MAD_F(0x04eb877c) /* 0.307502256 */, 18 }, + /* 4785 */ { MAD_F(0x04ebe15b) /* 0.307587962 */, 18 }, + /* 4786 */ { MAD_F(0x04ec3b3b) /* 0.307673674 */, 18 }, + /* 4787 */ { MAD_F(0x04ec951c) /* 0.307759392 */, 18 }, + /* 4788 */ { MAD_F(0x04ecef00) /* 0.307845115 */, 18 }, + /* 4789 */ { MAD_F(0x04ed48e5) /* 0.307930845 */, 18 }, + /* 4790 */ { MAD_F(0x04eda2cb) /* 0.308016581 */, 18 }, + /* 4791 */ { MAD_F(0x04edfcb3) /* 0.308102323 */, 18 }, + /* 4792 */ { MAD_F(0x04ee569d) /* 0.308188071 */, 18 }, + /* 4793 */ { MAD_F(0x04eeb088) /* 0.308273824 */, 18 }, + /* 4794 */ { MAD_F(0x04ef0a75) /* 0.308359584 */, 18 }, + /* 4795 */ { MAD_F(0x04ef6464) /* 0.308445350 */, 18 }, + /* 4796 */ { MAD_F(0x04efbe54) /* 0.308531121 */, 18 }, + /* 4797 */ { MAD_F(0x04f01846) /* 0.308616899 */, 18 }, + /* 4798 */ { MAD_F(0x04f07239) /* 0.308702682 */, 18 }, + /* 4799 */ { MAD_F(0x04f0cc2e) /* 0.308788472 */, 18 }, + + /* 4800 */ { MAD_F(0x04f12624) /* 0.308874267 */, 18 }, + /* 4801 */ { MAD_F(0x04f1801d) /* 0.308960068 */, 18 }, + /* 4802 */ { MAD_F(0x04f1da16) /* 0.309045876 */, 18 }, + /* 4803 */ { MAD_F(0x04f23412) /* 0.309131689 */, 18 }, + /* 4804 */ { MAD_F(0x04f28e0f) /* 0.309217508 */, 18 }, + /* 4805 */ { MAD_F(0x04f2e80d) /* 0.309303334 */, 18 }, + /* 4806 */ { MAD_F(0x04f3420d) /* 0.309389165 */, 18 }, + /* 4807 */ { MAD_F(0x04f39c0f) /* 0.309475002 */, 18 }, + /* 4808 */ { MAD_F(0x04f3f612) /* 0.309560845 */, 18 }, + /* 4809 */ { MAD_F(0x04f45017) /* 0.309646694 */, 18 }, + /* 4810 */ { MAD_F(0x04f4aa1e) /* 0.309732549 */, 18 }, + /* 4811 */ { MAD_F(0x04f50426) /* 0.309818410 */, 18 }, + /* 4812 */ { MAD_F(0x04f55e30) /* 0.309904277 */, 18 }, + /* 4813 */ { MAD_F(0x04f5b83b) /* 0.309990150 */, 18 }, + /* 4814 */ { MAD_F(0x04f61248) /* 0.310076028 */, 18 }, + /* 4815 */ { MAD_F(0x04f66c56) /* 0.310161913 */, 18 }, + + /* 4816 */ { MAD_F(0x04f6c666) /* 0.310247804 */, 18 }, + /* 4817 */ { MAD_F(0x04f72078) /* 0.310333700 */, 18 }, + /* 4818 */ { MAD_F(0x04f77a8b) /* 0.310419603 */, 18 }, + /* 4819 */ { MAD_F(0x04f7d4a0) /* 0.310505511 */, 18 }, + /* 4820 */ { MAD_F(0x04f82eb7) /* 0.310591426 */, 18 }, + /* 4821 */ { MAD_F(0x04f888cf) /* 0.310677346 */, 18 }, + /* 4822 */ { MAD_F(0x04f8e2e9) /* 0.310763272 */, 18 }, + /* 4823 */ { MAD_F(0x04f93d04) /* 0.310849205 */, 18 }, + /* 4824 */ { MAD_F(0x04f99721) /* 0.310935143 */, 18 }, + /* 4825 */ { MAD_F(0x04f9f13f) /* 0.311021087 */, 18 }, + /* 4826 */ { MAD_F(0x04fa4b5f) /* 0.311107037 */, 18 }, + /* 4827 */ { MAD_F(0x04faa581) /* 0.311192993 */, 18 }, + /* 4828 */ { MAD_F(0x04faffa4) /* 0.311278955 */, 18 }, + /* 4829 */ { MAD_F(0x04fb59c9) /* 0.311364923 */, 18 }, + /* 4830 */ { MAD_F(0x04fbb3ef) /* 0.311450897 */, 18 }, + /* 4831 */ { MAD_F(0x04fc0e17) /* 0.311536877 */, 18 }, + + /* 4832 */ { MAD_F(0x04fc6841) /* 0.311622862 */, 18 }, + /* 4833 */ { MAD_F(0x04fcc26c) /* 0.311708854 */, 18 }, + /* 4834 */ { MAD_F(0x04fd1c99) /* 0.311794851 */, 18 }, + /* 4835 */ { MAD_F(0x04fd76c7) /* 0.311880855 */, 18 }, + /* 4836 */ { MAD_F(0x04fdd0f7) /* 0.311966864 */, 18 }, + /* 4837 */ { MAD_F(0x04fe2b29) /* 0.312052880 */, 18 }, + /* 4838 */ { MAD_F(0x04fe855c) /* 0.312138901 */, 18 }, + /* 4839 */ { MAD_F(0x04fedf91) /* 0.312224928 */, 18 }, + /* 4840 */ { MAD_F(0x04ff39c7) /* 0.312310961 */, 18 }, + /* 4841 */ { MAD_F(0x04ff93ff) /* 0.312397000 */, 18 }, + /* 4842 */ { MAD_F(0x04ffee38) /* 0.312483045 */, 18 }, + /* 4843 */ { MAD_F(0x05004874) /* 0.312569096 */, 18 }, + /* 4844 */ { MAD_F(0x0500a2b0) /* 0.312655153 */, 18 }, + /* 4845 */ { MAD_F(0x0500fcef) /* 0.312741216 */, 18 }, + /* 4846 */ { MAD_F(0x0501572e) /* 0.312827284 */, 18 }, + /* 4847 */ { MAD_F(0x0501b170) /* 0.312913359 */, 18 }, + + /* 4848 */ { MAD_F(0x05020bb3) /* 0.312999439 */, 18 }, + /* 4849 */ { MAD_F(0x050265f8) /* 0.313085526 */, 18 }, + /* 4850 */ { MAD_F(0x0502c03e) /* 0.313171618 */, 18 }, + /* 4851 */ { MAD_F(0x05031a86) /* 0.313257716 */, 18 }, + /* 4852 */ { MAD_F(0x050374cf) /* 0.313343820 */, 18 }, + /* 4853 */ { MAD_F(0x0503cf1a) /* 0.313429931 */, 18 }, + /* 4854 */ { MAD_F(0x05042967) /* 0.313516047 */, 18 }, + /* 4855 */ { MAD_F(0x050483b5) /* 0.313602168 */, 18 }, + /* 4856 */ { MAD_F(0x0504de05) /* 0.313688296 */, 18 }, + /* 4857 */ { MAD_F(0x05053856) /* 0.313774430 */, 18 }, + /* 4858 */ { MAD_F(0x050592a9) /* 0.313860570 */, 18 }, + /* 4859 */ { MAD_F(0x0505ecfd) /* 0.313946715 */, 18 }, + /* 4860 */ { MAD_F(0x05064754) /* 0.314032867 */, 18 }, + /* 4861 */ { MAD_F(0x0506a1ab) /* 0.314119024 */, 18 }, + /* 4862 */ { MAD_F(0x0506fc04) /* 0.314205187 */, 18 }, + /* 4863 */ { MAD_F(0x0507565f) /* 0.314291357 */, 18 }, + + /* 4864 */ { MAD_F(0x0507b0bc) /* 0.314377532 */, 18 }, + /* 4865 */ { MAD_F(0x05080b1a) /* 0.314463713 */, 18 }, + /* 4866 */ { MAD_F(0x05086579) /* 0.314549900 */, 18 }, + /* 4867 */ { MAD_F(0x0508bfdb) /* 0.314636092 */, 18 }, + /* 4868 */ { MAD_F(0x05091a3d) /* 0.314722291 */, 18 }, + /* 4869 */ { MAD_F(0x050974a2) /* 0.314808496 */, 18 }, + /* 4870 */ { MAD_F(0x0509cf08) /* 0.314894706 */, 18 }, + /* 4871 */ { MAD_F(0x050a296f) /* 0.314980923 */, 18 }, + /* 4872 */ { MAD_F(0x050a83d8) /* 0.315067145 */, 18 }, + /* 4873 */ { MAD_F(0x050ade43) /* 0.315153373 */, 18 }, + /* 4874 */ { MAD_F(0x050b38af) /* 0.315239607 */, 18 }, + /* 4875 */ { MAD_F(0x050b931d) /* 0.315325847 */, 18 }, + /* 4876 */ { MAD_F(0x050bed8d) /* 0.315412093 */, 18 }, + /* 4877 */ { MAD_F(0x050c47fe) /* 0.315498345 */, 18 }, + /* 4878 */ { MAD_F(0x050ca271) /* 0.315584603 */, 18 }, + /* 4879 */ { MAD_F(0x050cfce5) /* 0.315670866 */, 18 }, + + /* 4880 */ { MAD_F(0x050d575b) /* 0.315757136 */, 18 }, + /* 4881 */ { MAD_F(0x050db1d2) /* 0.315843411 */, 18 }, + /* 4882 */ { MAD_F(0x050e0c4b) /* 0.315929693 */, 18 }, + /* 4883 */ { MAD_F(0x050e66c5) /* 0.316015980 */, 18 }, + /* 4884 */ { MAD_F(0x050ec141) /* 0.316102273 */, 18 }, + /* 4885 */ { MAD_F(0x050f1bbf) /* 0.316188572 */, 18 }, + /* 4886 */ { MAD_F(0x050f763e) /* 0.316274877 */, 18 }, + /* 4887 */ { MAD_F(0x050fd0bf) /* 0.316361187 */, 18 }, + /* 4888 */ { MAD_F(0x05102b42) /* 0.316447504 */, 18 }, + /* 4889 */ { MAD_F(0x051085c6) /* 0.316533826 */, 18 }, + /* 4890 */ { MAD_F(0x0510e04b) /* 0.316620155 */, 18 }, + /* 4891 */ { MAD_F(0x05113ad3) /* 0.316706489 */, 18 }, + /* 4892 */ { MAD_F(0x0511955b) /* 0.316792829 */, 18 }, + /* 4893 */ { MAD_F(0x0511efe6) /* 0.316879175 */, 18 }, + /* 4894 */ { MAD_F(0x05124a72) /* 0.316965527 */, 18 }, + /* 4895 */ { MAD_F(0x0512a4ff) /* 0.317051885 */, 18 }, + + /* 4896 */ { MAD_F(0x0512ff8e) /* 0.317138249 */, 18 }, + /* 4897 */ { MAD_F(0x05135a1f) /* 0.317224618 */, 18 }, + /* 4898 */ { MAD_F(0x0513b4b1) /* 0.317310994 */, 18 }, + /* 4899 */ { MAD_F(0x05140f45) /* 0.317397375 */, 18 }, + /* 4900 */ { MAD_F(0x051469da) /* 0.317483762 */, 18 }, + /* 4901 */ { MAD_F(0x0514c471) /* 0.317570155 */, 18 }, + /* 4902 */ { MAD_F(0x05151f0a) /* 0.317656554 */, 18 }, + /* 4903 */ { MAD_F(0x051579a4) /* 0.317742959 */, 18 }, + /* 4904 */ { MAD_F(0x0515d440) /* 0.317829370 */, 18 }, + /* 4905 */ { MAD_F(0x05162edd) /* 0.317915786 */, 18 }, + /* 4906 */ { MAD_F(0x0516897c) /* 0.318002209 */, 18 }, + /* 4907 */ { MAD_F(0x0516e41c) /* 0.318088637 */, 18 }, + /* 4908 */ { MAD_F(0x05173ebe) /* 0.318175071 */, 18 }, + /* 4909 */ { MAD_F(0x05179962) /* 0.318261511 */, 18 }, + /* 4910 */ { MAD_F(0x0517f407) /* 0.318347957 */, 18 }, + /* 4911 */ { MAD_F(0x05184eae) /* 0.318434409 */, 18 }, + + /* 4912 */ { MAD_F(0x0518a956) /* 0.318520867 */, 18 }, + /* 4913 */ { MAD_F(0x05190400) /* 0.318607330 */, 18 }, + /* 4914 */ { MAD_F(0x05195eab) /* 0.318693800 */, 18 }, + /* 4915 */ { MAD_F(0x0519b958) /* 0.318780275 */, 18 }, + /* 4916 */ { MAD_F(0x051a1407) /* 0.318866756 */, 18 }, + /* 4917 */ { MAD_F(0x051a6eb7) /* 0.318953243 */, 18 }, + /* 4918 */ { MAD_F(0x051ac969) /* 0.319039736 */, 18 }, + /* 4919 */ { MAD_F(0x051b241c) /* 0.319126235 */, 18 }, + /* 4920 */ { MAD_F(0x051b7ed1) /* 0.319212739 */, 18 }, + /* 4921 */ { MAD_F(0x051bd987) /* 0.319299250 */, 18 }, + /* 4922 */ { MAD_F(0x051c3440) /* 0.319385766 */, 18 }, + /* 4923 */ { MAD_F(0x051c8ef9) /* 0.319472288 */, 18 }, + /* 4924 */ { MAD_F(0x051ce9b4) /* 0.319558816 */, 18 }, + /* 4925 */ { MAD_F(0x051d4471) /* 0.319645350 */, 18 }, + /* 4926 */ { MAD_F(0x051d9f2f) /* 0.319731890 */, 18 }, + /* 4927 */ { MAD_F(0x051df9ef) /* 0.319818435 */, 18 }, + + /* 4928 */ { MAD_F(0x051e54b1) /* 0.319904987 */, 18 }, + /* 4929 */ { MAD_F(0x051eaf74) /* 0.319991544 */, 18 }, + /* 4930 */ { MAD_F(0x051f0a38) /* 0.320078107 */, 18 }, + /* 4931 */ { MAD_F(0x051f64ff) /* 0.320164676 */, 18 }, + /* 4932 */ { MAD_F(0x051fbfc6) /* 0.320251251 */, 18 }, + /* 4933 */ { MAD_F(0x05201a90) /* 0.320337832 */, 18 }, + /* 4934 */ { MAD_F(0x0520755b) /* 0.320424419 */, 18 }, + /* 4935 */ { MAD_F(0x0520d027) /* 0.320511011 */, 18 }, + /* 4936 */ { MAD_F(0x05212af5) /* 0.320597609 */, 18 }, + /* 4937 */ { MAD_F(0x052185c5) /* 0.320684213 */, 18 }, + /* 4938 */ { MAD_F(0x0521e096) /* 0.320770823 */, 18 }, + /* 4939 */ { MAD_F(0x05223b69) /* 0.320857439 */, 18 }, + /* 4940 */ { MAD_F(0x0522963d) /* 0.320944061 */, 18 }, + /* 4941 */ { MAD_F(0x0522f113) /* 0.321030688 */, 18 }, + /* 4942 */ { MAD_F(0x05234bea) /* 0.321117322 */, 18 }, + /* 4943 */ { MAD_F(0x0523a6c3) /* 0.321203961 */, 18 }, + + /* 4944 */ { MAD_F(0x0524019e) /* 0.321290606 */, 18 }, + /* 4945 */ { MAD_F(0x05245c7a) /* 0.321377257 */, 18 }, + /* 4946 */ { MAD_F(0x0524b758) /* 0.321463913 */, 18 }, + /* 4947 */ { MAD_F(0x05251237) /* 0.321550576 */, 18 }, + /* 4948 */ { MAD_F(0x05256d18) /* 0.321637244 */, 18 }, + /* 4949 */ { MAD_F(0x0525c7fb) /* 0.321723919 */, 18 }, + /* 4950 */ { MAD_F(0x052622df) /* 0.321810599 */, 18 }, + /* 4951 */ { MAD_F(0x05267dc4) /* 0.321897285 */, 18 }, + /* 4952 */ { MAD_F(0x0526d8ab) /* 0.321983976 */, 18 }, + /* 4953 */ { MAD_F(0x05273394) /* 0.322070674 */, 18 }, + /* 4954 */ { MAD_F(0x05278e7e) /* 0.322157377 */, 18 }, + /* 4955 */ { MAD_F(0x0527e96a) /* 0.322244087 */, 18 }, + /* 4956 */ { MAD_F(0x05284457) /* 0.322330802 */, 18 }, + /* 4957 */ { MAD_F(0x05289f46) /* 0.322417523 */, 18 }, + /* 4958 */ { MAD_F(0x0528fa37) /* 0.322504249 */, 18 }, + /* 4959 */ { MAD_F(0x05295529) /* 0.322590982 */, 18 }, + + /* 4960 */ { MAD_F(0x0529b01d) /* 0.322677720 */, 18 }, + /* 4961 */ { MAD_F(0x052a0b12) /* 0.322764465 */, 18 }, + /* 4962 */ { MAD_F(0x052a6609) /* 0.322851215 */, 18 }, + /* 4963 */ { MAD_F(0x052ac101) /* 0.322937971 */, 18 }, + /* 4964 */ { MAD_F(0x052b1bfb) /* 0.323024732 */, 18 }, + /* 4965 */ { MAD_F(0x052b76f7) /* 0.323111500 */, 18 }, + /* 4966 */ { MAD_F(0x052bd1f4) /* 0.323198273 */, 18 }, + /* 4967 */ { MAD_F(0x052c2cf2) /* 0.323285052 */, 18 }, + /* 4968 */ { MAD_F(0x052c87f2) /* 0.323371837 */, 18 }, + /* 4969 */ { MAD_F(0x052ce2f4) /* 0.323458628 */, 18 }, + /* 4970 */ { MAD_F(0x052d3df7) /* 0.323545425 */, 18 }, + /* 4971 */ { MAD_F(0x052d98fc) /* 0.323632227 */, 18 }, + /* 4972 */ { MAD_F(0x052df403) /* 0.323719036 */, 18 }, + /* 4973 */ { MAD_F(0x052e4f0b) /* 0.323805850 */, 18 }, + /* 4974 */ { MAD_F(0x052eaa14) /* 0.323892670 */, 18 }, + /* 4975 */ { MAD_F(0x052f051f) /* 0.323979496 */, 18 }, + + /* 4976 */ { MAD_F(0x052f602c) /* 0.324066327 */, 18 }, + /* 4977 */ { MAD_F(0x052fbb3a) /* 0.324153165 */, 18 }, + /* 4978 */ { MAD_F(0x0530164a) /* 0.324240008 */, 18 }, + /* 4979 */ { MAD_F(0x0530715b) /* 0.324326857 */, 18 }, + /* 4980 */ { MAD_F(0x0530cc6e) /* 0.324413712 */, 18 }, + /* 4981 */ { MAD_F(0x05312783) /* 0.324500572 */, 18 }, + /* 4982 */ { MAD_F(0x05318299) /* 0.324587439 */, 18 }, + /* 4983 */ { MAD_F(0x0531ddb0) /* 0.324674311 */, 18 }, + /* 4984 */ { MAD_F(0x053238ca) /* 0.324761189 */, 18 }, + /* 4985 */ { MAD_F(0x053293e4) /* 0.324848073 */, 18 }, + /* 4986 */ { MAD_F(0x0532ef01) /* 0.324934963 */, 18 }, + /* 4987 */ { MAD_F(0x05334a1e) /* 0.325021858 */, 18 }, + /* 4988 */ { MAD_F(0x0533a53e) /* 0.325108760 */, 18 }, + /* 4989 */ { MAD_F(0x0534005f) /* 0.325195667 */, 18 }, + /* 4990 */ { MAD_F(0x05345b81) /* 0.325282580 */, 18 }, + /* 4991 */ { MAD_F(0x0534b6a5) /* 0.325369498 */, 18 }, + + /* 4992 */ { MAD_F(0x053511cb) /* 0.325456423 */, 18 }, + /* 4993 */ { MAD_F(0x05356cf2) /* 0.325543353 */, 18 }, + /* 4994 */ { MAD_F(0x0535c81b) /* 0.325630290 */, 18 }, + /* 4995 */ { MAD_F(0x05362345) /* 0.325717232 */, 18 }, + /* 4996 */ { MAD_F(0x05367e71) /* 0.325804179 */, 18 }, + /* 4997 */ { MAD_F(0x0536d99f) /* 0.325891133 */, 18 }, + /* 4998 */ { MAD_F(0x053734ce) /* 0.325978092 */, 18 }, + /* 4999 */ { MAD_F(0x05378ffe) /* 0.326065057 */, 18 }, + /* 5000 */ { MAD_F(0x0537eb30) /* 0.326152028 */, 18 }, + /* 5001 */ { MAD_F(0x05384664) /* 0.326239005 */, 18 }, + /* 5002 */ { MAD_F(0x0538a199) /* 0.326325988 */, 18 }, + /* 5003 */ { MAD_F(0x0538fcd0) /* 0.326412976 */, 18 }, + /* 5004 */ { MAD_F(0x05395808) /* 0.326499970 */, 18 }, + /* 5005 */ { MAD_F(0x0539b342) /* 0.326586970 */, 18 }, + /* 5006 */ { MAD_F(0x053a0e7d) /* 0.326673976 */, 18 }, + /* 5007 */ { MAD_F(0x053a69ba) /* 0.326760988 */, 18 }, + + /* 5008 */ { MAD_F(0x053ac4f9) /* 0.326848005 */, 18 }, + /* 5009 */ { MAD_F(0x053b2039) /* 0.326935028 */, 18 }, + /* 5010 */ { MAD_F(0x053b7b7b) /* 0.327022057 */, 18 }, + /* 5011 */ { MAD_F(0x053bd6be) /* 0.327109092 */, 18 }, + /* 5012 */ { MAD_F(0x053c3203) /* 0.327196132 */, 18 }, + /* 5013 */ { MAD_F(0x053c8d49) /* 0.327283178 */, 18 }, + /* 5014 */ { MAD_F(0x053ce891) /* 0.327370231 */, 18 }, + /* 5015 */ { MAD_F(0x053d43da) /* 0.327457288 */, 18 }, + /* 5016 */ { MAD_F(0x053d9f25) /* 0.327544352 */, 18 }, + /* 5017 */ { MAD_F(0x053dfa72) /* 0.327631421 */, 18 }, + /* 5018 */ { MAD_F(0x053e55c0) /* 0.327718497 */, 18 }, + /* 5019 */ { MAD_F(0x053eb10f) /* 0.327805578 */, 18 }, + /* 5020 */ { MAD_F(0x053f0c61) /* 0.327892665 */, 18 }, + /* 5021 */ { MAD_F(0x053f67b3) /* 0.327979757 */, 18 }, + /* 5022 */ { MAD_F(0x053fc308) /* 0.328066855 */, 18 }, + /* 5023 */ { MAD_F(0x05401e5e) /* 0.328153960 */, 18 }, + + /* 5024 */ { MAD_F(0x054079b5) /* 0.328241070 */, 18 }, + /* 5025 */ { MAD_F(0x0540d50e) /* 0.328328185 */, 18 }, + /* 5026 */ { MAD_F(0x05413068) /* 0.328415307 */, 18 }, + /* 5027 */ { MAD_F(0x05418bc4) /* 0.328502434 */, 18 }, + /* 5028 */ { MAD_F(0x0541e722) /* 0.328589567 */, 18 }, + /* 5029 */ { MAD_F(0x05424281) /* 0.328676706 */, 18 }, + /* 5030 */ { MAD_F(0x05429de2) /* 0.328763850 */, 18 }, + /* 5031 */ { MAD_F(0x0542f944) /* 0.328851001 */, 18 }, + /* 5032 */ { MAD_F(0x054354a8) /* 0.328938157 */, 18 }, + /* 5033 */ { MAD_F(0x0543b00d) /* 0.329025319 */, 18 }, + /* 5034 */ { MAD_F(0x05440b74) /* 0.329112486 */, 18 }, + /* 5035 */ { MAD_F(0x054466dd) /* 0.329199660 */, 18 }, + /* 5036 */ { MAD_F(0x0544c247) /* 0.329286839 */, 18 }, + /* 5037 */ { MAD_F(0x05451db2) /* 0.329374024 */, 18 }, + /* 5038 */ { MAD_F(0x0545791f) /* 0.329461215 */, 18 }, + /* 5039 */ { MAD_F(0x0545d48e) /* 0.329548411 */, 18 }, + + /* 5040 */ { MAD_F(0x05462ffe) /* 0.329635614 */, 18 }, + /* 5041 */ { MAD_F(0x05468b70) /* 0.329722822 */, 18 }, + /* 5042 */ { MAD_F(0x0546e6e3) /* 0.329810036 */, 18 }, + /* 5043 */ { MAD_F(0x05474258) /* 0.329897255 */, 18 }, + /* 5044 */ { MAD_F(0x05479dce) /* 0.329984481 */, 18 }, + /* 5045 */ { MAD_F(0x0547f946) /* 0.330071712 */, 18 }, + /* 5046 */ { MAD_F(0x054854c0) /* 0.330158949 */, 18 }, + /* 5047 */ { MAD_F(0x0548b03b) /* 0.330246191 */, 18 }, + /* 5048 */ { MAD_F(0x05490bb7) /* 0.330333440 */, 18 }, + /* 5049 */ { MAD_F(0x05496735) /* 0.330420694 */, 18 }, + /* 5050 */ { MAD_F(0x0549c2b5) /* 0.330507954 */, 18 }, + /* 5051 */ { MAD_F(0x054a1e36) /* 0.330595220 */, 18 }, + /* 5052 */ { MAD_F(0x054a79b9) /* 0.330682491 */, 18 }, + /* 5053 */ { MAD_F(0x054ad53d) /* 0.330769768 */, 18 }, + /* 5054 */ { MAD_F(0x054b30c3) /* 0.330857051 */, 18 }, + /* 5055 */ { MAD_F(0x054b8c4b) /* 0.330944340 */, 18 }, + + /* 5056 */ { MAD_F(0x054be7d4) /* 0.331031635 */, 18 }, + /* 5057 */ { MAD_F(0x054c435e) /* 0.331118935 */, 18 }, + /* 5058 */ { MAD_F(0x054c9eea) /* 0.331206241 */, 18 }, + /* 5059 */ { MAD_F(0x054cfa78) /* 0.331293553 */, 18 }, + /* 5060 */ { MAD_F(0x054d5607) /* 0.331380870 */, 18 }, + /* 5061 */ { MAD_F(0x054db197) /* 0.331468193 */, 18 }, + /* 5062 */ { MAD_F(0x054e0d2a) /* 0.331555522 */, 18 }, + /* 5063 */ { MAD_F(0x054e68bd) /* 0.331642857 */, 18 }, + /* 5064 */ { MAD_F(0x054ec453) /* 0.331730198 */, 18 }, + /* 5065 */ { MAD_F(0x054f1fe9) /* 0.331817544 */, 18 }, + /* 5066 */ { MAD_F(0x054f7b82) /* 0.331904896 */, 18 }, + /* 5067 */ { MAD_F(0x054fd71c) /* 0.331992254 */, 18 }, + /* 5068 */ { MAD_F(0x055032b7) /* 0.332079617 */, 18 }, + /* 5069 */ { MAD_F(0x05508e54) /* 0.332166986 */, 18 }, + /* 5070 */ { MAD_F(0x0550e9f3) /* 0.332254361 */, 18 }, + /* 5071 */ { MAD_F(0x05514593) /* 0.332341742 */, 18 }, + + /* 5072 */ { MAD_F(0x0551a134) /* 0.332429129 */, 18 }, + /* 5073 */ { MAD_F(0x0551fcd8) /* 0.332516521 */, 18 }, + /* 5074 */ { MAD_F(0x0552587c) /* 0.332603919 */, 18 }, + /* 5075 */ { MAD_F(0x0552b423) /* 0.332691323 */, 18 }, + /* 5076 */ { MAD_F(0x05530fca) /* 0.332778732 */, 18 }, + /* 5077 */ { MAD_F(0x05536b74) /* 0.332866147 */, 18 }, + /* 5078 */ { MAD_F(0x0553c71f) /* 0.332953568 */, 18 }, + /* 5079 */ { MAD_F(0x055422cb) /* 0.333040995 */, 18 }, + /* 5080 */ { MAD_F(0x05547e79) /* 0.333128427 */, 18 }, + /* 5081 */ { MAD_F(0x0554da29) /* 0.333215865 */, 18 }, + /* 5082 */ { MAD_F(0x055535da) /* 0.333303309 */, 18 }, + /* 5083 */ { MAD_F(0x0555918c) /* 0.333390759 */, 18 }, + /* 5084 */ { MAD_F(0x0555ed40) /* 0.333478214 */, 18 }, + /* 5085 */ { MAD_F(0x055648f6) /* 0.333565675 */, 18 }, + /* 5086 */ { MAD_F(0x0556a4ad) /* 0.333653142 */, 18 }, + /* 5087 */ { MAD_F(0x05570066) /* 0.333740615 */, 18 }, + + /* 5088 */ { MAD_F(0x05575c20) /* 0.333828093 */, 18 }, + /* 5089 */ { MAD_F(0x0557b7dc) /* 0.333915577 */, 18 }, + /* 5090 */ { MAD_F(0x05581399) /* 0.334003067 */, 18 }, + /* 5091 */ { MAD_F(0x05586f58) /* 0.334090562 */, 18 }, + /* 5092 */ { MAD_F(0x0558cb19) /* 0.334178063 */, 18 }, + /* 5093 */ { MAD_F(0x055926db) /* 0.334265570 */, 18 }, + /* 5094 */ { MAD_F(0x0559829e) /* 0.334353083 */, 18 }, + /* 5095 */ { MAD_F(0x0559de63) /* 0.334440601 */, 18 }, + /* 5096 */ { MAD_F(0x055a3a2a) /* 0.334528126 */, 18 }, + /* 5097 */ { MAD_F(0x055a95f2) /* 0.334615655 */, 18 }, + /* 5098 */ { MAD_F(0x055af1bb) /* 0.334703191 */, 18 }, + /* 5099 */ { MAD_F(0x055b4d87) /* 0.334790732 */, 18 }, + /* 5100 */ { MAD_F(0x055ba953) /* 0.334878279 */, 18 }, + /* 5101 */ { MAD_F(0x055c0522) /* 0.334965832 */, 18 }, + /* 5102 */ { MAD_F(0x055c60f1) /* 0.335053391 */, 18 }, + /* 5103 */ { MAD_F(0x055cbcc3) /* 0.335140955 */, 18 }, + + /* 5104 */ { MAD_F(0x055d1896) /* 0.335228525 */, 18 }, + /* 5105 */ { MAD_F(0x055d746a) /* 0.335316100 */, 18 }, + /* 5106 */ { MAD_F(0x055dd040) /* 0.335403682 */, 18 }, + /* 5107 */ { MAD_F(0x055e2c17) /* 0.335491269 */, 18 }, + /* 5108 */ { MAD_F(0x055e87f0) /* 0.335578861 */, 18 }, + /* 5109 */ { MAD_F(0x055ee3cb) /* 0.335666460 */, 18 }, + /* 5110 */ { MAD_F(0x055f3fa7) /* 0.335754064 */, 18 }, + /* 5111 */ { MAD_F(0x055f9b85) /* 0.335841674 */, 18 }, + /* 5112 */ { MAD_F(0x055ff764) /* 0.335929290 */, 18 }, + /* 5113 */ { MAD_F(0x05605344) /* 0.336016911 */, 18 }, + /* 5114 */ { MAD_F(0x0560af27) /* 0.336104538 */, 18 }, + /* 5115 */ { MAD_F(0x05610b0a) /* 0.336192171 */, 18 }, + /* 5116 */ { MAD_F(0x056166f0) /* 0.336279809 */, 18 }, + /* 5117 */ { MAD_F(0x0561c2d7) /* 0.336367453 */, 18 }, + /* 5118 */ { MAD_F(0x05621ebf) /* 0.336455103 */, 18 }, + /* 5119 */ { MAD_F(0x05627aa9) /* 0.336542759 */, 18 }, + + /* 5120 */ { MAD_F(0x0562d694) /* 0.336630420 */, 18 }, + /* 5121 */ { MAD_F(0x05633281) /* 0.336718087 */, 18 }, + /* 5122 */ { MAD_F(0x05638e70) /* 0.336805760 */, 18 }, + /* 5123 */ { MAD_F(0x0563ea60) /* 0.336893439 */, 18 }, + /* 5124 */ { MAD_F(0x05644651) /* 0.336981123 */, 18 }, + /* 5125 */ { MAD_F(0x0564a244) /* 0.337068813 */, 18 }, + /* 5126 */ { MAD_F(0x0564fe39) /* 0.337156508 */, 18 }, + /* 5127 */ { MAD_F(0x05655a2f) /* 0.337244209 */, 18 }, + /* 5128 */ { MAD_F(0x0565b627) /* 0.337331916 */, 18 }, + /* 5129 */ { MAD_F(0x05661220) /* 0.337419629 */, 18 }, + /* 5130 */ { MAD_F(0x05666e1a) /* 0.337507347 */, 18 }, + /* 5131 */ { MAD_F(0x0566ca17) /* 0.337595071 */, 18 }, + /* 5132 */ { MAD_F(0x05672614) /* 0.337682801 */, 18 }, + /* 5133 */ { MAD_F(0x05678214) /* 0.337770537 */, 18 }, + /* 5134 */ { MAD_F(0x0567de15) /* 0.337858278 */, 18 }, + /* 5135 */ { MAD_F(0x05683a17) /* 0.337946025 */, 18 }, + + /* 5136 */ { MAD_F(0x0568961b) /* 0.338033777 */, 18 }, + /* 5137 */ { MAD_F(0x0568f220) /* 0.338121535 */, 18 }, + /* 5138 */ { MAD_F(0x05694e27) /* 0.338209299 */, 18 }, + /* 5139 */ { MAD_F(0x0569aa30) /* 0.338297069 */, 18 }, + /* 5140 */ { MAD_F(0x056a063a) /* 0.338384844 */, 18 }, + /* 5141 */ { MAD_F(0x056a6245) /* 0.338472625 */, 18 }, + /* 5142 */ { MAD_F(0x056abe52) /* 0.338560412 */, 18 }, + /* 5143 */ { MAD_F(0x056b1a61) /* 0.338648204 */, 18 }, + /* 5144 */ { MAD_F(0x056b7671) /* 0.338736002 */, 18 }, + /* 5145 */ { MAD_F(0x056bd283) /* 0.338823806 */, 18 }, + /* 5146 */ { MAD_F(0x056c2e96) /* 0.338911616 */, 18 }, + /* 5147 */ { MAD_F(0x056c8aab) /* 0.338999431 */, 18 }, + /* 5148 */ { MAD_F(0x056ce6c1) /* 0.339087252 */, 18 }, + /* 5149 */ { MAD_F(0x056d42d9) /* 0.339175078 */, 18 }, + /* 5150 */ { MAD_F(0x056d9ef2) /* 0.339262910 */, 18 }, + /* 5151 */ { MAD_F(0x056dfb0d) /* 0.339350748 */, 18 }, + + /* 5152 */ { MAD_F(0x056e5729) /* 0.339438592 */, 18 }, + /* 5153 */ { MAD_F(0x056eb347) /* 0.339526441 */, 18 }, + /* 5154 */ { MAD_F(0x056f0f66) /* 0.339614296 */, 18 }, + /* 5155 */ { MAD_F(0x056f6b87) /* 0.339702157 */, 18 }, + /* 5156 */ { MAD_F(0x056fc7aa) /* 0.339790023 */, 18 }, + /* 5157 */ { MAD_F(0x057023cd) /* 0.339877895 */, 18 }, + /* 5158 */ { MAD_F(0x05707ff3) /* 0.339965773 */, 18 }, + /* 5159 */ { MAD_F(0x0570dc1a) /* 0.340053656 */, 18 }, + /* 5160 */ { MAD_F(0x05713843) /* 0.340141545 */, 18 }, + /* 5161 */ { MAD_F(0x0571946d) /* 0.340229440 */, 18 }, + /* 5162 */ { MAD_F(0x0571f098) /* 0.340317340 */, 18 }, + /* 5163 */ { MAD_F(0x05724cc5) /* 0.340405246 */, 18 }, + /* 5164 */ { MAD_F(0x0572a8f4) /* 0.340493158 */, 18 }, + /* 5165 */ { MAD_F(0x05730524) /* 0.340581075 */, 18 }, + /* 5166 */ { MAD_F(0x05736156) /* 0.340668999 */, 18 }, + /* 5167 */ { MAD_F(0x0573bd89) /* 0.340756927 */, 18 }, + + /* 5168 */ { MAD_F(0x057419be) /* 0.340844862 */, 18 }, + /* 5169 */ { MAD_F(0x057475f4) /* 0.340932802 */, 18 }, + /* 5170 */ { MAD_F(0x0574d22c) /* 0.341020748 */, 18 }, + /* 5171 */ { MAD_F(0x05752e65) /* 0.341108699 */, 18 }, + /* 5172 */ { MAD_F(0x05758aa0) /* 0.341196656 */, 18 }, + /* 5173 */ { MAD_F(0x0575e6dc) /* 0.341284619 */, 18 }, + /* 5174 */ { MAD_F(0x0576431a) /* 0.341372587 */, 18 }, + /* 5175 */ { MAD_F(0x05769f59) /* 0.341460562 */, 18 }, + /* 5176 */ { MAD_F(0x0576fb9a) /* 0.341548541 */, 18 }, + /* 5177 */ { MAD_F(0x057757dd) /* 0.341636527 */, 18 }, + /* 5178 */ { MAD_F(0x0577b421) /* 0.341724518 */, 18 }, + /* 5179 */ { MAD_F(0x05781066) /* 0.341812515 */, 18 }, + /* 5180 */ { MAD_F(0x05786cad) /* 0.341900517 */, 18 }, + /* 5181 */ { MAD_F(0x0578c8f5) /* 0.341988525 */, 18 }, + /* 5182 */ { MAD_F(0x0579253f) /* 0.342076539 */, 18 }, + /* 5183 */ { MAD_F(0x0579818b) /* 0.342164558 */, 18 }, + + /* 5184 */ { MAD_F(0x0579ddd8) /* 0.342252584 */, 18 }, + /* 5185 */ { MAD_F(0x057a3a27) /* 0.342340614 */, 18 }, + /* 5186 */ { MAD_F(0x057a9677) /* 0.342428651 */, 18 }, + /* 5187 */ { MAD_F(0x057af2c8) /* 0.342516693 */, 18 }, + /* 5188 */ { MAD_F(0x057b4f1c) /* 0.342604741 */, 18 }, + /* 5189 */ { MAD_F(0x057bab70) /* 0.342692794 */, 18 }, + /* 5190 */ { MAD_F(0x057c07c6) /* 0.342780853 */, 18 }, + /* 5191 */ { MAD_F(0x057c641e) /* 0.342868918 */, 18 }, + /* 5192 */ { MAD_F(0x057cc077) /* 0.342956988 */, 18 }, + /* 5193 */ { MAD_F(0x057d1cd2) /* 0.343045064 */, 18 }, + /* 5194 */ { MAD_F(0x057d792e) /* 0.343133146 */, 18 }, + /* 5195 */ { MAD_F(0x057dd58c) /* 0.343221233 */, 18 }, + /* 5196 */ { MAD_F(0x057e31eb) /* 0.343309326 */, 18 }, + /* 5197 */ { MAD_F(0x057e8e4c) /* 0.343397425 */, 18 }, + /* 5198 */ { MAD_F(0x057eeaae) /* 0.343485529 */, 18 }, + /* 5199 */ { MAD_F(0x057f4712) /* 0.343573639 */, 18 }, + + /* 5200 */ { MAD_F(0x057fa378) /* 0.343661754 */, 18 }, + /* 5201 */ { MAD_F(0x057fffde) /* 0.343749876 */, 18 }, + /* 5202 */ { MAD_F(0x05805c47) /* 0.343838003 */, 18 }, + /* 5203 */ { MAD_F(0x0580b8b1) /* 0.343926135 */, 18 }, + /* 5204 */ { MAD_F(0x0581151c) /* 0.344014273 */, 18 }, + /* 5205 */ { MAD_F(0x05817189) /* 0.344102417 */, 18 }, + /* 5206 */ { MAD_F(0x0581cdf7) /* 0.344190566 */, 18 }, + /* 5207 */ { MAD_F(0x05822a67) /* 0.344278722 */, 18 }, + /* 5208 */ { MAD_F(0x058286d9) /* 0.344366882 */, 18 }, + /* 5209 */ { MAD_F(0x0582e34c) /* 0.344455049 */, 18 }, + /* 5210 */ { MAD_F(0x05833fc0) /* 0.344543221 */, 18 }, + /* 5211 */ { MAD_F(0x05839c36) /* 0.344631398 */, 18 }, + /* 5212 */ { MAD_F(0x0583f8ae) /* 0.344719582 */, 18 }, + /* 5213 */ { MAD_F(0x05845527) /* 0.344807771 */, 18 }, + /* 5214 */ { MAD_F(0x0584b1a1) /* 0.344895965 */, 18 }, + /* 5215 */ { MAD_F(0x05850e1e) /* 0.344984165 */, 18 }, + + /* 5216 */ { MAD_F(0x05856a9b) /* 0.345072371 */, 18 }, + /* 5217 */ { MAD_F(0x0585c71a) /* 0.345160583 */, 18 }, + /* 5218 */ { MAD_F(0x0586239b) /* 0.345248800 */, 18 }, + /* 5219 */ { MAD_F(0x0586801d) /* 0.345337023 */, 18 }, + /* 5220 */ { MAD_F(0x0586dca1) /* 0.345425251 */, 18 }, + /* 5221 */ { MAD_F(0x05873926) /* 0.345513485 */, 18 }, + /* 5222 */ { MAD_F(0x058795ac) /* 0.345601725 */, 18 }, + /* 5223 */ { MAD_F(0x0587f235) /* 0.345689970 */, 18 }, + /* 5224 */ { MAD_F(0x05884ebe) /* 0.345778221 */, 18 }, + /* 5225 */ { MAD_F(0x0588ab49) /* 0.345866478 */, 18 }, + /* 5226 */ { MAD_F(0x058907d6) /* 0.345954740 */, 18 }, + /* 5227 */ { MAD_F(0x05896464) /* 0.346043008 */, 18 }, + /* 5228 */ { MAD_F(0x0589c0f4) /* 0.346131281 */, 18 }, + /* 5229 */ { MAD_F(0x058a1d85) /* 0.346219560 */, 18 }, + /* 5230 */ { MAD_F(0x058a7a18) /* 0.346307845 */, 18 }, + /* 5231 */ { MAD_F(0x058ad6ac) /* 0.346396135 */, 18 }, + + /* 5232 */ { MAD_F(0x058b3342) /* 0.346484431 */, 18 }, + /* 5233 */ { MAD_F(0x058b8fd9) /* 0.346572733 */, 18 }, + /* 5234 */ { MAD_F(0x058bec72) /* 0.346661040 */, 18 }, + /* 5235 */ { MAD_F(0x058c490c) /* 0.346749353 */, 18 }, + /* 5236 */ { MAD_F(0x058ca5a8) /* 0.346837671 */, 18 }, + /* 5237 */ { MAD_F(0x058d0246) /* 0.346925996 */, 18 }, + /* 5238 */ { MAD_F(0x058d5ee4) /* 0.347014325 */, 18 }, + /* 5239 */ { MAD_F(0x058dbb85) /* 0.347102661 */, 18 }, + /* 5240 */ { MAD_F(0x058e1827) /* 0.347191002 */, 18 }, + /* 5241 */ { MAD_F(0x058e74ca) /* 0.347279348 */, 18 }, + /* 5242 */ { MAD_F(0x058ed16f) /* 0.347367700 */, 18 }, + /* 5243 */ { MAD_F(0x058f2e15) /* 0.347456058 */, 18 }, + /* 5244 */ { MAD_F(0x058f8abd) /* 0.347544422 */, 18 }, + /* 5245 */ { MAD_F(0x058fe766) /* 0.347632791 */, 18 }, + /* 5246 */ { MAD_F(0x05904411) /* 0.347721165 */, 18 }, + /* 5247 */ { MAD_F(0x0590a0be) /* 0.347809546 */, 18 }, + + /* 5248 */ { MAD_F(0x0590fd6c) /* 0.347897931 */, 18 }, + /* 5249 */ { MAD_F(0x05915a1b) /* 0.347986323 */, 18 }, + /* 5250 */ { MAD_F(0x0591b6cc) /* 0.348074720 */, 18 }, + /* 5251 */ { MAD_F(0x0592137e) /* 0.348163123 */, 18 }, + /* 5252 */ { MAD_F(0x05927032) /* 0.348251531 */, 18 }, + /* 5253 */ { MAD_F(0x0592cce8) /* 0.348339945 */, 18 }, + /* 5254 */ { MAD_F(0x0593299f) /* 0.348428365 */, 18 }, + /* 5255 */ { MAD_F(0x05938657) /* 0.348516790 */, 18 }, + /* 5256 */ { MAD_F(0x0593e311) /* 0.348605221 */, 18 }, + /* 5257 */ { MAD_F(0x05943fcd) /* 0.348693657 */, 18 }, + /* 5258 */ { MAD_F(0x05949c8a) /* 0.348782099 */, 18 }, + /* 5259 */ { MAD_F(0x0594f948) /* 0.348870547 */, 18 }, + /* 5260 */ { MAD_F(0x05955608) /* 0.348959000 */, 18 }, + /* 5261 */ { MAD_F(0x0595b2ca) /* 0.349047459 */, 18 }, + /* 5262 */ { MAD_F(0x05960f8c) /* 0.349135923 */, 18 }, + /* 5263 */ { MAD_F(0x05966c51) /* 0.349224393 */, 18 }, + + /* 5264 */ { MAD_F(0x0596c917) /* 0.349312869 */, 18 }, + /* 5265 */ { MAD_F(0x059725de) /* 0.349401350 */, 18 }, + /* 5266 */ { MAD_F(0x059782a7) /* 0.349489837 */, 18 }, + /* 5267 */ { MAD_F(0x0597df72) /* 0.349578329 */, 18 }, + /* 5268 */ { MAD_F(0x05983c3e) /* 0.349666827 */, 18 }, + /* 5269 */ { MAD_F(0x0598990c) /* 0.349755331 */, 18 }, + /* 5270 */ { MAD_F(0x0598f5db) /* 0.349843840 */, 18 }, + /* 5271 */ { MAD_F(0x059952ab) /* 0.349932355 */, 18 }, + /* 5272 */ { MAD_F(0x0599af7d) /* 0.350020876 */, 18 }, + /* 5273 */ { MAD_F(0x059a0c51) /* 0.350109402 */, 18 }, + /* 5274 */ { MAD_F(0x059a6926) /* 0.350197933 */, 18 }, + /* 5275 */ { MAD_F(0x059ac5fc) /* 0.350286470 */, 18 }, + /* 5276 */ { MAD_F(0x059b22d4) /* 0.350375013 */, 18 }, + /* 5277 */ { MAD_F(0x059b7fae) /* 0.350463562 */, 18 }, + /* 5278 */ { MAD_F(0x059bdc89) /* 0.350552116 */, 18 }, + /* 5279 */ { MAD_F(0x059c3965) /* 0.350640675 */, 18 }, + + /* 5280 */ { MAD_F(0x059c9643) /* 0.350729240 */, 18 }, + /* 5281 */ { MAD_F(0x059cf323) /* 0.350817811 */, 18 }, + /* 5282 */ { MAD_F(0x059d5004) /* 0.350906388 */, 18 }, + /* 5283 */ { MAD_F(0x059dace6) /* 0.350994970 */, 18 }, + /* 5284 */ { MAD_F(0x059e09cb) /* 0.351083557 */, 18 }, + /* 5285 */ { MAD_F(0x059e66b0) /* 0.351172150 */, 18 }, + /* 5286 */ { MAD_F(0x059ec397) /* 0.351260749 */, 18 }, + /* 5287 */ { MAD_F(0x059f2080) /* 0.351349353 */, 18 }, + /* 5288 */ { MAD_F(0x059f7d6a) /* 0.351437963 */, 18 }, + /* 5289 */ { MAD_F(0x059fda55) /* 0.351526579 */, 18 }, + /* 5290 */ { MAD_F(0x05a03742) /* 0.351615200 */, 18 }, + /* 5291 */ { MAD_F(0x05a09431) /* 0.351703827 */, 18 }, + /* 5292 */ { MAD_F(0x05a0f121) /* 0.351792459 */, 18 }, + /* 5293 */ { MAD_F(0x05a14e12) /* 0.351881097 */, 18 }, + /* 5294 */ { MAD_F(0x05a1ab05) /* 0.351969740 */, 18 }, + /* 5295 */ { MAD_F(0x05a207fa) /* 0.352058389 */, 18 }, + + /* 5296 */ { MAD_F(0x05a264f0) /* 0.352147044 */, 18 }, + /* 5297 */ { MAD_F(0x05a2c1e7) /* 0.352235704 */, 18 }, + /* 5298 */ { MAD_F(0x05a31ee1) /* 0.352324369 */, 18 }, + /* 5299 */ { MAD_F(0x05a37bdb) /* 0.352413041 */, 18 }, + /* 5300 */ { MAD_F(0x05a3d8d7) /* 0.352501718 */, 18 }, + /* 5301 */ { MAD_F(0x05a435d5) /* 0.352590400 */, 18 }, + /* 5302 */ { MAD_F(0x05a492d4) /* 0.352679088 */, 18 }, + /* 5303 */ { MAD_F(0x05a4efd4) /* 0.352767782 */, 18 }, + /* 5304 */ { MAD_F(0x05a54cd6) /* 0.352856481 */, 18 }, + /* 5305 */ { MAD_F(0x05a5a9da) /* 0.352945186 */, 18 }, + /* 5306 */ { MAD_F(0x05a606df) /* 0.353033896 */, 18 }, + /* 5307 */ { MAD_F(0x05a663e5) /* 0.353122612 */, 18 }, + /* 5308 */ { MAD_F(0x05a6c0ed) /* 0.353211333 */, 18 }, + /* 5309 */ { MAD_F(0x05a71df7) /* 0.353300061 */, 18 }, + /* 5310 */ { MAD_F(0x05a77b02) /* 0.353388793 */, 18 }, + /* 5311 */ { MAD_F(0x05a7d80e) /* 0.353477531 */, 18 }, + + /* 5312 */ { MAD_F(0x05a8351c) /* 0.353566275 */, 18 }, + /* 5313 */ { MAD_F(0x05a8922c) /* 0.353655024 */, 18 }, + /* 5314 */ { MAD_F(0x05a8ef3c) /* 0.353743779 */, 18 }, + /* 5315 */ { MAD_F(0x05a94c4f) /* 0.353832540 */, 18 }, + /* 5316 */ { MAD_F(0x05a9a963) /* 0.353921306 */, 18 }, + /* 5317 */ { MAD_F(0x05aa0678) /* 0.354010077 */, 18 }, + /* 5318 */ { MAD_F(0x05aa638f) /* 0.354098855 */, 18 }, + /* 5319 */ { MAD_F(0x05aac0a8) /* 0.354187637 */, 18 }, + /* 5320 */ { MAD_F(0x05ab1dc2) /* 0.354276426 */, 18 }, + /* 5321 */ { MAD_F(0x05ab7add) /* 0.354365220 */, 18 }, + /* 5322 */ { MAD_F(0x05abd7fa) /* 0.354454019 */, 18 }, + /* 5323 */ { MAD_F(0x05ac3518) /* 0.354542824 */, 18 }, + /* 5324 */ { MAD_F(0x05ac9238) /* 0.354631635 */, 18 }, + /* 5325 */ { MAD_F(0x05acef5a) /* 0.354720451 */, 18 }, + /* 5326 */ { MAD_F(0x05ad4c7d) /* 0.354809272 */, 18 }, + /* 5327 */ { MAD_F(0x05ada9a1) /* 0.354898100 */, 18 }, + + /* 5328 */ { MAD_F(0x05ae06c7) /* 0.354986932 */, 18 }, + /* 5329 */ { MAD_F(0x05ae63ee) /* 0.355075771 */, 18 }, + /* 5330 */ { MAD_F(0x05aec117) /* 0.355164615 */, 18 }, + /* 5331 */ { MAD_F(0x05af1e41) /* 0.355253464 */, 18 }, + /* 5332 */ { MAD_F(0x05af7b6d) /* 0.355342319 */, 18 }, + /* 5333 */ { MAD_F(0x05afd89b) /* 0.355431180 */, 18 }, + /* 5334 */ { MAD_F(0x05b035c9) /* 0.355520046 */, 18 }, + /* 5335 */ { MAD_F(0x05b092fa) /* 0.355608917 */, 18 }, + /* 5336 */ { MAD_F(0x05b0f02b) /* 0.355697795 */, 18 }, + /* 5337 */ { MAD_F(0x05b14d5f) /* 0.355786677 */, 18 }, + /* 5338 */ { MAD_F(0x05b1aa94) /* 0.355875566 */, 18 }, + /* 5339 */ { MAD_F(0x05b207ca) /* 0.355964460 */, 18 }, + /* 5340 */ { MAD_F(0x05b26502) /* 0.356053359 */, 18 }, + /* 5341 */ { MAD_F(0x05b2c23b) /* 0.356142264 */, 18 }, + /* 5342 */ { MAD_F(0x05b31f76) /* 0.356231175 */, 18 }, + /* 5343 */ { MAD_F(0x05b37cb2) /* 0.356320091 */, 18 }, + + /* 5344 */ { MAD_F(0x05b3d9f0) /* 0.356409012 */, 18 }, + /* 5345 */ { MAD_F(0x05b4372f) /* 0.356497940 */, 18 }, + /* 5346 */ { MAD_F(0x05b4946f) /* 0.356586872 */, 18 }, + /* 5347 */ { MAD_F(0x05b4f1b2) /* 0.356675811 */, 18 }, + /* 5348 */ { MAD_F(0x05b54ef5) /* 0.356764754 */, 18 }, + /* 5349 */ { MAD_F(0x05b5ac3a) /* 0.356853704 */, 18 }, + /* 5350 */ { MAD_F(0x05b60981) /* 0.356942659 */, 18 }, + /* 5351 */ { MAD_F(0x05b666c9) /* 0.357031619 */, 18 }, + /* 5352 */ { MAD_F(0x05b6c413) /* 0.357120585 */, 18 }, + /* 5353 */ { MAD_F(0x05b7215e) /* 0.357209557 */, 18 }, + /* 5354 */ { MAD_F(0x05b77eab) /* 0.357298534 */, 18 }, + /* 5355 */ { MAD_F(0x05b7dbf9) /* 0.357387516 */, 18 }, + /* 5356 */ { MAD_F(0x05b83948) /* 0.357476504 */, 18 }, + /* 5357 */ { MAD_F(0x05b89699) /* 0.357565498 */, 18 }, + /* 5358 */ { MAD_F(0x05b8f3ec) /* 0.357654497 */, 18 }, + /* 5359 */ { MAD_F(0x05b95140) /* 0.357743502 */, 18 }, + + /* 5360 */ { MAD_F(0x05b9ae95) /* 0.357832512 */, 18 }, + /* 5361 */ { MAD_F(0x05ba0bec) /* 0.357921528 */, 18 }, + /* 5362 */ { MAD_F(0x05ba6945) /* 0.358010550 */, 18 }, + /* 5363 */ { MAD_F(0x05bac69f) /* 0.358099576 */, 18 }, + /* 5364 */ { MAD_F(0x05bb23fa) /* 0.358188609 */, 18 }, + /* 5365 */ { MAD_F(0x05bb8157) /* 0.358277647 */, 18 }, + /* 5366 */ { MAD_F(0x05bbdeb6) /* 0.358366690 */, 18 }, + /* 5367 */ { MAD_F(0x05bc3c16) /* 0.358455739 */, 18 }, + /* 5368 */ { MAD_F(0x05bc9977) /* 0.358544794 */, 18 }, + /* 5369 */ { MAD_F(0x05bcf6da) /* 0.358633854 */, 18 }, + /* 5370 */ { MAD_F(0x05bd543e) /* 0.358722920 */, 18 }, + /* 5371 */ { MAD_F(0x05bdb1a4) /* 0.358811991 */, 18 }, + /* 5372 */ { MAD_F(0x05be0f0b) /* 0.358901067 */, 18 }, + /* 5373 */ { MAD_F(0x05be6c74) /* 0.358990150 */, 18 }, + /* 5374 */ { MAD_F(0x05bec9df) /* 0.359079237 */, 18 }, + /* 5375 */ { MAD_F(0x05bf274a) /* 0.359168331 */, 18 }, + + /* 5376 */ { MAD_F(0x05bf84b8) /* 0.359257429 */, 18 }, + /* 5377 */ { MAD_F(0x05bfe226) /* 0.359346534 */, 18 }, + /* 5378 */ { MAD_F(0x05c03f97) /* 0.359435644 */, 18 }, + /* 5379 */ { MAD_F(0x05c09d08) /* 0.359524759 */, 18 }, + /* 5380 */ { MAD_F(0x05c0fa7c) /* 0.359613880 */, 18 }, + /* 5381 */ { MAD_F(0x05c157f0) /* 0.359703006 */, 18 }, + /* 5382 */ { MAD_F(0x05c1b566) /* 0.359792138 */, 18 }, + /* 5383 */ { MAD_F(0x05c212de) /* 0.359881276 */, 18 }, + /* 5384 */ { MAD_F(0x05c27057) /* 0.359970419 */, 18 }, + /* 5385 */ { MAD_F(0x05c2cdd2) /* 0.360059567 */, 18 }, + /* 5386 */ { MAD_F(0x05c32b4e) /* 0.360148721 */, 18 }, + /* 5387 */ { MAD_F(0x05c388cb) /* 0.360237881 */, 18 }, + /* 5388 */ { MAD_F(0x05c3e64b) /* 0.360327046 */, 18 }, + /* 5389 */ { MAD_F(0x05c443cb) /* 0.360416216 */, 18 }, + /* 5390 */ { MAD_F(0x05c4a14d) /* 0.360505392 */, 18 }, + /* 5391 */ { MAD_F(0x05c4fed1) /* 0.360594574 */, 18 }, + + /* 5392 */ { MAD_F(0x05c55c56) /* 0.360683761 */, 18 }, + /* 5393 */ { MAD_F(0x05c5b9dc) /* 0.360772953 */, 18 }, + /* 5394 */ { MAD_F(0x05c61764) /* 0.360862152 */, 18 }, + /* 5395 */ { MAD_F(0x05c674ed) /* 0.360951355 */, 18 }, + /* 5396 */ { MAD_F(0x05c6d278) /* 0.361040564 */, 18 }, + /* 5397 */ { MAD_F(0x05c73005) /* 0.361129779 */, 18 }, + /* 5398 */ { MAD_F(0x05c78d93) /* 0.361218999 */, 18 }, + /* 5399 */ { MAD_F(0x05c7eb22) /* 0.361308225 */, 18 }, + /* 5400 */ { MAD_F(0x05c848b3) /* 0.361397456 */, 18 }, + /* 5401 */ { MAD_F(0x05c8a645) /* 0.361486693 */, 18 }, + /* 5402 */ { MAD_F(0x05c903d9) /* 0.361575935 */, 18 }, + /* 5403 */ { MAD_F(0x05c9616e) /* 0.361665183 */, 18 }, + /* 5404 */ { MAD_F(0x05c9bf05) /* 0.361754436 */, 18 }, + /* 5405 */ { MAD_F(0x05ca1c9d) /* 0.361843695 */, 18 }, + /* 5406 */ { MAD_F(0x05ca7a37) /* 0.361932959 */, 18 }, + /* 5407 */ { MAD_F(0x05cad7d2) /* 0.362022229 */, 18 }, + + /* 5408 */ { MAD_F(0x05cb356e) /* 0.362111504 */, 18 }, + /* 5409 */ { MAD_F(0x05cb930d) /* 0.362200785 */, 18 }, + /* 5410 */ { MAD_F(0x05cbf0ac) /* 0.362290071 */, 18 }, + /* 5411 */ { MAD_F(0x05cc4e4d) /* 0.362379362 */, 18 }, + /* 5412 */ { MAD_F(0x05ccabf0) /* 0.362468660 */, 18 }, + /* 5413 */ { MAD_F(0x05cd0994) /* 0.362557962 */, 18 }, + /* 5414 */ { MAD_F(0x05cd6739) /* 0.362647271 */, 18 }, + /* 5415 */ { MAD_F(0x05cdc4e0) /* 0.362736584 */, 18 }, + /* 5416 */ { MAD_F(0x05ce2289) /* 0.362825904 */, 18 }, + /* 5417 */ { MAD_F(0x05ce8033) /* 0.362915228 */, 18 }, + /* 5418 */ { MAD_F(0x05ceddde) /* 0.363004559 */, 18 }, + /* 5419 */ { MAD_F(0x05cf3b8b) /* 0.363093894 */, 18 }, + /* 5420 */ { MAD_F(0x05cf9939) /* 0.363183236 */, 18 }, + /* 5421 */ { MAD_F(0x05cff6e9) /* 0.363272582 */, 18 }, + /* 5422 */ { MAD_F(0x05d0549a) /* 0.363361935 */, 18 }, + /* 5423 */ { MAD_F(0x05d0b24d) /* 0.363451292 */, 18 }, + + /* 5424 */ { MAD_F(0x05d11001) /* 0.363540655 */, 18 }, + /* 5425 */ { MAD_F(0x05d16db7) /* 0.363630024 */, 18 }, + /* 5426 */ { MAD_F(0x05d1cb6e) /* 0.363719398 */, 18 }, + /* 5427 */ { MAD_F(0x05d22927) /* 0.363808778 */, 18 }, + /* 5428 */ { MAD_F(0x05d286e1) /* 0.363898163 */, 18 }, + /* 5429 */ { MAD_F(0x05d2e49d) /* 0.363987554 */, 18 }, + /* 5430 */ { MAD_F(0x05d3425a) /* 0.364076950 */, 18 }, + /* 5431 */ { MAD_F(0x05d3a018) /* 0.364166352 */, 18 }, + /* 5432 */ { MAD_F(0x05d3fdd8) /* 0.364255759 */, 18 }, + /* 5433 */ { MAD_F(0x05d45b9a) /* 0.364345171 */, 18 }, + /* 5434 */ { MAD_F(0x05d4b95d) /* 0.364434589 */, 18 }, + /* 5435 */ { MAD_F(0x05d51721) /* 0.364524013 */, 18 }, + /* 5436 */ { MAD_F(0x05d574e7) /* 0.364613442 */, 18 }, + /* 5437 */ { MAD_F(0x05d5d2af) /* 0.364702877 */, 18 }, + /* 5438 */ { MAD_F(0x05d63078) /* 0.364792317 */, 18 }, + /* 5439 */ { MAD_F(0x05d68e42) /* 0.364881762 */, 18 }, + + /* 5440 */ { MAD_F(0x05d6ec0e) /* 0.364971213 */, 18 }, + /* 5441 */ { MAD_F(0x05d749db) /* 0.365060669 */, 18 }, + /* 5442 */ { MAD_F(0x05d7a7aa) /* 0.365150131 */, 18 }, + /* 5443 */ { MAD_F(0x05d8057a) /* 0.365239599 */, 18 }, + /* 5444 */ { MAD_F(0x05d8634c) /* 0.365329072 */, 18 }, + /* 5445 */ { MAD_F(0x05d8c11f) /* 0.365418550 */, 18 }, + /* 5446 */ { MAD_F(0x05d91ef4) /* 0.365508034 */, 18 }, + /* 5447 */ { MAD_F(0x05d97cca) /* 0.365597523 */, 18 }, + /* 5448 */ { MAD_F(0x05d9daa1) /* 0.365687018 */, 18 }, + /* 5449 */ { MAD_F(0x05da387a) /* 0.365776518 */, 18 }, + /* 5450 */ { MAD_F(0x05da9655) /* 0.365866024 */, 18 }, + /* 5451 */ { MAD_F(0x05daf431) /* 0.365955536 */, 18 }, + /* 5452 */ { MAD_F(0x05db520e) /* 0.366045052 */, 18 }, + /* 5453 */ { MAD_F(0x05dbafed) /* 0.366134574 */, 18 }, + /* 5454 */ { MAD_F(0x05dc0dce) /* 0.366224102 */, 18 }, + /* 5455 */ { MAD_F(0x05dc6baf) /* 0.366313635 */, 18 }, + + /* 5456 */ { MAD_F(0x05dcc993) /* 0.366403174 */, 18 }, + /* 5457 */ { MAD_F(0x05dd2778) /* 0.366492718 */, 18 }, + /* 5458 */ { MAD_F(0x05dd855e) /* 0.366582267 */, 18 }, + /* 5459 */ { MAD_F(0x05dde346) /* 0.366671822 */, 18 }, + /* 5460 */ { MAD_F(0x05de412f) /* 0.366761383 */, 18 }, + /* 5461 */ { MAD_F(0x05de9f1a) /* 0.366850949 */, 18 }, + /* 5462 */ { MAD_F(0x05defd06) /* 0.366940520 */, 18 }, + /* 5463 */ { MAD_F(0x05df5af3) /* 0.367030097 */, 18 }, + /* 5464 */ { MAD_F(0x05dfb8e2) /* 0.367119680 */, 18 }, + /* 5465 */ { MAD_F(0x05e016d3) /* 0.367209267 */, 18 }, + /* 5466 */ { MAD_F(0x05e074c5) /* 0.367298861 */, 18 }, + /* 5467 */ { MAD_F(0x05e0d2b8) /* 0.367388459 */, 18 }, + /* 5468 */ { MAD_F(0x05e130ad) /* 0.367478064 */, 18 }, + /* 5469 */ { MAD_F(0x05e18ea4) /* 0.367567673 */, 18 }, + /* 5470 */ { MAD_F(0x05e1ec9c) /* 0.367657288 */, 18 }, + /* 5471 */ { MAD_F(0x05e24a95) /* 0.367746909 */, 18 }, + + /* 5472 */ { MAD_F(0x05e2a890) /* 0.367836535 */, 18 }, + /* 5473 */ { MAD_F(0x05e3068c) /* 0.367926167 */, 18 }, + /* 5474 */ { MAD_F(0x05e3648a) /* 0.368015804 */, 18 }, + /* 5475 */ { MAD_F(0x05e3c289) /* 0.368105446 */, 18 }, + /* 5476 */ { MAD_F(0x05e4208a) /* 0.368195094 */, 18 }, + /* 5477 */ { MAD_F(0x05e47e8c) /* 0.368284747 */, 18 }, + /* 5478 */ { MAD_F(0x05e4dc8f) /* 0.368374406 */, 18 }, + /* 5479 */ { MAD_F(0x05e53a94) /* 0.368464070 */, 18 }, + /* 5480 */ { MAD_F(0x05e5989b) /* 0.368553740 */, 18 }, + /* 5481 */ { MAD_F(0x05e5f6a3) /* 0.368643415 */, 18 }, + /* 5482 */ { MAD_F(0x05e654ac) /* 0.368733096 */, 18 }, + /* 5483 */ { MAD_F(0x05e6b2b7) /* 0.368822782 */, 18 }, + /* 5484 */ { MAD_F(0x05e710c4) /* 0.368912473 */, 18 }, + /* 5485 */ { MAD_F(0x05e76ed2) /* 0.369002170 */, 18 }, + /* 5486 */ { MAD_F(0x05e7cce1) /* 0.369091873 */, 18 }, + /* 5487 */ { MAD_F(0x05e82af2) /* 0.369181581 */, 18 }, + + /* 5488 */ { MAD_F(0x05e88904) /* 0.369271294 */, 18 }, + /* 5489 */ { MAD_F(0x05e8e718) /* 0.369361013 */, 18 }, + /* 5490 */ { MAD_F(0x05e9452d) /* 0.369450737 */, 18 }, + /* 5491 */ { MAD_F(0x05e9a343) /* 0.369540467 */, 18 }, + /* 5492 */ { MAD_F(0x05ea015c) /* 0.369630202 */, 18 }, + /* 5493 */ { MAD_F(0x05ea5f75) /* 0.369719942 */, 18 }, + /* 5494 */ { MAD_F(0x05eabd90) /* 0.369809688 */, 18 }, + /* 5495 */ { MAD_F(0x05eb1bad) /* 0.369899440 */, 18 }, + /* 5496 */ { MAD_F(0x05eb79cb) /* 0.369989197 */, 18 }, + /* 5497 */ { MAD_F(0x05ebd7ea) /* 0.370078959 */, 18 }, + /* 5498 */ { MAD_F(0x05ec360b) /* 0.370168727 */, 18 }, + /* 5499 */ { MAD_F(0x05ec942d) /* 0.370258500 */, 18 }, + /* 5500 */ { MAD_F(0x05ecf251) /* 0.370348279 */, 18 }, + /* 5501 */ { MAD_F(0x05ed5076) /* 0.370438063 */, 18 }, + /* 5502 */ { MAD_F(0x05edae9d) /* 0.370527853 */, 18 }, + /* 5503 */ { MAD_F(0x05ee0cc5) /* 0.370617648 */, 18 }, + + /* 5504 */ { MAD_F(0x05ee6aef) /* 0.370707448 */, 18 }, + /* 5505 */ { MAD_F(0x05eec91a) /* 0.370797254 */, 18 }, + /* 5506 */ { MAD_F(0x05ef2746) /* 0.370887065 */, 18 }, + /* 5507 */ { MAD_F(0x05ef8574) /* 0.370976882 */, 18 }, + /* 5508 */ { MAD_F(0x05efe3a4) /* 0.371066704 */, 18 }, + /* 5509 */ { MAD_F(0x05f041d5) /* 0.371156532 */, 18 }, + /* 5510 */ { MAD_F(0x05f0a007) /* 0.371246365 */, 18 }, + /* 5511 */ { MAD_F(0x05f0fe3b) /* 0.371336203 */, 18 }, + /* 5512 */ { MAD_F(0x05f15c70) /* 0.371426047 */, 18 }, + /* 5513 */ { MAD_F(0x05f1baa7) /* 0.371515897 */, 18 }, + /* 5514 */ { MAD_F(0x05f218df) /* 0.371605751 */, 18 }, + /* 5515 */ { MAD_F(0x05f27719) /* 0.371695612 */, 18 }, + /* 5516 */ { MAD_F(0x05f2d554) /* 0.371785477 */, 18 }, + /* 5517 */ { MAD_F(0x05f33390) /* 0.371875348 */, 18 }, + /* 5518 */ { MAD_F(0x05f391cf) /* 0.371965225 */, 18 }, + /* 5519 */ { MAD_F(0x05f3f00e) /* 0.372055107 */, 18 }, + + /* 5520 */ { MAD_F(0x05f44e4f) /* 0.372144994 */, 18 }, + /* 5521 */ { MAD_F(0x05f4ac91) /* 0.372234887 */, 18 }, + /* 5522 */ { MAD_F(0x05f50ad5) /* 0.372324785 */, 18 }, + /* 5523 */ { MAD_F(0x05f5691b) /* 0.372414689 */, 18 }, + /* 5524 */ { MAD_F(0x05f5c761) /* 0.372504598 */, 18 }, + /* 5525 */ { MAD_F(0x05f625aa) /* 0.372594513 */, 18 }, + /* 5526 */ { MAD_F(0x05f683f3) /* 0.372684433 */, 18 }, + /* 5527 */ { MAD_F(0x05f6e23f) /* 0.372774358 */, 18 }, + /* 5528 */ { MAD_F(0x05f7408b) /* 0.372864289 */, 18 }, + /* 5529 */ { MAD_F(0x05f79ed9) /* 0.372954225 */, 18 }, + /* 5530 */ { MAD_F(0x05f7fd29) /* 0.373044167 */, 18 }, + /* 5531 */ { MAD_F(0x05f85b7a) /* 0.373134114 */, 18 }, + /* 5532 */ { MAD_F(0x05f8b9cc) /* 0.373224066 */, 18 }, + /* 5533 */ { MAD_F(0x05f91820) /* 0.373314024 */, 18 }, + /* 5534 */ { MAD_F(0x05f97675) /* 0.373403987 */, 18 }, + /* 5535 */ { MAD_F(0x05f9d4cc) /* 0.373493956 */, 18 }, + + /* 5536 */ { MAD_F(0x05fa3324) /* 0.373583930 */, 18 }, + /* 5537 */ { MAD_F(0x05fa917e) /* 0.373673910 */, 18 }, + /* 5538 */ { MAD_F(0x05faefd9) /* 0.373763895 */, 18 }, + /* 5539 */ { MAD_F(0x05fb4e36) /* 0.373853885 */, 18 }, + /* 5540 */ { MAD_F(0x05fbac94) /* 0.373943881 */, 18 }, + /* 5541 */ { MAD_F(0x05fc0af3) /* 0.374033882 */, 18 }, + /* 5542 */ { MAD_F(0x05fc6954) /* 0.374123889 */, 18 }, + /* 5543 */ { MAD_F(0x05fcc7b7) /* 0.374213901 */, 18 }, + /* 5544 */ { MAD_F(0x05fd261b) /* 0.374303918 */, 18 }, + /* 5545 */ { MAD_F(0x05fd8480) /* 0.374393941 */, 18 }, + /* 5546 */ { MAD_F(0x05fde2e7) /* 0.374483970 */, 18 }, + /* 5547 */ { MAD_F(0x05fe414f) /* 0.374574003 */, 18 }, + /* 5548 */ { MAD_F(0x05fe9fb9) /* 0.374664042 */, 18 }, + /* 5549 */ { MAD_F(0x05fefe24) /* 0.374754087 */, 18 }, + /* 5550 */ { MAD_F(0x05ff5c91) /* 0.374844137 */, 18 }, + /* 5551 */ { MAD_F(0x05ffbaff) /* 0.374934192 */, 18 }, + + /* 5552 */ { MAD_F(0x0600196e) /* 0.375024253 */, 18 }, + /* 5553 */ { MAD_F(0x060077df) /* 0.375114319 */, 18 }, + /* 5554 */ { MAD_F(0x0600d651) /* 0.375204391 */, 18 }, + /* 5555 */ { MAD_F(0x060134c5) /* 0.375294468 */, 18 }, + /* 5556 */ { MAD_F(0x0601933b) /* 0.375384550 */, 18 }, + /* 5557 */ { MAD_F(0x0601f1b1) /* 0.375474638 */, 18 }, + /* 5558 */ { MAD_F(0x0602502a) /* 0.375564731 */, 18 }, + /* 5559 */ { MAD_F(0x0602aea3) /* 0.375654830 */, 18 }, + /* 5560 */ { MAD_F(0x06030d1e) /* 0.375744934 */, 18 }, + /* 5561 */ { MAD_F(0x06036b9b) /* 0.375835043 */, 18 }, + /* 5562 */ { MAD_F(0x0603ca19) /* 0.375925158 */, 18 }, + /* 5563 */ { MAD_F(0x06042898) /* 0.376015278 */, 18 }, + /* 5564 */ { MAD_F(0x06048719) /* 0.376105404 */, 18 }, + /* 5565 */ { MAD_F(0x0604e59c) /* 0.376195535 */, 18 }, + /* 5566 */ { MAD_F(0x0605441f) /* 0.376285671 */, 18 }, + /* 5567 */ { MAD_F(0x0605a2a5) /* 0.376375813 */, 18 }, + + /* 5568 */ { MAD_F(0x0606012b) /* 0.376465960 */, 18 }, + /* 5569 */ { MAD_F(0x06065fb4) /* 0.376556113 */, 18 }, + /* 5570 */ { MAD_F(0x0606be3d) /* 0.376646271 */, 18 }, + /* 5571 */ { MAD_F(0x06071cc8) /* 0.376736434 */, 18 }, + /* 5572 */ { MAD_F(0x06077b55) /* 0.376826603 */, 18 }, + /* 5573 */ { MAD_F(0x0607d9e3) /* 0.376916777 */, 18 }, + /* 5574 */ { MAD_F(0x06083872) /* 0.377006957 */, 18 }, + /* 5575 */ { MAD_F(0x06089703) /* 0.377097141 */, 18 }, + /* 5576 */ { MAD_F(0x0608f595) /* 0.377187332 */, 18 }, + /* 5577 */ { MAD_F(0x06095429) /* 0.377277528 */, 18 }, + /* 5578 */ { MAD_F(0x0609b2be) /* 0.377367729 */, 18 }, + /* 5579 */ { MAD_F(0x060a1155) /* 0.377457935 */, 18 }, + /* 5580 */ { MAD_F(0x060a6fed) /* 0.377548147 */, 18 }, + /* 5581 */ { MAD_F(0x060ace86) /* 0.377638364 */, 18 }, + /* 5582 */ { MAD_F(0x060b2d21) /* 0.377728587 */, 18 }, + /* 5583 */ { MAD_F(0x060b8bbe) /* 0.377818815 */, 18 }, + + /* 5584 */ { MAD_F(0x060bea5c) /* 0.377909049 */, 18 }, + /* 5585 */ { MAD_F(0x060c48fb) /* 0.377999288 */, 18 }, + /* 5586 */ { MAD_F(0x060ca79c) /* 0.378089532 */, 18 }, + /* 5587 */ { MAD_F(0x060d063e) /* 0.378179781 */, 18 }, + /* 5588 */ { MAD_F(0x060d64e1) /* 0.378270036 */, 18 }, + /* 5589 */ { MAD_F(0x060dc387) /* 0.378360297 */, 18 }, + /* 5590 */ { MAD_F(0x060e222d) /* 0.378450563 */, 18 }, + /* 5591 */ { MAD_F(0x060e80d5) /* 0.378540834 */, 18 }, + /* 5592 */ { MAD_F(0x060edf7f) /* 0.378631110 */, 18 }, + /* 5593 */ { MAD_F(0x060f3e29) /* 0.378721392 */, 18 }, + /* 5594 */ { MAD_F(0x060f9cd6) /* 0.378811680 */, 18 }, + /* 5595 */ { MAD_F(0x060ffb83) /* 0.378901972 */, 18 }, + /* 5596 */ { MAD_F(0x06105a33) /* 0.378992270 */, 18 }, + /* 5597 */ { MAD_F(0x0610b8e3) /* 0.379082574 */, 18 }, + /* 5598 */ { MAD_F(0x06111795) /* 0.379172883 */, 18 }, + /* 5599 */ { MAD_F(0x06117649) /* 0.379263197 */, 18 }, + + /* 5600 */ { MAD_F(0x0611d4fe) /* 0.379353516 */, 18 }, + /* 5601 */ { MAD_F(0x061233b4) /* 0.379443841 */, 18 }, + /* 5602 */ { MAD_F(0x0612926c) /* 0.379534172 */, 18 }, + /* 5603 */ { MAD_F(0x0612f125) /* 0.379624507 */, 18 }, + /* 5604 */ { MAD_F(0x06134fe0) /* 0.379714848 */, 18 }, + /* 5605 */ { MAD_F(0x0613ae9c) /* 0.379805195 */, 18 }, + /* 5606 */ { MAD_F(0x06140d5a) /* 0.379895547 */, 18 }, + /* 5607 */ { MAD_F(0x06146c19) /* 0.379985904 */, 18 }, + /* 5608 */ { MAD_F(0x0614cada) /* 0.380076266 */, 18 }, + /* 5609 */ { MAD_F(0x0615299c) /* 0.380166634 */, 18 }, + /* 5610 */ { MAD_F(0x0615885f) /* 0.380257008 */, 18 }, + /* 5611 */ { MAD_F(0x0615e724) /* 0.380347386 */, 18 }, + /* 5612 */ { MAD_F(0x061645ea) /* 0.380437770 */, 18 }, + /* 5613 */ { MAD_F(0x0616a4b2) /* 0.380528160 */, 18 }, + /* 5614 */ { MAD_F(0x0617037b) /* 0.380618555 */, 18 }, + /* 5615 */ { MAD_F(0x06176246) /* 0.380708955 */, 18 }, + + /* 5616 */ { MAD_F(0x0617c112) /* 0.380799360 */, 18 }, + /* 5617 */ { MAD_F(0x06181fdf) /* 0.380889771 */, 18 }, + /* 5618 */ { MAD_F(0x06187eae) /* 0.380980187 */, 18 }, + /* 5619 */ { MAD_F(0x0618dd7e) /* 0.381070609 */, 18 }, + /* 5620 */ { MAD_F(0x06193c50) /* 0.381161036 */, 18 }, + /* 5621 */ { MAD_F(0x06199b24) /* 0.381251468 */, 18 }, + /* 5622 */ { MAD_F(0x0619f9f8) /* 0.381341906 */, 18 }, + /* 5623 */ { MAD_F(0x061a58ce) /* 0.381432349 */, 18 }, + /* 5624 */ { MAD_F(0x061ab7a6) /* 0.381522798 */, 18 }, + /* 5625 */ { MAD_F(0x061b167f) /* 0.381613251 */, 18 }, + /* 5626 */ { MAD_F(0x061b7559) /* 0.381703711 */, 18 }, + /* 5627 */ { MAD_F(0x061bd435) /* 0.381794175 */, 18 }, + /* 5628 */ { MAD_F(0x061c3313) /* 0.381884645 */, 18 }, + /* 5629 */ { MAD_F(0x061c91f1) /* 0.381975120 */, 18 }, + /* 5630 */ { MAD_F(0x061cf0d2) /* 0.382065601 */, 18 }, + /* 5631 */ { MAD_F(0x061d4fb3) /* 0.382156087 */, 18 }, + + /* 5632 */ { MAD_F(0x061dae96) /* 0.382246578 */, 18 }, + /* 5633 */ { MAD_F(0x061e0d7b) /* 0.382337075 */, 18 }, + /* 5634 */ { MAD_F(0x061e6c61) /* 0.382427577 */, 18 }, + /* 5635 */ { MAD_F(0x061ecb48) /* 0.382518084 */, 18 }, + /* 5636 */ { MAD_F(0x061f2a31) /* 0.382608597 */, 18 }, + /* 5637 */ { MAD_F(0x061f891b) /* 0.382699115 */, 18 }, + /* 5638 */ { MAD_F(0x061fe807) /* 0.382789638 */, 18 }, + /* 5639 */ { MAD_F(0x062046f4) /* 0.382880167 */, 18 }, + /* 5640 */ { MAD_F(0x0620a5e3) /* 0.382970701 */, 18 }, + /* 5641 */ { MAD_F(0x062104d3) /* 0.383061241 */, 18 }, + /* 5642 */ { MAD_F(0x062163c4) /* 0.383151786 */, 18 }, + /* 5643 */ { MAD_F(0x0621c2b7) /* 0.383242336 */, 18 }, + /* 5644 */ { MAD_F(0x062221ab) /* 0.383332891 */, 18 }, + /* 5645 */ { MAD_F(0x062280a1) /* 0.383423452 */, 18 }, + /* 5646 */ { MAD_F(0x0622df98) /* 0.383514018 */, 18 }, + /* 5647 */ { MAD_F(0x06233e91) /* 0.383604590 */, 18 }, + + /* 5648 */ { MAD_F(0x06239d8b) /* 0.383695167 */, 18 }, + /* 5649 */ { MAD_F(0x0623fc86) /* 0.383785749 */, 18 }, + /* 5650 */ { MAD_F(0x06245b83) /* 0.383876337 */, 18 }, + /* 5651 */ { MAD_F(0x0624ba82) /* 0.383966930 */, 18 }, + /* 5652 */ { MAD_F(0x06251981) /* 0.384057528 */, 18 }, + /* 5653 */ { MAD_F(0x06257883) /* 0.384148132 */, 18 }, + /* 5654 */ { MAD_F(0x0625d785) /* 0.384238741 */, 18 }, + /* 5655 */ { MAD_F(0x06263689) /* 0.384329355 */, 18 }, + /* 5656 */ { MAD_F(0x0626958f) /* 0.384419975 */, 18 }, + /* 5657 */ { MAD_F(0x0626f496) /* 0.384510600 */, 18 }, + /* 5658 */ { MAD_F(0x0627539e) /* 0.384601230 */, 18 }, + /* 5659 */ { MAD_F(0x0627b2a8) /* 0.384691866 */, 18 }, + /* 5660 */ { MAD_F(0x062811b3) /* 0.384782507 */, 18 }, + /* 5661 */ { MAD_F(0x062870c0) /* 0.384873153 */, 18 }, + /* 5662 */ { MAD_F(0x0628cfce) /* 0.384963805 */, 18 }, + /* 5663 */ { MAD_F(0x06292ede) /* 0.385054462 */, 18 }, + + /* 5664 */ { MAD_F(0x06298def) /* 0.385145124 */, 18 }, + /* 5665 */ { MAD_F(0x0629ed01) /* 0.385235792 */, 18 }, + /* 5666 */ { MAD_F(0x062a4c15) /* 0.385326465 */, 18 }, + /* 5667 */ { MAD_F(0x062aab2a) /* 0.385417143 */, 18 }, + /* 5668 */ { MAD_F(0x062b0a41) /* 0.385507827 */, 18 }, + /* 5669 */ { MAD_F(0x062b6959) /* 0.385598516 */, 18 }, + /* 5670 */ { MAD_F(0x062bc873) /* 0.385689211 */, 18 }, + /* 5671 */ { MAD_F(0x062c278e) /* 0.385779910 */, 18 }, + /* 5672 */ { MAD_F(0x062c86aa) /* 0.385870615 */, 18 }, + /* 5673 */ { MAD_F(0x062ce5c8) /* 0.385961326 */, 18 }, + /* 5674 */ { MAD_F(0x062d44e8) /* 0.386052041 */, 18 }, + /* 5675 */ { MAD_F(0x062da408) /* 0.386142762 */, 18 }, + /* 5676 */ { MAD_F(0x062e032a) /* 0.386233489 */, 18 }, + /* 5677 */ { MAD_F(0x062e624e) /* 0.386324221 */, 18 }, + /* 5678 */ { MAD_F(0x062ec173) /* 0.386414958 */, 18 }, + /* 5679 */ { MAD_F(0x062f209a) /* 0.386505700 */, 18 }, + + /* 5680 */ { MAD_F(0x062f7fc1) /* 0.386596448 */, 18 }, + /* 5681 */ { MAD_F(0x062fdeeb) /* 0.386687201 */, 18 }, + /* 5682 */ { MAD_F(0x06303e16) /* 0.386777959 */, 18 }, + /* 5683 */ { MAD_F(0x06309d42) /* 0.386868723 */, 18 }, + /* 5684 */ { MAD_F(0x0630fc6f) /* 0.386959492 */, 18 }, + /* 5685 */ { MAD_F(0x06315b9e) /* 0.387050266 */, 18 }, + /* 5686 */ { MAD_F(0x0631bacf) /* 0.387141045 */, 18 }, + /* 5687 */ { MAD_F(0x06321a01) /* 0.387231830 */, 18 }, + /* 5688 */ { MAD_F(0x06327934) /* 0.387322621 */, 18 }, + /* 5689 */ { MAD_F(0x0632d869) /* 0.387413416 */, 18 }, + /* 5690 */ { MAD_F(0x0633379f) /* 0.387504217 */, 18 }, + /* 5691 */ { MAD_F(0x063396d7) /* 0.387595023 */, 18 }, + /* 5692 */ { MAD_F(0x0633f610) /* 0.387685835 */, 18 }, + /* 5693 */ { MAD_F(0x0634554a) /* 0.387776652 */, 18 }, + /* 5694 */ { MAD_F(0x0634b486) /* 0.387867474 */, 18 }, + /* 5695 */ { MAD_F(0x063513c3) /* 0.387958301 */, 18 }, + + /* 5696 */ { MAD_F(0x06357302) /* 0.388049134 */, 18 }, + /* 5697 */ { MAD_F(0x0635d242) /* 0.388139972 */, 18 }, + /* 5698 */ { MAD_F(0x06363184) /* 0.388230816 */, 18 }, + /* 5699 */ { MAD_F(0x063690c7) /* 0.388321665 */, 18 }, + /* 5700 */ { MAD_F(0x0636f00b) /* 0.388412519 */, 18 }, + /* 5701 */ { MAD_F(0x06374f51) /* 0.388503378 */, 18 }, + /* 5702 */ { MAD_F(0x0637ae99) /* 0.388594243 */, 18 }, + /* 5703 */ { MAD_F(0x06380de1) /* 0.388685113 */, 18 }, + /* 5704 */ { MAD_F(0x06386d2b) /* 0.388775988 */, 18 }, + /* 5705 */ { MAD_F(0x0638cc77) /* 0.388866869 */, 18 }, + /* 5706 */ { MAD_F(0x06392bc4) /* 0.388957755 */, 18 }, + /* 5707 */ { MAD_F(0x06398b12) /* 0.389048646 */, 18 }, + /* 5708 */ { MAD_F(0x0639ea62) /* 0.389139542 */, 18 }, + /* 5709 */ { MAD_F(0x063a49b4) /* 0.389230444 */, 18 }, + /* 5710 */ { MAD_F(0x063aa906) /* 0.389321352 */, 18 }, + /* 5711 */ { MAD_F(0x063b085a) /* 0.389412264 */, 18 }, + + /* 5712 */ { MAD_F(0x063b67b0) /* 0.389503182 */, 18 }, + /* 5713 */ { MAD_F(0x063bc707) /* 0.389594105 */, 18 }, + /* 5714 */ { MAD_F(0x063c265f) /* 0.389685033 */, 18 }, + /* 5715 */ { MAD_F(0x063c85b9) /* 0.389775967 */, 18 }, + /* 5716 */ { MAD_F(0x063ce514) /* 0.389866906 */, 18 }, + /* 5717 */ { MAD_F(0x063d4471) /* 0.389957850 */, 18 }, + /* 5718 */ { MAD_F(0x063da3cf) /* 0.390048800 */, 18 }, + /* 5719 */ { MAD_F(0x063e032f) /* 0.390139755 */, 18 }, + /* 5720 */ { MAD_F(0x063e6290) /* 0.390230715 */, 18 }, + /* 5721 */ { MAD_F(0x063ec1f2) /* 0.390321681 */, 18 }, + /* 5722 */ { MAD_F(0x063f2156) /* 0.390412651 */, 18 }, + /* 5723 */ { MAD_F(0x063f80bb) /* 0.390503628 */, 18 }, + /* 5724 */ { MAD_F(0x063fe022) /* 0.390594609 */, 18 }, + /* 5725 */ { MAD_F(0x06403f8a) /* 0.390685596 */, 18 }, + /* 5726 */ { MAD_F(0x06409ef3) /* 0.390776588 */, 18 }, + /* 5727 */ { MAD_F(0x0640fe5e) /* 0.390867585 */, 18 }, + + /* 5728 */ { MAD_F(0x06415dcb) /* 0.390958588 */, 18 }, + /* 5729 */ { MAD_F(0x0641bd38) /* 0.391049596 */, 18 }, + /* 5730 */ { MAD_F(0x06421ca7) /* 0.391140609 */, 18 }, + /* 5731 */ { MAD_F(0x06427c18) /* 0.391231627 */, 18 }, + /* 5732 */ { MAD_F(0x0642db8a) /* 0.391322651 */, 18 }, + /* 5733 */ { MAD_F(0x06433afd) /* 0.391413680 */, 18 }, + /* 5734 */ { MAD_F(0x06439a72) /* 0.391504714 */, 18 }, + /* 5735 */ { MAD_F(0x0643f9e9) /* 0.391595754 */, 18 }, + /* 5736 */ { MAD_F(0x06445960) /* 0.391686799 */, 18 }, + /* 5737 */ { MAD_F(0x0644b8d9) /* 0.391777849 */, 18 }, + /* 5738 */ { MAD_F(0x06451854) /* 0.391868905 */, 18 }, + /* 5739 */ { MAD_F(0x064577d0) /* 0.391959966 */, 18 }, + /* 5740 */ { MAD_F(0x0645d74d) /* 0.392051032 */, 18 }, + /* 5741 */ { MAD_F(0x064636cc) /* 0.392142103 */, 18 }, + /* 5742 */ { MAD_F(0x0646964c) /* 0.392233180 */, 18 }, + /* 5743 */ { MAD_F(0x0646f5ce) /* 0.392324262 */, 18 }, + + /* 5744 */ { MAD_F(0x06475551) /* 0.392415349 */, 18 }, + /* 5745 */ { MAD_F(0x0647b4d5) /* 0.392506442 */, 18 }, + /* 5746 */ { MAD_F(0x0648145b) /* 0.392597540 */, 18 }, + /* 5747 */ { MAD_F(0x064873e3) /* 0.392688643 */, 18 }, + /* 5748 */ { MAD_F(0x0648d36b) /* 0.392779751 */, 18 }, + /* 5749 */ { MAD_F(0x064932f6) /* 0.392870865 */, 18 }, + /* 5750 */ { MAD_F(0x06499281) /* 0.392961984 */, 18 }, + /* 5751 */ { MAD_F(0x0649f20e) /* 0.393053108 */, 18 }, + /* 5752 */ { MAD_F(0x064a519c) /* 0.393144238 */, 18 }, + /* 5753 */ { MAD_F(0x064ab12c) /* 0.393235372 */, 18 }, + /* 5754 */ { MAD_F(0x064b10be) /* 0.393326513 */, 18 }, + /* 5755 */ { MAD_F(0x064b7050) /* 0.393417658 */, 18 }, + /* 5756 */ { MAD_F(0x064bcfe4) /* 0.393508809 */, 18 }, + /* 5757 */ { MAD_F(0x064c2f7a) /* 0.393599965 */, 18 }, + /* 5758 */ { MAD_F(0x064c8f11) /* 0.393691126 */, 18 }, + /* 5759 */ { MAD_F(0x064ceea9) /* 0.393782292 */, 18 }, + + /* 5760 */ { MAD_F(0x064d4e43) /* 0.393873464 */, 18 }, + /* 5761 */ { MAD_F(0x064dadde) /* 0.393964641 */, 18 }, + /* 5762 */ { MAD_F(0x064e0d7a) /* 0.394055823 */, 18 }, + /* 5763 */ { MAD_F(0x064e6d18) /* 0.394147011 */, 18 }, + /* 5764 */ { MAD_F(0x064eccb8) /* 0.394238204 */, 18 }, + /* 5765 */ { MAD_F(0x064f2c59) /* 0.394329402 */, 18 }, + /* 5766 */ { MAD_F(0x064f8bfb) /* 0.394420605 */, 18 }, + /* 5767 */ { MAD_F(0x064feb9e) /* 0.394511814 */, 18 }, + /* 5768 */ { MAD_F(0x06504b44) /* 0.394603028 */, 18 }, + /* 5769 */ { MAD_F(0x0650aaea) /* 0.394694247 */, 18 }, + /* 5770 */ { MAD_F(0x06510a92) /* 0.394785472 */, 18 }, + /* 5771 */ { MAD_F(0x06516a3b) /* 0.394876702 */, 18 }, + /* 5772 */ { MAD_F(0x0651c9e6) /* 0.394967937 */, 18 }, + /* 5773 */ { MAD_F(0x06522992) /* 0.395059177 */, 18 }, + /* 5774 */ { MAD_F(0x06528940) /* 0.395150423 */, 18 }, + /* 5775 */ { MAD_F(0x0652e8ef) /* 0.395241673 */, 18 }, + + /* 5776 */ { MAD_F(0x0653489f) /* 0.395332930 */, 18 }, + /* 5777 */ { MAD_F(0x0653a851) /* 0.395424191 */, 18 }, + /* 5778 */ { MAD_F(0x06540804) /* 0.395515458 */, 18 }, + /* 5779 */ { MAD_F(0x065467b9) /* 0.395606730 */, 18 }, + /* 5780 */ { MAD_F(0x0654c76f) /* 0.395698007 */, 18 }, + /* 5781 */ { MAD_F(0x06552726) /* 0.395789289 */, 18 }, + /* 5782 */ { MAD_F(0x065586df) /* 0.395880577 */, 18 }, + /* 5783 */ { MAD_F(0x0655e699) /* 0.395971870 */, 18 }, + /* 5784 */ { MAD_F(0x06564655) /* 0.396063168 */, 18 }, + /* 5785 */ { MAD_F(0x0656a612) /* 0.396154472 */, 18 }, + /* 5786 */ { MAD_F(0x065705d0) /* 0.396245780 */, 18 }, + /* 5787 */ { MAD_F(0x06576590) /* 0.396337094 */, 18 }, + /* 5788 */ { MAD_F(0x0657c552) /* 0.396428414 */, 18 }, + /* 5789 */ { MAD_F(0x06582514) /* 0.396519738 */, 18 }, + /* 5790 */ { MAD_F(0x065884d9) /* 0.396611068 */, 18 }, + /* 5791 */ { MAD_F(0x0658e49e) /* 0.396702403 */, 18 }, + + /* 5792 */ { MAD_F(0x06594465) /* 0.396793743 */, 18 }, + /* 5793 */ { MAD_F(0x0659a42e) /* 0.396885089 */, 18 }, + /* 5794 */ { MAD_F(0x065a03f7) /* 0.396976440 */, 18 }, + /* 5795 */ { MAD_F(0x065a63c3) /* 0.397067796 */, 18 }, + /* 5796 */ { MAD_F(0x065ac38f) /* 0.397159157 */, 18 }, + /* 5797 */ { MAD_F(0x065b235d) /* 0.397250524 */, 18 }, + /* 5798 */ { MAD_F(0x065b832d) /* 0.397341896 */, 18 }, + /* 5799 */ { MAD_F(0x065be2fe) /* 0.397433273 */, 18 }, + /* 5800 */ { MAD_F(0x065c42d0) /* 0.397524655 */, 18 }, + /* 5801 */ { MAD_F(0x065ca2a3) /* 0.397616043 */, 18 }, + /* 5802 */ { MAD_F(0x065d0279) /* 0.397707436 */, 18 }, + /* 5803 */ { MAD_F(0x065d624f) /* 0.397798834 */, 18 }, + /* 5804 */ { MAD_F(0x065dc227) /* 0.397890237 */, 18 }, + /* 5805 */ { MAD_F(0x065e2200) /* 0.397981646 */, 18 }, + /* 5806 */ { MAD_F(0x065e81db) /* 0.398073059 */, 18 }, + /* 5807 */ { MAD_F(0x065ee1b7) /* 0.398164479 */, 18 }, + + /* 5808 */ { MAD_F(0x065f4195) /* 0.398255903 */, 18 }, + /* 5809 */ { MAD_F(0x065fa174) /* 0.398347333 */, 18 }, + /* 5810 */ { MAD_F(0x06600154) /* 0.398438767 */, 18 }, + /* 5811 */ { MAD_F(0x06606136) /* 0.398530207 */, 18 }, + /* 5812 */ { MAD_F(0x0660c119) /* 0.398621653 */, 18 }, + /* 5813 */ { MAD_F(0x066120fd) /* 0.398713103 */, 18 }, + /* 5814 */ { MAD_F(0x066180e3) /* 0.398804559 */, 18 }, + /* 5815 */ { MAD_F(0x0661e0cb) /* 0.398896020 */, 18 }, + /* 5816 */ { MAD_F(0x066240b4) /* 0.398987487 */, 18 }, + /* 5817 */ { MAD_F(0x0662a09e) /* 0.399078958 */, 18 }, + /* 5818 */ { MAD_F(0x06630089) /* 0.399170435 */, 18 }, + /* 5819 */ { MAD_F(0x06636077) /* 0.399261917 */, 18 }, + /* 5820 */ { MAD_F(0x0663c065) /* 0.399353404 */, 18 }, + /* 5821 */ { MAD_F(0x06642055) /* 0.399444897 */, 18 }, + /* 5822 */ { MAD_F(0x06648046) /* 0.399536395 */, 18 }, + /* 5823 */ { MAD_F(0x0664e039) /* 0.399627898 */, 18 }, + + /* 5824 */ { MAD_F(0x0665402d) /* 0.399719406 */, 18 }, + /* 5825 */ { MAD_F(0x0665a022) /* 0.399810919 */, 18 }, + /* 5826 */ { MAD_F(0x06660019) /* 0.399902438 */, 18 }, + /* 5827 */ { MAD_F(0x06666011) /* 0.399993962 */, 18 }, + /* 5828 */ { MAD_F(0x0666c00b) /* 0.400085491 */, 18 }, + /* 5829 */ { MAD_F(0x06672006) /* 0.400177026 */, 18 }, + /* 5830 */ { MAD_F(0x06678003) /* 0.400268565 */, 18 }, + /* 5831 */ { MAD_F(0x0667e000) /* 0.400360110 */, 18 }, + /* 5832 */ { MAD_F(0x06684000) /* 0.400451660 */, 18 }, + /* 5833 */ { MAD_F(0x0668a000) /* 0.400543216 */, 18 }, + /* 5834 */ { MAD_F(0x06690003) /* 0.400634776 */, 18 }, + /* 5835 */ { MAD_F(0x06696006) /* 0.400726342 */, 18 }, + /* 5836 */ { MAD_F(0x0669c00b) /* 0.400817913 */, 18 }, + /* 5837 */ { MAD_F(0x066a2011) /* 0.400909489 */, 18 }, + /* 5838 */ { MAD_F(0x066a8019) /* 0.401001071 */, 18 }, + /* 5839 */ { MAD_F(0x066ae022) /* 0.401092657 */, 18 }, + + /* 5840 */ { MAD_F(0x066b402d) /* 0.401184249 */, 18 }, + /* 5841 */ { MAD_F(0x066ba039) /* 0.401275847 */, 18 }, + /* 5842 */ { MAD_F(0x066c0046) /* 0.401367449 */, 18 }, + /* 5843 */ { MAD_F(0x066c6055) /* 0.401459057 */, 18 }, + /* 5844 */ { MAD_F(0x066cc065) /* 0.401550670 */, 18 }, + /* 5845 */ { MAD_F(0x066d2076) /* 0.401642288 */, 18 }, + /* 5846 */ { MAD_F(0x066d8089) /* 0.401733911 */, 18 }, + /* 5847 */ { MAD_F(0x066de09e) /* 0.401825540 */, 18 }, + /* 5848 */ { MAD_F(0x066e40b3) /* 0.401917173 */, 18 }, + /* 5849 */ { MAD_F(0x066ea0cb) /* 0.402008812 */, 18 }, + /* 5850 */ { MAD_F(0x066f00e3) /* 0.402100457 */, 18 }, + /* 5851 */ { MAD_F(0x066f60fd) /* 0.402192106 */, 18 }, + /* 5852 */ { MAD_F(0x066fc118) /* 0.402283761 */, 18 }, + /* 5853 */ { MAD_F(0x06702135) /* 0.402375420 */, 18 }, + /* 5854 */ { MAD_F(0x06708153) /* 0.402467086 */, 18 }, + /* 5855 */ { MAD_F(0x0670e173) /* 0.402558756 */, 18 }, + + /* 5856 */ { MAD_F(0x06714194) /* 0.402650431 */, 18 }, + /* 5857 */ { MAD_F(0x0671a1b6) /* 0.402742112 */, 18 }, + /* 5858 */ { MAD_F(0x067201da) /* 0.402833798 */, 18 }, + /* 5859 */ { MAD_F(0x067261ff) /* 0.402925489 */, 18 }, + /* 5860 */ { MAD_F(0x0672c226) /* 0.403017186 */, 18 }, + /* 5861 */ { MAD_F(0x0673224e) /* 0.403108887 */, 18 }, + /* 5862 */ { MAD_F(0x06738277) /* 0.403200594 */, 18 }, + /* 5863 */ { MAD_F(0x0673e2a2) /* 0.403292306 */, 18 }, + /* 5864 */ { MAD_F(0x067442ce) /* 0.403384024 */, 18 }, + /* 5865 */ { MAD_F(0x0674a2fc) /* 0.403475746 */, 18 }, + /* 5866 */ { MAD_F(0x0675032b) /* 0.403567474 */, 18 }, + /* 5867 */ { MAD_F(0x0675635b) /* 0.403659207 */, 18 }, + /* 5868 */ { MAD_F(0x0675c38d) /* 0.403750945 */, 18 }, + /* 5869 */ { MAD_F(0x067623c0) /* 0.403842688 */, 18 }, + /* 5870 */ { MAD_F(0x067683f4) /* 0.403934437 */, 18 }, + /* 5871 */ { MAD_F(0x0676e42a) /* 0.404026190 */, 18 }, + + /* 5872 */ { MAD_F(0x06774462) /* 0.404117949 */, 18 }, + /* 5873 */ { MAD_F(0x0677a49b) /* 0.404209714 */, 18 }, + /* 5874 */ { MAD_F(0x067804d5) /* 0.404301483 */, 18 }, + /* 5875 */ { MAD_F(0x06786510) /* 0.404393258 */, 18 }, + /* 5876 */ { MAD_F(0x0678c54d) /* 0.404485037 */, 18 }, + /* 5877 */ { MAD_F(0x0679258c) /* 0.404576822 */, 18 }, + /* 5878 */ { MAD_F(0x067985cb) /* 0.404668613 */, 18 }, + /* 5879 */ { MAD_F(0x0679e60c) /* 0.404760408 */, 18 }, + /* 5880 */ { MAD_F(0x067a464f) /* 0.404852209 */, 18 }, + /* 5881 */ { MAD_F(0x067aa693) /* 0.404944014 */, 18 }, + /* 5882 */ { MAD_F(0x067b06d8) /* 0.405035825 */, 18 }, + /* 5883 */ { MAD_F(0x067b671f) /* 0.405127642 */, 18 }, + /* 5884 */ { MAD_F(0x067bc767) /* 0.405219463 */, 18 }, + /* 5885 */ { MAD_F(0x067c27b1) /* 0.405311290 */, 18 }, + /* 5886 */ { MAD_F(0x067c87fc) /* 0.405403122 */, 18 }, + /* 5887 */ { MAD_F(0x067ce848) /* 0.405494959 */, 18 }, + + /* 5888 */ { MAD_F(0x067d4896) /* 0.405586801 */, 18 }, + /* 5889 */ { MAD_F(0x067da8e5) /* 0.405678648 */, 18 }, + /* 5890 */ { MAD_F(0x067e0935) /* 0.405770501 */, 18 }, + /* 5891 */ { MAD_F(0x067e6987) /* 0.405862359 */, 18 }, + /* 5892 */ { MAD_F(0x067ec9da) /* 0.405954222 */, 18 }, + /* 5893 */ { MAD_F(0x067f2a2f) /* 0.406046090 */, 18 }, + /* 5894 */ { MAD_F(0x067f8a85) /* 0.406137963 */, 18 }, + /* 5895 */ { MAD_F(0x067feadd) /* 0.406229842 */, 18 }, + /* 5896 */ { MAD_F(0x06804b36) /* 0.406321726 */, 18 }, + /* 5897 */ { MAD_F(0x0680ab90) /* 0.406413615 */, 18 }, + /* 5898 */ { MAD_F(0x06810beb) /* 0.406505509 */, 18 }, + /* 5899 */ { MAD_F(0x06816c49) /* 0.406597408 */, 18 }, + /* 5900 */ { MAD_F(0x0681cca7) /* 0.406689313 */, 18 }, + /* 5901 */ { MAD_F(0x06822d07) /* 0.406781223 */, 18 }, + /* 5902 */ { MAD_F(0x06828d68) /* 0.406873138 */, 18 }, + /* 5903 */ { MAD_F(0x0682edcb) /* 0.406965058 */, 18 }, + + /* 5904 */ { MAD_F(0x06834e2f) /* 0.407056983 */, 18 }, + /* 5905 */ { MAD_F(0x0683ae94) /* 0.407148914 */, 18 }, + /* 5906 */ { MAD_F(0x06840efb) /* 0.407240850 */, 18 }, + /* 5907 */ { MAD_F(0x06846f63) /* 0.407332791 */, 18 }, + /* 5908 */ { MAD_F(0x0684cfcd) /* 0.407424737 */, 18 }, + /* 5909 */ { MAD_F(0x06853038) /* 0.407516688 */, 18 }, + /* 5910 */ { MAD_F(0x068590a4) /* 0.407608645 */, 18 }, + /* 5911 */ { MAD_F(0x0685f112) /* 0.407700606 */, 18 }, + /* 5912 */ { MAD_F(0x06865181) /* 0.407792573 */, 18 }, + /* 5913 */ { MAD_F(0x0686b1f2) /* 0.407884545 */, 18 }, + /* 5914 */ { MAD_F(0x06871264) /* 0.407976522 */, 18 }, + /* 5915 */ { MAD_F(0x068772d7) /* 0.408068505 */, 18 }, + /* 5916 */ { MAD_F(0x0687d34c) /* 0.408160492 */, 18 }, + /* 5917 */ { MAD_F(0x068833c2) /* 0.408252485 */, 18 }, + /* 5918 */ { MAD_F(0x06889439) /* 0.408344483 */, 18 }, + /* 5919 */ { MAD_F(0x0688f4b2) /* 0.408436486 */, 18 }, + + /* 5920 */ { MAD_F(0x0689552c) /* 0.408528495 */, 18 }, + /* 5921 */ { MAD_F(0x0689b5a8) /* 0.408620508 */, 18 }, + /* 5922 */ { MAD_F(0x068a1625) /* 0.408712527 */, 18 }, + /* 5923 */ { MAD_F(0x068a76a4) /* 0.408804551 */, 18 }, + /* 5924 */ { MAD_F(0x068ad724) /* 0.408896580 */, 18 }, + /* 5925 */ { MAD_F(0x068b37a5) /* 0.408988614 */, 18 }, + /* 5926 */ { MAD_F(0x068b9827) /* 0.409080653 */, 18 }, + /* 5927 */ { MAD_F(0x068bf8ac) /* 0.409172698 */, 18 }, + /* 5928 */ { MAD_F(0x068c5931) /* 0.409264748 */, 18 }, + /* 5929 */ { MAD_F(0x068cb9b8) /* 0.409356803 */, 18 }, + /* 5930 */ { MAD_F(0x068d1a40) /* 0.409448863 */, 18 }, + /* 5931 */ { MAD_F(0x068d7aca) /* 0.409540928 */, 18 }, + /* 5932 */ { MAD_F(0x068ddb54) /* 0.409632999 */, 18 }, + /* 5933 */ { MAD_F(0x068e3be1) /* 0.409725074 */, 18 }, + /* 5934 */ { MAD_F(0x068e9c6f) /* 0.409817155 */, 18 }, + /* 5935 */ { MAD_F(0x068efcfe) /* 0.409909241 */, 18 }, + + /* 5936 */ { MAD_F(0x068f5d8e) /* 0.410001332 */, 18 }, + /* 5937 */ { MAD_F(0x068fbe20) /* 0.410093428 */, 18 }, + /* 5938 */ { MAD_F(0x06901eb4) /* 0.410185530 */, 18 }, + /* 5939 */ { MAD_F(0x06907f48) /* 0.410277637 */, 18 }, + /* 5940 */ { MAD_F(0x0690dfde) /* 0.410369748 */, 18 }, + /* 5941 */ { MAD_F(0x06914076) /* 0.410461865 */, 18 }, + /* 5942 */ { MAD_F(0x0691a10f) /* 0.410553988 */, 18 }, + /* 5943 */ { MAD_F(0x069201a9) /* 0.410646115 */, 18 }, + /* 5944 */ { MAD_F(0x06926245) /* 0.410738247 */, 18 }, + /* 5945 */ { MAD_F(0x0692c2e2) /* 0.410830385 */, 18 }, + /* 5946 */ { MAD_F(0x06932380) /* 0.410922528 */, 18 }, + /* 5947 */ { MAD_F(0x06938420) /* 0.411014676 */, 18 }, + /* 5948 */ { MAD_F(0x0693e4c1) /* 0.411106829 */, 18 }, + /* 5949 */ { MAD_F(0x06944563) /* 0.411198987 */, 18 }, + /* 5950 */ { MAD_F(0x0694a607) /* 0.411291151 */, 18 }, + /* 5951 */ { MAD_F(0x069506ad) /* 0.411383320 */, 18 }, + + /* 5952 */ { MAD_F(0x06956753) /* 0.411475493 */, 18 }, + /* 5953 */ { MAD_F(0x0695c7fc) /* 0.411567672 */, 18 }, + /* 5954 */ { MAD_F(0x069628a5) /* 0.411659857 */, 18 }, + /* 5955 */ { MAD_F(0x06968950) /* 0.411752046 */, 18 }, + /* 5956 */ { MAD_F(0x0696e9fc) /* 0.411844240 */, 18 }, + /* 5957 */ { MAD_F(0x06974aaa) /* 0.411936440 */, 18 }, + /* 5958 */ { MAD_F(0x0697ab59) /* 0.412028645 */, 18 }, + /* 5959 */ { MAD_F(0x06980c09) /* 0.412120855 */, 18 }, + /* 5960 */ { MAD_F(0x06986cbb) /* 0.412213070 */, 18 }, + /* 5961 */ { MAD_F(0x0698cd6e) /* 0.412305290 */, 18 }, + /* 5962 */ { MAD_F(0x06992e23) /* 0.412397516 */, 18 }, + /* 5963 */ { MAD_F(0x06998ed9) /* 0.412489746 */, 18 }, + /* 5964 */ { MAD_F(0x0699ef90) /* 0.412581982 */, 18 }, + /* 5965 */ { MAD_F(0x069a5049) /* 0.412674223 */, 18 }, + /* 5966 */ { MAD_F(0x069ab103) /* 0.412766469 */, 18 }, + /* 5967 */ { MAD_F(0x069b11bf) /* 0.412858720 */, 18 }, + + /* 5968 */ { MAD_F(0x069b727b) /* 0.412950976 */, 18 }, + /* 5969 */ { MAD_F(0x069bd33a) /* 0.413043238 */, 18 }, + /* 5970 */ { MAD_F(0x069c33f9) /* 0.413135505 */, 18 }, + /* 5971 */ { MAD_F(0x069c94ba) /* 0.413227776 */, 18 }, + /* 5972 */ { MAD_F(0x069cf57d) /* 0.413320053 */, 18 }, + /* 5973 */ { MAD_F(0x069d5641) /* 0.413412335 */, 18 }, + /* 5974 */ { MAD_F(0x069db706) /* 0.413504623 */, 18 }, + /* 5975 */ { MAD_F(0x069e17cc) /* 0.413596915 */, 18 }, + /* 5976 */ { MAD_F(0x069e7894) /* 0.413689213 */, 18 }, + /* 5977 */ { MAD_F(0x069ed95e) /* 0.413781515 */, 18 }, + /* 5978 */ { MAD_F(0x069f3a28) /* 0.413873823 */, 18 }, + /* 5979 */ { MAD_F(0x069f9af4) /* 0.413966136 */, 18 }, + /* 5980 */ { MAD_F(0x069ffbc2) /* 0.414058454 */, 18 }, + /* 5981 */ { MAD_F(0x06a05c91) /* 0.414150778 */, 18 }, + /* 5982 */ { MAD_F(0x06a0bd61) /* 0.414243106 */, 18 }, + /* 5983 */ { MAD_F(0x06a11e32) /* 0.414335440 */, 18 }, + + /* 5984 */ { MAD_F(0x06a17f05) /* 0.414427779 */, 18 }, + /* 5985 */ { MAD_F(0x06a1dfda) /* 0.414520122 */, 18 }, + /* 5986 */ { MAD_F(0x06a240b0) /* 0.414612471 */, 18 }, + /* 5987 */ { MAD_F(0x06a2a187) /* 0.414704826 */, 18 }, + /* 5988 */ { MAD_F(0x06a3025f) /* 0.414797185 */, 18 }, + /* 5989 */ { MAD_F(0x06a36339) /* 0.414889549 */, 18 }, + /* 5990 */ { MAD_F(0x06a3c414) /* 0.414981919 */, 18 }, + /* 5991 */ { MAD_F(0x06a424f1) /* 0.415074294 */, 18 }, + /* 5992 */ { MAD_F(0x06a485cf) /* 0.415166674 */, 18 }, + /* 5993 */ { MAD_F(0x06a4e6ae) /* 0.415259059 */, 18 }, + /* 5994 */ { MAD_F(0x06a5478f) /* 0.415351449 */, 18 }, + /* 5995 */ { MAD_F(0x06a5a871) /* 0.415443844 */, 18 }, + /* 5996 */ { MAD_F(0x06a60955) /* 0.415536244 */, 18 }, + /* 5997 */ { MAD_F(0x06a66a3a) /* 0.415628650 */, 18 }, + /* 5998 */ { MAD_F(0x06a6cb20) /* 0.415721061 */, 18 }, + /* 5999 */ { MAD_F(0x06a72c08) /* 0.415813476 */, 18 }, + + /* 6000 */ { MAD_F(0x06a78cf1) /* 0.415905897 */, 18 }, + /* 6001 */ { MAD_F(0x06a7eddb) /* 0.415998324 */, 18 }, + /* 6002 */ { MAD_F(0x06a84ec7) /* 0.416090755 */, 18 }, + /* 6003 */ { MAD_F(0x06a8afb4) /* 0.416183191 */, 18 }, + /* 6004 */ { MAD_F(0x06a910a3) /* 0.416275633 */, 18 }, + /* 6005 */ { MAD_F(0x06a97193) /* 0.416368079 */, 18 }, + /* 6006 */ { MAD_F(0x06a9d284) /* 0.416460531 */, 18 }, + /* 6007 */ { MAD_F(0x06aa3377) /* 0.416552988 */, 18 }, + /* 6008 */ { MAD_F(0x06aa946b) /* 0.416645450 */, 18 }, + /* 6009 */ { MAD_F(0x06aaf561) /* 0.416737917 */, 18 }, + /* 6010 */ { MAD_F(0x06ab5657) /* 0.416830389 */, 18 }, + /* 6011 */ { MAD_F(0x06abb750) /* 0.416922867 */, 18 }, + /* 6012 */ { MAD_F(0x06ac1849) /* 0.417015349 */, 18 }, + /* 6013 */ { MAD_F(0x06ac7944) /* 0.417107837 */, 18 }, + /* 6014 */ { MAD_F(0x06acda41) /* 0.417200330 */, 18 }, + /* 6015 */ { MAD_F(0x06ad3b3e) /* 0.417292828 */, 18 }, + + /* 6016 */ { MAD_F(0x06ad9c3d) /* 0.417385331 */, 18 }, + /* 6017 */ { MAD_F(0x06adfd3e) /* 0.417477839 */, 18 }, + /* 6018 */ { MAD_F(0x06ae5e40) /* 0.417570352 */, 18 }, + /* 6019 */ { MAD_F(0x06aebf43) /* 0.417662871 */, 18 }, + /* 6020 */ { MAD_F(0x06af2047) /* 0.417755394 */, 18 }, + /* 6021 */ { MAD_F(0x06af814d) /* 0.417847923 */, 18 }, + /* 6022 */ { MAD_F(0x06afe255) /* 0.417940457 */, 18 }, + /* 6023 */ { MAD_F(0x06b0435e) /* 0.418032996 */, 18 }, + /* 6024 */ { MAD_F(0x06b0a468) /* 0.418125540 */, 18 }, + /* 6025 */ { MAD_F(0x06b10573) /* 0.418218089 */, 18 }, + /* 6026 */ { MAD_F(0x06b16680) /* 0.418310643 */, 18 }, + /* 6027 */ { MAD_F(0x06b1c78e) /* 0.418403203 */, 18 }, + /* 6028 */ { MAD_F(0x06b2289e) /* 0.418495767 */, 18 }, + /* 6029 */ { MAD_F(0x06b289af) /* 0.418588337 */, 18 }, + /* 6030 */ { MAD_F(0x06b2eac1) /* 0.418680911 */, 18 }, + /* 6031 */ { MAD_F(0x06b34bd5) /* 0.418773491 */, 18 }, + + /* 6032 */ { MAD_F(0x06b3acea) /* 0.418866076 */, 18 }, + /* 6033 */ { MAD_F(0x06b40e00) /* 0.418958666 */, 18 }, + /* 6034 */ { MAD_F(0x06b46f18) /* 0.419051262 */, 18 }, + /* 6035 */ { MAD_F(0x06b4d031) /* 0.419143862 */, 18 }, + /* 6036 */ { MAD_F(0x06b5314c) /* 0.419236467 */, 18 }, + /* 6037 */ { MAD_F(0x06b59268) /* 0.419329078 */, 18 }, + /* 6038 */ { MAD_F(0x06b5f385) /* 0.419421694 */, 18 }, + /* 6039 */ { MAD_F(0x06b654a4) /* 0.419514314 */, 18 }, + /* 6040 */ { MAD_F(0x06b6b5c4) /* 0.419606940 */, 18 }, + /* 6041 */ { MAD_F(0x06b716e6) /* 0.419699571 */, 18 }, + /* 6042 */ { MAD_F(0x06b77808) /* 0.419792208 */, 18 }, + /* 6043 */ { MAD_F(0x06b7d92d) /* 0.419884849 */, 18 }, + /* 6044 */ { MAD_F(0x06b83a52) /* 0.419977495 */, 18 }, + /* 6045 */ { MAD_F(0x06b89b79) /* 0.420070147 */, 18 }, + /* 6046 */ { MAD_F(0x06b8fca1) /* 0.420162803 */, 18 }, + /* 6047 */ { MAD_F(0x06b95dcb) /* 0.420255465 */, 18 }, + + /* 6048 */ { MAD_F(0x06b9bef6) /* 0.420348132 */, 18 }, + /* 6049 */ { MAD_F(0x06ba2023) /* 0.420440803 */, 18 }, + /* 6050 */ { MAD_F(0x06ba8150) /* 0.420533481 */, 18 }, + /* 6051 */ { MAD_F(0x06bae280) /* 0.420626163 */, 18 }, + /* 6052 */ { MAD_F(0x06bb43b0) /* 0.420718850 */, 18 }, + /* 6053 */ { MAD_F(0x06bba4e2) /* 0.420811542 */, 18 }, + /* 6054 */ { MAD_F(0x06bc0615) /* 0.420904240 */, 18 }, + /* 6055 */ { MAD_F(0x06bc674a) /* 0.420996942 */, 18 }, + /* 6056 */ { MAD_F(0x06bcc880) /* 0.421089650 */, 18 }, + /* 6057 */ { MAD_F(0x06bd29b7) /* 0.421182362 */, 18 }, + /* 6058 */ { MAD_F(0x06bd8af0) /* 0.421275080 */, 18 }, + /* 6059 */ { MAD_F(0x06bdec2a) /* 0.421367803 */, 18 }, + /* 6060 */ { MAD_F(0x06be4d66) /* 0.421460531 */, 18 }, + /* 6061 */ { MAD_F(0x06beaea3) /* 0.421553264 */, 18 }, + /* 6062 */ { MAD_F(0x06bf0fe1) /* 0.421646003 */, 18 }, + /* 6063 */ { MAD_F(0x06bf7120) /* 0.421738746 */, 18 }, + + /* 6064 */ { MAD_F(0x06bfd261) /* 0.421831494 */, 18 }, + /* 6065 */ { MAD_F(0x06c033a4) /* 0.421924248 */, 18 }, + /* 6066 */ { MAD_F(0x06c094e7) /* 0.422017007 */, 18 }, + /* 6067 */ { MAD_F(0x06c0f62c) /* 0.422109770 */, 18 }, + /* 6068 */ { MAD_F(0x06c15773) /* 0.422202539 */, 18 }, + /* 6069 */ { MAD_F(0x06c1b8bb) /* 0.422295313 */, 18 }, + /* 6070 */ { MAD_F(0x06c21a04) /* 0.422388092 */, 18 }, + /* 6071 */ { MAD_F(0x06c27b4e) /* 0.422480876 */, 18 }, + /* 6072 */ { MAD_F(0x06c2dc9a) /* 0.422573665 */, 18 }, + /* 6073 */ { MAD_F(0x06c33de8) /* 0.422666460 */, 18 }, + /* 6074 */ { MAD_F(0x06c39f36) /* 0.422759259 */, 18 }, + /* 6075 */ { MAD_F(0x06c40086) /* 0.422852064 */, 18 }, + /* 6076 */ { MAD_F(0x06c461d8) /* 0.422944873 */, 18 }, + /* 6077 */ { MAD_F(0x06c4c32a) /* 0.423037688 */, 18 }, + /* 6078 */ { MAD_F(0x06c5247f) /* 0.423130508 */, 18 }, + /* 6079 */ { MAD_F(0x06c585d4) /* 0.423223333 */, 18 }, + + /* 6080 */ { MAD_F(0x06c5e72b) /* 0.423316162 */, 18 }, + /* 6081 */ { MAD_F(0x06c64883) /* 0.423408997 */, 18 }, + /* 6082 */ { MAD_F(0x06c6a9dd) /* 0.423501838 */, 18 }, + /* 6083 */ { MAD_F(0x06c70b38) /* 0.423594683 */, 18 }, + /* 6084 */ { MAD_F(0x06c76c94) /* 0.423687533 */, 18 }, + /* 6085 */ { MAD_F(0x06c7cdf2) /* 0.423780389 */, 18 }, + /* 6086 */ { MAD_F(0x06c82f51) /* 0.423873249 */, 18 }, + /* 6087 */ { MAD_F(0x06c890b1) /* 0.423966115 */, 18 }, + /* 6088 */ { MAD_F(0x06c8f213) /* 0.424058985 */, 18 }, + /* 6089 */ { MAD_F(0x06c95376) /* 0.424151861 */, 18 }, + /* 6090 */ { MAD_F(0x06c9b4da) /* 0.424244742 */, 18 }, + /* 6091 */ { MAD_F(0x06ca1640) /* 0.424337628 */, 18 }, + /* 6092 */ { MAD_F(0x06ca77a8) /* 0.424430519 */, 18 }, + /* 6093 */ { MAD_F(0x06cad910) /* 0.424523415 */, 18 }, + /* 6094 */ { MAD_F(0x06cb3a7a) /* 0.424616316 */, 18 }, + /* 6095 */ { MAD_F(0x06cb9be5) /* 0.424709222 */, 18 }, + + /* 6096 */ { MAD_F(0x06cbfd52) /* 0.424802133 */, 18 }, + /* 6097 */ { MAD_F(0x06cc5ec0) /* 0.424895050 */, 18 }, + /* 6098 */ { MAD_F(0x06ccc030) /* 0.424987971 */, 18 }, + /* 6099 */ { MAD_F(0x06cd21a0) /* 0.425080898 */, 18 }, + /* 6100 */ { MAD_F(0x06cd8313) /* 0.425173829 */, 18 }, + /* 6101 */ { MAD_F(0x06cde486) /* 0.425266766 */, 18 }, + /* 6102 */ { MAD_F(0x06ce45fb) /* 0.425359708 */, 18 }, + /* 6103 */ { MAD_F(0x06cea771) /* 0.425452655 */, 18 }, + /* 6104 */ { MAD_F(0x06cf08e9) /* 0.425545607 */, 18 }, + /* 6105 */ { MAD_F(0x06cf6a62) /* 0.425638564 */, 18 }, + /* 6106 */ { MAD_F(0x06cfcbdc) /* 0.425731526 */, 18 }, + /* 6107 */ { MAD_F(0x06d02d58) /* 0.425824493 */, 18 }, + /* 6108 */ { MAD_F(0x06d08ed5) /* 0.425917465 */, 18 }, + /* 6109 */ { MAD_F(0x06d0f053) /* 0.426010443 */, 18 }, + /* 6110 */ { MAD_F(0x06d151d3) /* 0.426103425 */, 18 }, + /* 6111 */ { MAD_F(0x06d1b354) /* 0.426196412 */, 18 }, + + /* 6112 */ { MAD_F(0x06d214d7) /* 0.426289405 */, 18 }, + /* 6113 */ { MAD_F(0x06d2765a) /* 0.426382403 */, 18 }, + /* 6114 */ { MAD_F(0x06d2d7e0) /* 0.426475405 */, 18 }, + /* 6115 */ { MAD_F(0x06d33966) /* 0.426568413 */, 18 }, + /* 6116 */ { MAD_F(0x06d39aee) /* 0.426661426 */, 18 }, + /* 6117 */ { MAD_F(0x06d3fc77) /* 0.426754444 */, 18 }, + /* 6118 */ { MAD_F(0x06d45e02) /* 0.426847467 */, 18 }, + /* 6119 */ { MAD_F(0x06d4bf8e) /* 0.426940495 */, 18 }, + /* 6120 */ { MAD_F(0x06d5211c) /* 0.427033528 */, 18 }, + /* 6121 */ { MAD_F(0x06d582aa) /* 0.427126566 */, 18 }, + /* 6122 */ { MAD_F(0x06d5e43a) /* 0.427219609 */, 18 }, + /* 6123 */ { MAD_F(0x06d645cc) /* 0.427312657 */, 18 }, + /* 6124 */ { MAD_F(0x06d6a75f) /* 0.427405711 */, 18 }, + /* 6125 */ { MAD_F(0x06d708f3) /* 0.427498769 */, 18 }, + /* 6126 */ { MAD_F(0x06d76a88) /* 0.427591833 */, 18 }, + /* 6127 */ { MAD_F(0x06d7cc1f) /* 0.427684901 */, 18 }, + + /* 6128 */ { MAD_F(0x06d82db8) /* 0.427777975 */, 18 }, + /* 6129 */ { MAD_F(0x06d88f51) /* 0.427871054 */, 18 }, + /* 6130 */ { MAD_F(0x06d8f0ec) /* 0.427964137 */, 18 }, + /* 6131 */ { MAD_F(0x06d95288) /* 0.428057226 */, 18 }, + /* 6132 */ { MAD_F(0x06d9b426) /* 0.428150320 */, 18 }, + /* 6133 */ { MAD_F(0x06da15c5) /* 0.428243419 */, 18 }, + /* 6134 */ { MAD_F(0x06da7766) /* 0.428336523 */, 18 }, + /* 6135 */ { MAD_F(0x06dad907) /* 0.428429632 */, 18 }, + /* 6136 */ { MAD_F(0x06db3aaa) /* 0.428522746 */, 18 }, + /* 6137 */ { MAD_F(0x06db9c4f) /* 0.428615865 */, 18 }, + /* 6138 */ { MAD_F(0x06dbfdf5) /* 0.428708989 */, 18 }, + /* 6139 */ { MAD_F(0x06dc5f9c) /* 0.428802119 */, 18 }, + /* 6140 */ { MAD_F(0x06dcc145) /* 0.428895253 */, 18 }, + /* 6141 */ { MAD_F(0x06dd22ee) /* 0.428988392 */, 18 }, + /* 6142 */ { MAD_F(0x06dd849a) /* 0.429081537 */, 18 }, + /* 6143 */ { MAD_F(0x06dde646) /* 0.429174686 */, 18 }, + + /* 6144 */ { MAD_F(0x06de47f4) /* 0.429267841 */, 18 }, + /* 6145 */ { MAD_F(0x06dea9a4) /* 0.429361001 */, 18 }, + /* 6146 */ { MAD_F(0x06df0b54) /* 0.429454165 */, 18 }, + /* 6147 */ { MAD_F(0x06df6d06) /* 0.429547335 */, 18 }, + /* 6148 */ { MAD_F(0x06dfceba) /* 0.429640510 */, 18 }, + /* 6149 */ { MAD_F(0x06e0306f) /* 0.429733690 */, 18 }, + /* 6150 */ { MAD_F(0x06e09225) /* 0.429826874 */, 18 }, + /* 6151 */ { MAD_F(0x06e0f3dc) /* 0.429920064 */, 18 }, + /* 6152 */ { MAD_F(0x06e15595) /* 0.430013259 */, 18 }, + /* 6153 */ { MAD_F(0x06e1b74f) /* 0.430106459 */, 18 }, + /* 6154 */ { MAD_F(0x06e2190b) /* 0.430199664 */, 18 }, + /* 6155 */ { MAD_F(0x06e27ac8) /* 0.430292875 */, 18 }, + /* 6156 */ { MAD_F(0x06e2dc86) /* 0.430386090 */, 18 }, + /* 6157 */ { MAD_F(0x06e33e46) /* 0.430479310 */, 18 }, + /* 6158 */ { MAD_F(0x06e3a007) /* 0.430572535 */, 18 }, + /* 6159 */ { MAD_F(0x06e401c9) /* 0.430665765 */, 18 }, + + /* 6160 */ { MAD_F(0x06e4638d) /* 0.430759001 */, 18 }, + /* 6161 */ { MAD_F(0x06e4c552) /* 0.430852241 */, 18 }, + /* 6162 */ { MAD_F(0x06e52718) /* 0.430945487 */, 18 }, + /* 6163 */ { MAD_F(0x06e588e0) /* 0.431038737 */, 18 }, + /* 6164 */ { MAD_F(0x06e5eaa9) /* 0.431131993 */, 18 }, + /* 6165 */ { MAD_F(0x06e64c73) /* 0.431225253 */, 18 }, + /* 6166 */ { MAD_F(0x06e6ae3f) /* 0.431318519 */, 18 }, + /* 6167 */ { MAD_F(0x06e7100c) /* 0.431411790 */, 18 }, + /* 6168 */ { MAD_F(0x06e771db) /* 0.431505065 */, 18 }, + /* 6169 */ { MAD_F(0x06e7d3ab) /* 0.431598346 */, 18 }, + /* 6170 */ { MAD_F(0x06e8357c) /* 0.431691632 */, 18 }, + /* 6171 */ { MAD_F(0x06e8974e) /* 0.431784923 */, 18 }, + /* 6172 */ { MAD_F(0x06e8f922) /* 0.431878218 */, 18 }, + /* 6173 */ { MAD_F(0x06e95af8) /* 0.431971519 */, 18 }, + /* 6174 */ { MAD_F(0x06e9bcce) /* 0.432064825 */, 18 }, + /* 6175 */ { MAD_F(0x06ea1ea6) /* 0.432158136 */, 18 }, + + /* 6176 */ { MAD_F(0x06ea807f) /* 0.432251452 */, 18 }, + /* 6177 */ { MAD_F(0x06eae25a) /* 0.432344773 */, 18 }, + /* 6178 */ { MAD_F(0x06eb4436) /* 0.432438099 */, 18 }, + /* 6179 */ { MAD_F(0x06eba614) /* 0.432531431 */, 18 }, + /* 6180 */ { MAD_F(0x06ec07f2) /* 0.432624767 */, 18 }, + /* 6181 */ { MAD_F(0x06ec69d2) /* 0.432718108 */, 18 }, + /* 6182 */ { MAD_F(0x06eccbb4) /* 0.432811454 */, 18 }, + /* 6183 */ { MAD_F(0x06ed2d97) /* 0.432904805 */, 18 }, + /* 6184 */ { MAD_F(0x06ed8f7b) /* 0.432998162 */, 18 }, + /* 6185 */ { MAD_F(0x06edf160) /* 0.433091523 */, 18 }, + /* 6186 */ { MAD_F(0x06ee5347) /* 0.433184889 */, 18 }, + /* 6187 */ { MAD_F(0x06eeb52f) /* 0.433278261 */, 18 }, + /* 6188 */ { MAD_F(0x06ef1719) /* 0.433371637 */, 18 }, + /* 6189 */ { MAD_F(0x06ef7904) /* 0.433465019 */, 18 }, + /* 6190 */ { MAD_F(0x06efdaf0) /* 0.433558405 */, 18 }, + /* 6191 */ { MAD_F(0x06f03cde) /* 0.433651797 */, 18 }, + + /* 6192 */ { MAD_F(0x06f09ecc) /* 0.433745193 */, 18 }, + /* 6193 */ { MAD_F(0x06f100bd) /* 0.433838595 */, 18 }, + /* 6194 */ { MAD_F(0x06f162ae) /* 0.433932001 */, 18 }, + /* 6195 */ { MAD_F(0x06f1c4a1) /* 0.434025413 */, 18 }, + /* 6196 */ { MAD_F(0x06f22696) /* 0.434118830 */, 18 }, + /* 6197 */ { MAD_F(0x06f2888b) /* 0.434212251 */, 18 }, + /* 6198 */ { MAD_F(0x06f2ea82) /* 0.434305678 */, 18 }, + /* 6199 */ { MAD_F(0x06f34c7b) /* 0.434399110 */, 18 }, + /* 6200 */ { MAD_F(0x06f3ae75) /* 0.434492546 */, 18 }, + /* 6201 */ { MAD_F(0x06f41070) /* 0.434585988 */, 18 }, + /* 6202 */ { MAD_F(0x06f4726c) /* 0.434679435 */, 18 }, + /* 6203 */ { MAD_F(0x06f4d46a) /* 0.434772887 */, 18 }, + /* 6204 */ { MAD_F(0x06f53669) /* 0.434866344 */, 18 }, + /* 6205 */ { MAD_F(0x06f59869) /* 0.434959806 */, 18 }, + /* 6206 */ { MAD_F(0x06f5fa6b) /* 0.435053272 */, 18 }, + /* 6207 */ { MAD_F(0x06f65c6e) /* 0.435146744 */, 18 }, + + /* 6208 */ { MAD_F(0x06f6be73) /* 0.435240221 */, 18 }, + /* 6209 */ { MAD_F(0x06f72079) /* 0.435333703 */, 18 }, + /* 6210 */ { MAD_F(0x06f78280) /* 0.435427190 */, 18 }, + /* 6211 */ { MAD_F(0x06f7e489) /* 0.435520682 */, 18 }, + /* 6212 */ { MAD_F(0x06f84693) /* 0.435614179 */, 18 }, + /* 6213 */ { MAD_F(0x06f8a89e) /* 0.435707681 */, 18 }, + /* 6214 */ { MAD_F(0x06f90aaa) /* 0.435801188 */, 18 }, + /* 6215 */ { MAD_F(0x06f96cb8) /* 0.435894700 */, 18 }, + /* 6216 */ { MAD_F(0x06f9cec8) /* 0.435988217 */, 18 }, + /* 6217 */ { MAD_F(0x06fa30d8) /* 0.436081739 */, 18 }, + /* 6218 */ { MAD_F(0x06fa92ea) /* 0.436175266 */, 18 }, + /* 6219 */ { MAD_F(0x06faf4fe) /* 0.436268799 */, 18 }, + /* 6220 */ { MAD_F(0x06fb5712) /* 0.436362336 */, 18 }, + /* 6221 */ { MAD_F(0x06fbb928) /* 0.436455878 */, 18 }, + /* 6222 */ { MAD_F(0x06fc1b40) /* 0.436549425 */, 18 }, + /* 6223 */ { MAD_F(0x06fc7d58) /* 0.436642977 */, 18 }, + + /* 6224 */ { MAD_F(0x06fcdf72) /* 0.436736534 */, 18 }, + /* 6225 */ { MAD_F(0x06fd418e) /* 0.436830096 */, 18 }, + /* 6226 */ { MAD_F(0x06fda3ab) /* 0.436923664 */, 18 }, + /* 6227 */ { MAD_F(0x06fe05c9) /* 0.437017236 */, 18 }, + /* 6228 */ { MAD_F(0x06fe67e8) /* 0.437110813 */, 18 }, + /* 6229 */ { MAD_F(0x06feca09) /* 0.437204395 */, 18 }, + /* 6230 */ { MAD_F(0x06ff2c2b) /* 0.437297982 */, 18 }, + /* 6231 */ { MAD_F(0x06ff8e4f) /* 0.437391575 */, 18 }, + /* 6232 */ { MAD_F(0x06fff073) /* 0.437485172 */, 18 }, + /* 6233 */ { MAD_F(0x0700529a) /* 0.437578774 */, 18 }, + /* 6234 */ { MAD_F(0x0700b4c1) /* 0.437672381 */, 18 }, + /* 6235 */ { MAD_F(0x070116ea) /* 0.437765994 */, 18 }, + /* 6236 */ { MAD_F(0x07017914) /* 0.437859611 */, 18 }, + /* 6237 */ { MAD_F(0x0701db40) /* 0.437953233 */, 18 }, + /* 6238 */ { MAD_F(0x07023d6c) /* 0.438046860 */, 18 }, + /* 6239 */ { MAD_F(0x07029f9b) /* 0.438140493 */, 18 }, + + /* 6240 */ { MAD_F(0x070301ca) /* 0.438234130 */, 18 }, + /* 6241 */ { MAD_F(0x070363fb) /* 0.438327772 */, 18 }, + /* 6242 */ { MAD_F(0x0703c62d) /* 0.438421419 */, 18 }, + /* 6243 */ { MAD_F(0x07042861) /* 0.438515072 */, 18 }, + /* 6244 */ { MAD_F(0x07048a96) /* 0.438608729 */, 18 }, + /* 6245 */ { MAD_F(0x0704eccc) /* 0.438702391 */, 18 }, + /* 6246 */ { MAD_F(0x07054f04) /* 0.438796059 */, 18 }, + /* 6247 */ { MAD_F(0x0705b13d) /* 0.438889731 */, 18 }, + /* 6248 */ { MAD_F(0x07061377) /* 0.438983408 */, 18 }, + /* 6249 */ { MAD_F(0x070675b3) /* 0.439077090 */, 18 }, + /* 6250 */ { MAD_F(0x0706d7f0) /* 0.439170778 */, 18 }, + /* 6251 */ { MAD_F(0x07073a2e) /* 0.439264470 */, 18 }, + /* 6252 */ { MAD_F(0x07079c6e) /* 0.439358167 */, 18 }, + /* 6253 */ { MAD_F(0x0707feaf) /* 0.439451869 */, 18 }, + /* 6254 */ { MAD_F(0x070860f1) /* 0.439545577 */, 18 }, + /* 6255 */ { MAD_F(0x0708c335) /* 0.439639289 */, 18 }, + + /* 6256 */ { MAD_F(0x0709257a) /* 0.439733006 */, 18 }, + /* 6257 */ { MAD_F(0x070987c0) /* 0.439826728 */, 18 }, + /* 6258 */ { MAD_F(0x0709ea08) /* 0.439920456 */, 18 }, + /* 6259 */ { MAD_F(0x070a4c51) /* 0.440014188 */, 18 }, + /* 6260 */ { MAD_F(0x070aae9b) /* 0.440107925 */, 18 }, + /* 6261 */ { MAD_F(0x070b10e7) /* 0.440201667 */, 18 }, + /* 6262 */ { MAD_F(0x070b7334) /* 0.440295414 */, 18 }, + /* 6263 */ { MAD_F(0x070bd583) /* 0.440389167 */, 18 }, + /* 6264 */ { MAD_F(0x070c37d2) /* 0.440482924 */, 18 }, + /* 6265 */ { MAD_F(0x070c9a23) /* 0.440576686 */, 18 }, + /* 6266 */ { MAD_F(0x070cfc76) /* 0.440670453 */, 18 }, + /* 6267 */ { MAD_F(0x070d5eca) /* 0.440764225 */, 18 }, + /* 6268 */ { MAD_F(0x070dc11f) /* 0.440858002 */, 18 }, + /* 6269 */ { MAD_F(0x070e2375) /* 0.440951784 */, 18 }, + /* 6270 */ { MAD_F(0x070e85cd) /* 0.441045572 */, 18 }, + /* 6271 */ { MAD_F(0x070ee826) /* 0.441139364 */, 18 }, + + /* 6272 */ { MAD_F(0x070f4a80) /* 0.441233161 */, 18 }, + /* 6273 */ { MAD_F(0x070facdc) /* 0.441326963 */, 18 }, + /* 6274 */ { MAD_F(0x07100f39) /* 0.441420770 */, 18 }, + /* 6275 */ { MAD_F(0x07107198) /* 0.441514582 */, 18 }, + /* 6276 */ { MAD_F(0x0710d3f8) /* 0.441608399 */, 18 }, + /* 6277 */ { MAD_F(0x07113659) /* 0.441702221 */, 18 }, + /* 6278 */ { MAD_F(0x071198bb) /* 0.441796048 */, 18 }, + /* 6279 */ { MAD_F(0x0711fb1f) /* 0.441889880 */, 18 }, + /* 6280 */ { MAD_F(0x07125d84) /* 0.441983717 */, 18 }, + /* 6281 */ { MAD_F(0x0712bfeb) /* 0.442077559 */, 18 }, + /* 6282 */ { MAD_F(0x07132253) /* 0.442171406 */, 18 }, + /* 6283 */ { MAD_F(0x071384bc) /* 0.442265257 */, 18 }, + /* 6284 */ { MAD_F(0x0713e726) /* 0.442359114 */, 18 }, + /* 6285 */ { MAD_F(0x07144992) /* 0.442452976 */, 18 }, + /* 6286 */ { MAD_F(0x0714abff) /* 0.442546843 */, 18 }, + /* 6287 */ { MAD_F(0x07150e6e) /* 0.442640715 */, 18 }, + + /* 6288 */ { MAD_F(0x071570de) /* 0.442734592 */, 18 }, + /* 6289 */ { MAD_F(0x0715d34f) /* 0.442828473 */, 18 }, + /* 6290 */ { MAD_F(0x071635c1) /* 0.442922360 */, 18 }, + /* 6291 */ { MAD_F(0x07169835) /* 0.443016252 */, 18 }, + /* 6292 */ { MAD_F(0x0716faaa) /* 0.443110148 */, 18 }, + /* 6293 */ { MAD_F(0x07175d21) /* 0.443204050 */, 18 }, + /* 6294 */ { MAD_F(0x0717bf99) /* 0.443297957 */, 18 }, + /* 6295 */ { MAD_F(0x07182212) /* 0.443391868 */, 18 }, + /* 6296 */ { MAD_F(0x0718848d) /* 0.443485785 */, 18 }, + /* 6297 */ { MAD_F(0x0718e709) /* 0.443579706 */, 18 }, + /* 6298 */ { MAD_F(0x07194986) /* 0.443673633 */, 18 }, + /* 6299 */ { MAD_F(0x0719ac04) /* 0.443767564 */, 18 }, + /* 6300 */ { MAD_F(0x071a0e84) /* 0.443861501 */, 18 }, + /* 6301 */ { MAD_F(0x071a7105) /* 0.443955442 */, 18 }, + /* 6302 */ { MAD_F(0x071ad388) /* 0.444049389 */, 18 }, + /* 6303 */ { MAD_F(0x071b360c) /* 0.444143340 */, 18 }, + + /* 6304 */ { MAD_F(0x071b9891) /* 0.444237296 */, 18 }, + /* 6305 */ { MAD_F(0x071bfb18) /* 0.444331258 */, 18 }, + /* 6306 */ { MAD_F(0x071c5d9f) /* 0.444425224 */, 18 }, + /* 6307 */ { MAD_F(0x071cc029) /* 0.444519195 */, 18 }, + /* 6308 */ { MAD_F(0x071d22b3) /* 0.444613171 */, 18 }, + /* 6309 */ { MAD_F(0x071d853f) /* 0.444707153 */, 18 }, + /* 6310 */ { MAD_F(0x071de7cc) /* 0.444801139 */, 18 }, + /* 6311 */ { MAD_F(0x071e4a5b) /* 0.444895130 */, 18 }, + /* 6312 */ { MAD_F(0x071eaceb) /* 0.444989126 */, 18 }, + /* 6313 */ { MAD_F(0x071f0f7c) /* 0.445083127 */, 18 }, + /* 6314 */ { MAD_F(0x071f720e) /* 0.445177133 */, 18 }, + /* 6315 */ { MAD_F(0x071fd4a2) /* 0.445271144 */, 18 }, + /* 6316 */ { MAD_F(0x07203737) /* 0.445365160 */, 18 }, + /* 6317 */ { MAD_F(0x072099ce) /* 0.445459181 */, 18 }, + /* 6318 */ { MAD_F(0x0720fc66) /* 0.445553206 */, 18 }, + /* 6319 */ { MAD_F(0x07215eff) /* 0.445647237 */, 18 }, + + /* 6320 */ { MAD_F(0x0721c19a) /* 0.445741273 */, 18 }, + /* 6321 */ { MAD_F(0x07222436) /* 0.445835314 */, 18 }, + /* 6322 */ { MAD_F(0x072286d3) /* 0.445929359 */, 18 }, + /* 6323 */ { MAD_F(0x0722e971) /* 0.446023410 */, 18 }, + /* 6324 */ { MAD_F(0x07234c11) /* 0.446117466 */, 18 }, + /* 6325 */ { MAD_F(0x0723aeb2) /* 0.446211526 */, 18 }, + /* 6326 */ { MAD_F(0x07241155) /* 0.446305592 */, 18 }, + /* 6327 */ { MAD_F(0x072473f9) /* 0.446399662 */, 18 }, + /* 6328 */ { MAD_F(0x0724d69e) /* 0.446493738 */, 18 }, + /* 6329 */ { MAD_F(0x07253944) /* 0.446587818 */, 18 }, + /* 6330 */ { MAD_F(0x07259bec) /* 0.446681903 */, 18 }, + /* 6331 */ { MAD_F(0x0725fe95) /* 0.446775994 */, 18 }, + /* 6332 */ { MAD_F(0x07266140) /* 0.446870089 */, 18 }, + /* 6333 */ { MAD_F(0x0726c3ec) /* 0.446964189 */, 18 }, + /* 6334 */ { MAD_F(0x07272699) /* 0.447058294 */, 18 }, + /* 6335 */ { MAD_F(0x07278947) /* 0.447152404 */, 18 }, + + /* 6336 */ { MAD_F(0x0727ebf7) /* 0.447246519 */, 18 }, + /* 6337 */ { MAD_F(0x07284ea8) /* 0.447340639 */, 18 }, + /* 6338 */ { MAD_F(0x0728b15b) /* 0.447434764 */, 18 }, + /* 6339 */ { MAD_F(0x0729140f) /* 0.447528894 */, 18 }, + /* 6340 */ { MAD_F(0x072976c4) /* 0.447623029 */, 18 }, + /* 6341 */ { MAD_F(0x0729d97a) /* 0.447717169 */, 18 }, + /* 6342 */ { MAD_F(0x072a3c32) /* 0.447811314 */, 18 }, + /* 6343 */ { MAD_F(0x072a9eeb) /* 0.447905463 */, 18 }, + /* 6344 */ { MAD_F(0x072b01a6) /* 0.447999618 */, 18 }, + /* 6345 */ { MAD_F(0x072b6461) /* 0.448093778 */, 18 }, + /* 6346 */ { MAD_F(0x072bc71e) /* 0.448187942 */, 18 }, + /* 6347 */ { MAD_F(0x072c29dd) /* 0.448282112 */, 18 }, + /* 6348 */ { MAD_F(0x072c8c9d) /* 0.448376286 */, 18 }, + /* 6349 */ { MAD_F(0x072cef5e) /* 0.448470466 */, 18 }, + /* 6350 */ { MAD_F(0x072d5220) /* 0.448564650 */, 18 }, + /* 6351 */ { MAD_F(0x072db4e4) /* 0.448658839 */, 18 }, + + /* 6352 */ { MAD_F(0x072e17a9) /* 0.448753033 */, 18 }, + /* 6353 */ { MAD_F(0x072e7a6f) /* 0.448847233 */, 18 }, + /* 6354 */ { MAD_F(0x072edd37) /* 0.448941437 */, 18 }, + /* 6355 */ { MAD_F(0x072f4000) /* 0.449035646 */, 18 }, + /* 6356 */ { MAD_F(0x072fa2ca) /* 0.449129860 */, 18 }, + /* 6357 */ { MAD_F(0x07300596) /* 0.449224079 */, 18 }, + /* 6358 */ { MAD_F(0x07306863) /* 0.449318303 */, 18 }, + /* 6359 */ { MAD_F(0x0730cb32) /* 0.449412531 */, 18 }, + /* 6360 */ { MAD_F(0x07312e01) /* 0.449506765 */, 18 }, + /* 6361 */ { MAD_F(0x073190d2) /* 0.449601004 */, 18 }, + /* 6362 */ { MAD_F(0x0731f3a5) /* 0.449695247 */, 18 }, + /* 6363 */ { MAD_F(0x07325678) /* 0.449789496 */, 18 }, + /* 6364 */ { MAD_F(0x0732b94d) /* 0.449883749 */, 18 }, + /* 6365 */ { MAD_F(0x07331c23) /* 0.449978008 */, 18 }, + /* 6366 */ { MAD_F(0x07337efb) /* 0.450072271 */, 18 }, + /* 6367 */ { MAD_F(0x0733e1d4) /* 0.450166540 */, 18 }, + + /* 6368 */ { MAD_F(0x073444ae) /* 0.450260813 */, 18 }, + /* 6369 */ { MAD_F(0x0734a78a) /* 0.450355091 */, 18 }, + /* 6370 */ { MAD_F(0x07350a67) /* 0.450449374 */, 18 }, + /* 6371 */ { MAD_F(0x07356d45) /* 0.450543662 */, 18 }, + /* 6372 */ { MAD_F(0x0735d025) /* 0.450637955 */, 18 }, + /* 6373 */ { MAD_F(0x07363306) /* 0.450732253 */, 18 }, + /* 6374 */ { MAD_F(0x073695e8) /* 0.450826556 */, 18 }, + /* 6375 */ { MAD_F(0x0736f8cb) /* 0.450920864 */, 18 }, + /* 6376 */ { MAD_F(0x07375bb0) /* 0.451015176 */, 18 }, + /* 6377 */ { MAD_F(0x0737be96) /* 0.451109494 */, 18 }, + /* 6378 */ { MAD_F(0x0738217e) /* 0.451203817 */, 18 }, + /* 6379 */ { MAD_F(0x07388467) /* 0.451298144 */, 18 }, + /* 6380 */ { MAD_F(0x0738e751) /* 0.451392477 */, 18 }, + /* 6381 */ { MAD_F(0x07394a3d) /* 0.451486814 */, 18 }, + /* 6382 */ { MAD_F(0x0739ad29) /* 0.451581156 */, 18 }, + /* 6383 */ { MAD_F(0x073a1017) /* 0.451675503 */, 18 }, + + /* 6384 */ { MAD_F(0x073a7307) /* 0.451769856 */, 18 }, + /* 6385 */ { MAD_F(0x073ad5f8) /* 0.451864213 */, 18 }, + /* 6386 */ { MAD_F(0x073b38ea) /* 0.451958575 */, 18 }, + /* 6387 */ { MAD_F(0x073b9bdd) /* 0.452052942 */, 18 }, + /* 6388 */ { MAD_F(0x073bfed2) /* 0.452147313 */, 18 }, + /* 6389 */ { MAD_F(0x073c61c8) /* 0.452241690 */, 18 }, + /* 6390 */ { MAD_F(0x073cc4bf) /* 0.452336072 */, 18 }, + /* 6391 */ { MAD_F(0x073d27b8) /* 0.452430458 */, 18 }, + /* 6392 */ { MAD_F(0x073d8ab2) /* 0.452524850 */, 18 }, + /* 6393 */ { MAD_F(0x073dedae) /* 0.452619246 */, 18 }, + /* 6394 */ { MAD_F(0x073e50aa) /* 0.452713648 */, 18 }, + /* 6395 */ { MAD_F(0x073eb3a8) /* 0.452808054 */, 18 }, + /* 6396 */ { MAD_F(0x073f16a8) /* 0.452902465 */, 18 }, + /* 6397 */ { MAD_F(0x073f79a8) /* 0.452996882 */, 18 }, + /* 6398 */ { MAD_F(0x073fdcaa) /* 0.453091303 */, 18 }, + /* 6399 */ { MAD_F(0x07403fad) /* 0.453185729 */, 18 }, + + /* 6400 */ { MAD_F(0x0740a2b2) /* 0.453280160 */, 18 }, + /* 6401 */ { MAD_F(0x074105b8) /* 0.453374595 */, 18 }, + /* 6402 */ { MAD_F(0x074168bf) /* 0.453469036 */, 18 }, + /* 6403 */ { MAD_F(0x0741cbc8) /* 0.453563482 */, 18 }, + /* 6404 */ { MAD_F(0x07422ed2) /* 0.453657932 */, 18 }, + /* 6405 */ { MAD_F(0x074291dd) /* 0.453752388 */, 18 }, + /* 6406 */ { MAD_F(0x0742f4e9) /* 0.453846848 */, 18 }, + /* 6407 */ { MAD_F(0x074357f7) /* 0.453941314 */, 18 }, + /* 6408 */ { MAD_F(0x0743bb06) /* 0.454035784 */, 18 }, + /* 6409 */ { MAD_F(0x07441e17) /* 0.454130259 */, 18 }, + /* 6410 */ { MAD_F(0x07448129) /* 0.454224739 */, 18 }, + /* 6411 */ { MAD_F(0x0744e43c) /* 0.454319224 */, 18 }, + /* 6412 */ { MAD_F(0x07454750) /* 0.454413714 */, 18 }, + /* 6413 */ { MAD_F(0x0745aa66) /* 0.454508209 */, 18 }, + /* 6414 */ { MAD_F(0x07460d7d) /* 0.454602708 */, 18 }, + /* 6415 */ { MAD_F(0x07467095) /* 0.454697213 */, 18 }, + + /* 6416 */ { MAD_F(0x0746d3af) /* 0.454791723 */, 18 }, + /* 6417 */ { MAD_F(0x074736ca) /* 0.454886237 */, 18 }, + /* 6418 */ { MAD_F(0x074799e7) /* 0.454980756 */, 18 }, + /* 6419 */ { MAD_F(0x0747fd04) /* 0.455075281 */, 18 }, + /* 6420 */ { MAD_F(0x07486023) /* 0.455169810 */, 18 }, + /* 6421 */ { MAD_F(0x0748c344) /* 0.455264344 */, 18 }, + /* 6422 */ { MAD_F(0x07492665) /* 0.455358883 */, 18 }, + /* 6423 */ { MAD_F(0x07498988) /* 0.455453427 */, 18 }, + /* 6424 */ { MAD_F(0x0749ecac) /* 0.455547976 */, 18 }, + /* 6425 */ { MAD_F(0x074a4fd2) /* 0.455642529 */, 18 }, + /* 6426 */ { MAD_F(0x074ab2f9) /* 0.455737088 */, 18 }, + /* 6427 */ { MAD_F(0x074b1621) /* 0.455831652 */, 18 }, + /* 6428 */ { MAD_F(0x074b794b) /* 0.455926220 */, 18 }, + /* 6429 */ { MAD_F(0x074bdc75) /* 0.456020793 */, 18 }, + /* 6430 */ { MAD_F(0x074c3fa1) /* 0.456115372 */, 18 }, + /* 6431 */ { MAD_F(0x074ca2cf) /* 0.456209955 */, 18 }, + + /* 6432 */ { MAD_F(0x074d05fe) /* 0.456304543 */, 18 }, + /* 6433 */ { MAD_F(0x074d692e) /* 0.456399136 */, 18 }, + /* 6434 */ { MAD_F(0x074dcc5f) /* 0.456493733 */, 18 }, + /* 6435 */ { MAD_F(0x074e2f92) /* 0.456588336 */, 18 }, + /* 6436 */ { MAD_F(0x074e92c6) /* 0.456682944 */, 18 }, + /* 6437 */ { MAD_F(0x074ef5fb) /* 0.456777556 */, 18 }, + /* 6438 */ { MAD_F(0x074f5932) /* 0.456872174 */, 18 }, + /* 6439 */ { MAD_F(0x074fbc6a) /* 0.456966796 */, 18 }, + /* 6440 */ { MAD_F(0x07501fa3) /* 0.457061423 */, 18 }, + /* 6441 */ { MAD_F(0x075082de) /* 0.457156056 */, 18 }, + /* 6442 */ { MAD_F(0x0750e61a) /* 0.457250693 */, 18 }, + /* 6443 */ { MAD_F(0x07514957) /* 0.457345335 */, 18 }, + /* 6444 */ { MAD_F(0x0751ac96) /* 0.457439981 */, 18 }, + /* 6445 */ { MAD_F(0x07520fd6) /* 0.457534633 */, 18 }, + /* 6446 */ { MAD_F(0x07527317) /* 0.457629290 */, 18 }, + /* 6447 */ { MAD_F(0x0752d659) /* 0.457723951 */, 18 }, + + /* 6448 */ { MAD_F(0x0753399d) /* 0.457818618 */, 18 }, + /* 6449 */ { MAD_F(0x07539ce2) /* 0.457913289 */, 18 }, + /* 6450 */ { MAD_F(0x07540029) /* 0.458007965 */, 18 }, + /* 6451 */ { MAD_F(0x07546371) /* 0.458102646 */, 18 }, + /* 6452 */ { MAD_F(0x0754c6ba) /* 0.458197332 */, 18 }, + /* 6453 */ { MAD_F(0x07552a04) /* 0.458292023 */, 18 }, + /* 6454 */ { MAD_F(0x07558d50) /* 0.458386719 */, 18 }, + /* 6455 */ { MAD_F(0x0755f09d) /* 0.458481420 */, 18 }, + /* 6456 */ { MAD_F(0x075653eb) /* 0.458576125 */, 18 }, + /* 6457 */ { MAD_F(0x0756b73b) /* 0.458670836 */, 18 }, + /* 6458 */ { MAD_F(0x07571a8c) /* 0.458765551 */, 18 }, + /* 6459 */ { MAD_F(0x07577dde) /* 0.458860271 */, 18 }, + /* 6460 */ { MAD_F(0x0757e131) /* 0.458954996 */, 18 }, + /* 6461 */ { MAD_F(0x07584486) /* 0.459049726 */, 18 }, + /* 6462 */ { MAD_F(0x0758a7dd) /* 0.459144461 */, 18 }, + /* 6463 */ { MAD_F(0x07590b34) /* 0.459239201 */, 18 }, + + /* 6464 */ { MAD_F(0x07596e8d) /* 0.459333946 */, 18 }, + /* 6465 */ { MAD_F(0x0759d1e7) /* 0.459428695 */, 18 }, + /* 6466 */ { MAD_F(0x075a3542) /* 0.459523450 */, 18 }, + /* 6467 */ { MAD_F(0x075a989f) /* 0.459618209 */, 18 }, + /* 6468 */ { MAD_F(0x075afbfd) /* 0.459712973 */, 18 }, + /* 6469 */ { MAD_F(0x075b5f5d) /* 0.459807742 */, 18 }, + /* 6470 */ { MAD_F(0x075bc2bd) /* 0.459902516 */, 18 }, + /* 6471 */ { MAD_F(0x075c261f) /* 0.459997295 */, 18 }, + /* 6472 */ { MAD_F(0x075c8983) /* 0.460092079 */, 18 }, + /* 6473 */ { MAD_F(0x075cece7) /* 0.460186867 */, 18 }, + /* 6474 */ { MAD_F(0x075d504d) /* 0.460281661 */, 18 }, + /* 6475 */ { MAD_F(0x075db3b5) /* 0.460376459 */, 18 }, + /* 6476 */ { MAD_F(0x075e171d) /* 0.460471262 */, 18 }, + /* 6477 */ { MAD_F(0x075e7a87) /* 0.460566071 */, 18 }, + /* 6478 */ { MAD_F(0x075eddf2) /* 0.460660884 */, 18 }, + /* 6479 */ { MAD_F(0x075f415f) /* 0.460755701 */, 18 }, + + /* 6480 */ { MAD_F(0x075fa4cc) /* 0.460850524 */, 18 }, + /* 6481 */ { MAD_F(0x0760083b) /* 0.460945352 */, 18 }, + /* 6482 */ { MAD_F(0x07606bac) /* 0.461040184 */, 18 }, + /* 6483 */ { MAD_F(0x0760cf1e) /* 0.461135022 */, 18 }, + /* 6484 */ { MAD_F(0x07613291) /* 0.461229864 */, 18 }, + /* 6485 */ { MAD_F(0x07619605) /* 0.461324711 */, 18 }, + /* 6486 */ { MAD_F(0x0761f97b) /* 0.461419563 */, 18 }, + /* 6487 */ { MAD_F(0x07625cf2) /* 0.461514420 */, 18 }, + /* 6488 */ { MAD_F(0x0762c06a) /* 0.461609282 */, 18 }, + /* 6489 */ { MAD_F(0x076323e3) /* 0.461704149 */, 18 }, + /* 6490 */ { MAD_F(0x0763875e) /* 0.461799020 */, 18 }, + /* 6491 */ { MAD_F(0x0763eadb) /* 0.461893897 */, 18 }, + /* 6492 */ { MAD_F(0x07644e58) /* 0.461988778 */, 18 }, + /* 6493 */ { MAD_F(0x0764b1d7) /* 0.462083664 */, 18 }, + /* 6494 */ { MAD_F(0x07651557) /* 0.462178555 */, 18 }, + /* 6495 */ { MAD_F(0x076578d8) /* 0.462273451 */, 18 }, + + /* 6496 */ { MAD_F(0x0765dc5b) /* 0.462368352 */, 18 }, + /* 6497 */ { MAD_F(0x07663fdf) /* 0.462463257 */, 18 }, + /* 6498 */ { MAD_F(0x0766a364) /* 0.462558168 */, 18 }, + /* 6499 */ { MAD_F(0x076706eb) /* 0.462653083 */, 18 }, + /* 6500 */ { MAD_F(0x07676a73) /* 0.462748003 */, 18 }, + /* 6501 */ { MAD_F(0x0767cdfc) /* 0.462842928 */, 18 }, + /* 6502 */ { MAD_F(0x07683187) /* 0.462937858 */, 18 }, + /* 6503 */ { MAD_F(0x07689513) /* 0.463032793 */, 18 }, + /* 6504 */ { MAD_F(0x0768f8a0) /* 0.463127733 */, 18 }, + /* 6505 */ { MAD_F(0x07695c2e) /* 0.463222678 */, 18 }, + /* 6506 */ { MAD_F(0x0769bfbe) /* 0.463317627 */, 18 }, + /* 6507 */ { MAD_F(0x076a234f) /* 0.463412581 */, 18 }, + /* 6508 */ { MAD_F(0x076a86e2) /* 0.463507540 */, 18 }, + /* 6509 */ { MAD_F(0x076aea75) /* 0.463602504 */, 18 }, + /* 6510 */ { MAD_F(0x076b4e0a) /* 0.463697473 */, 18 }, + /* 6511 */ { MAD_F(0x076bb1a1) /* 0.463792447 */, 18 }, + + /* 6512 */ { MAD_F(0x076c1538) /* 0.463887426 */, 18 }, + /* 6513 */ { MAD_F(0x076c78d1) /* 0.463982409 */, 18 }, + /* 6514 */ { MAD_F(0x076cdc6c) /* 0.464077398 */, 18 }, + /* 6515 */ { MAD_F(0x076d4007) /* 0.464172391 */, 18 }, + /* 6516 */ { MAD_F(0x076da3a4) /* 0.464267389 */, 18 }, + /* 6517 */ { MAD_F(0x076e0742) /* 0.464362392 */, 18 }, + /* 6518 */ { MAD_F(0x076e6ae2) /* 0.464457399 */, 18 }, + /* 6519 */ { MAD_F(0x076ece82) /* 0.464552412 */, 18 }, + /* 6520 */ { MAD_F(0x076f3224) /* 0.464647430 */, 18 }, + /* 6521 */ { MAD_F(0x076f95c8) /* 0.464742452 */, 18 }, + /* 6522 */ { MAD_F(0x076ff96c) /* 0.464837479 */, 18 }, + /* 6523 */ { MAD_F(0x07705d12) /* 0.464932511 */, 18 }, + /* 6524 */ { MAD_F(0x0770c0ba) /* 0.465027548 */, 18 }, + /* 6525 */ { MAD_F(0x07712462) /* 0.465122590 */, 18 }, + /* 6526 */ { MAD_F(0x0771880c) /* 0.465217637 */, 18 }, + /* 6527 */ { MAD_F(0x0771ebb7) /* 0.465312688 */, 18 }, + + /* 6528 */ { MAD_F(0x07724f64) /* 0.465407744 */, 18 }, + /* 6529 */ { MAD_F(0x0772b312) /* 0.465502806 */, 18 }, + /* 6530 */ { MAD_F(0x077316c1) /* 0.465597872 */, 18 }, + /* 6531 */ { MAD_F(0x07737a71) /* 0.465692943 */, 18 }, + /* 6532 */ { MAD_F(0x0773de23) /* 0.465788018 */, 18 }, + /* 6533 */ { MAD_F(0x077441d6) /* 0.465883099 */, 18 }, + /* 6534 */ { MAD_F(0x0774a58a) /* 0.465978184 */, 18 }, + /* 6535 */ { MAD_F(0x07750940) /* 0.466073275 */, 18 }, + /* 6536 */ { MAD_F(0x07756cf7) /* 0.466168370 */, 18 }, + /* 6537 */ { MAD_F(0x0775d0af) /* 0.466263470 */, 18 }, + /* 6538 */ { MAD_F(0x07763468) /* 0.466358575 */, 18 }, + /* 6539 */ { MAD_F(0x07769823) /* 0.466453684 */, 18 }, + /* 6540 */ { MAD_F(0x0776fbdf) /* 0.466548799 */, 18 }, + /* 6541 */ { MAD_F(0x07775f9d) /* 0.466643918 */, 18 }, + /* 6542 */ { MAD_F(0x0777c35c) /* 0.466739043 */, 18 }, + /* 6543 */ { MAD_F(0x0778271c) /* 0.466834172 */, 18 }, + + /* 6544 */ { MAD_F(0x07788add) /* 0.466929306 */, 18 }, + /* 6545 */ { MAD_F(0x0778ee9f) /* 0.467024445 */, 18 }, + /* 6546 */ { MAD_F(0x07795263) /* 0.467119588 */, 18 }, + /* 6547 */ { MAD_F(0x0779b629) /* 0.467214737 */, 18 }, + /* 6548 */ { MAD_F(0x077a19ef) /* 0.467309890 */, 18 }, + /* 6549 */ { MAD_F(0x077a7db7) /* 0.467405048 */, 18 }, + /* 6550 */ { MAD_F(0x077ae180) /* 0.467500211 */, 18 }, + /* 6551 */ { MAD_F(0x077b454b) /* 0.467595379 */, 18 }, + /* 6552 */ { MAD_F(0x077ba916) /* 0.467690552 */, 18 }, + /* 6553 */ { MAD_F(0x077c0ce3) /* 0.467785729 */, 18 }, + /* 6554 */ { MAD_F(0x077c70b2) /* 0.467880912 */, 18 }, + /* 6555 */ { MAD_F(0x077cd481) /* 0.467976099 */, 18 }, + /* 6556 */ { MAD_F(0x077d3852) /* 0.468071291 */, 18 }, + /* 6557 */ { MAD_F(0x077d9c24) /* 0.468166488 */, 18 }, + /* 6558 */ { MAD_F(0x077dfff8) /* 0.468261690 */, 18 }, + /* 6559 */ { MAD_F(0x077e63cd) /* 0.468356896 */, 18 }, + + /* 6560 */ { MAD_F(0x077ec7a3) /* 0.468452108 */, 18 }, + /* 6561 */ { MAD_F(0x077f2b7a) /* 0.468547324 */, 18 }, + /* 6562 */ { MAD_F(0x077f8f53) /* 0.468642545 */, 18 }, + /* 6563 */ { MAD_F(0x077ff32d) /* 0.468737771 */, 18 }, + /* 6564 */ { MAD_F(0x07805708) /* 0.468833002 */, 18 }, + /* 6565 */ { MAD_F(0x0780bae5) /* 0.468928237 */, 18 }, + /* 6566 */ { MAD_F(0x07811ec3) /* 0.469023478 */, 18 }, + /* 6567 */ { MAD_F(0x078182a2) /* 0.469118723 */, 18 }, + /* 6568 */ { MAD_F(0x0781e683) /* 0.469213973 */, 18 }, + /* 6569 */ { MAD_F(0x07824a64) /* 0.469309228 */, 18 }, + /* 6570 */ { MAD_F(0x0782ae47) /* 0.469404488 */, 18 }, + /* 6571 */ { MAD_F(0x0783122c) /* 0.469499752 */, 18 }, + /* 6572 */ { MAD_F(0x07837612) /* 0.469595022 */, 18 }, + /* 6573 */ { MAD_F(0x0783d9f9) /* 0.469690296 */, 18 }, + /* 6574 */ { MAD_F(0x07843de1) /* 0.469785575 */, 18 }, + /* 6575 */ { MAD_F(0x0784a1ca) /* 0.469880859 */, 18 }, + + /* 6576 */ { MAD_F(0x078505b5) /* 0.469976148 */, 18 }, + /* 6577 */ { MAD_F(0x078569a2) /* 0.470071442 */, 18 }, + /* 6578 */ { MAD_F(0x0785cd8f) /* 0.470166740 */, 18 }, + /* 6579 */ { MAD_F(0x0786317e) /* 0.470262043 */, 18 }, + /* 6580 */ { MAD_F(0x0786956e) /* 0.470357351 */, 18 }, + /* 6581 */ { MAD_F(0x0786f95f) /* 0.470452664 */, 18 }, + /* 6582 */ { MAD_F(0x07875d52) /* 0.470547982 */, 18 }, + /* 6583 */ { MAD_F(0x0787c146) /* 0.470643305 */, 18 }, + /* 6584 */ { MAD_F(0x0788253b) /* 0.470738632 */, 18 }, + /* 6585 */ { MAD_F(0x07888932) /* 0.470833964 */, 18 }, + /* 6586 */ { MAD_F(0x0788ed2a) /* 0.470929301 */, 18 }, + /* 6587 */ { MAD_F(0x07895123) /* 0.471024643 */, 18 }, + /* 6588 */ { MAD_F(0x0789b51d) /* 0.471119990 */, 18 }, + /* 6589 */ { MAD_F(0x078a1919) /* 0.471215341 */, 18 }, + /* 6590 */ { MAD_F(0x078a7d16) /* 0.471310698 */, 18 }, + /* 6591 */ { MAD_F(0x078ae114) /* 0.471406059 */, 18 }, + + /* 6592 */ { MAD_F(0x078b4514) /* 0.471501425 */, 18 }, + /* 6593 */ { MAD_F(0x078ba915) /* 0.471596796 */, 18 }, + /* 6594 */ { MAD_F(0x078c0d17) /* 0.471692171 */, 18 }, + /* 6595 */ { MAD_F(0x078c711a) /* 0.471787552 */, 18 }, + /* 6596 */ { MAD_F(0x078cd51f) /* 0.471882937 */, 18 }, + /* 6597 */ { MAD_F(0x078d3925) /* 0.471978327 */, 18 }, + /* 6598 */ { MAD_F(0x078d9d2d) /* 0.472073722 */, 18 }, + /* 6599 */ { MAD_F(0x078e0135) /* 0.472169122 */, 18 }, + /* 6600 */ { MAD_F(0x078e653f) /* 0.472264527 */, 18 }, + /* 6601 */ { MAD_F(0x078ec94b) /* 0.472359936 */, 18 }, + /* 6602 */ { MAD_F(0x078f2d57) /* 0.472455350 */, 18 }, + /* 6603 */ { MAD_F(0x078f9165) /* 0.472550769 */, 18 }, + /* 6604 */ { MAD_F(0x078ff574) /* 0.472646193 */, 18 }, + /* 6605 */ { MAD_F(0x07905985) /* 0.472741622 */, 18 }, + /* 6606 */ { MAD_F(0x0790bd96) /* 0.472837055 */, 18 }, + /* 6607 */ { MAD_F(0x079121a9) /* 0.472932493 */, 18 }, + + /* 6608 */ { MAD_F(0x079185be) /* 0.473027937 */, 18 }, + /* 6609 */ { MAD_F(0x0791e9d3) /* 0.473123384 */, 18 }, + /* 6610 */ { MAD_F(0x07924dea) /* 0.473218837 */, 18 }, + /* 6611 */ { MAD_F(0x0792b202) /* 0.473314295 */, 18 }, + /* 6612 */ { MAD_F(0x0793161c) /* 0.473409757 */, 18 }, + /* 6613 */ { MAD_F(0x07937a37) /* 0.473505224 */, 18 }, + /* 6614 */ { MAD_F(0x0793de53) /* 0.473600696 */, 18 }, + /* 6615 */ { MAD_F(0x07944270) /* 0.473696173 */, 18 }, + /* 6616 */ { MAD_F(0x0794a68f) /* 0.473791655 */, 18 }, + /* 6617 */ { MAD_F(0x07950aaf) /* 0.473887141 */, 18 }, + /* 6618 */ { MAD_F(0x07956ed0) /* 0.473982632 */, 18 }, + /* 6619 */ { MAD_F(0x0795d2f2) /* 0.474078128 */, 18 }, + /* 6620 */ { MAD_F(0x07963716) /* 0.474173629 */, 18 }, + /* 6621 */ { MAD_F(0x07969b3b) /* 0.474269135 */, 18 }, + /* 6622 */ { MAD_F(0x0796ff62) /* 0.474364645 */, 18 }, + /* 6623 */ { MAD_F(0x07976389) /* 0.474460161 */, 18 }, + + /* 6624 */ { MAD_F(0x0797c7b2) /* 0.474555681 */, 18 }, + /* 6625 */ { MAD_F(0x07982bdd) /* 0.474651205 */, 18 }, + /* 6626 */ { MAD_F(0x07989008) /* 0.474746735 */, 18 }, + /* 6627 */ { MAD_F(0x0798f435) /* 0.474842270 */, 18 }, + /* 6628 */ { MAD_F(0x07995863) /* 0.474937809 */, 18 }, + /* 6629 */ { MAD_F(0x0799bc92) /* 0.475033353 */, 18 }, + /* 6630 */ { MAD_F(0x079a20c3) /* 0.475128902 */, 18 }, + /* 6631 */ { MAD_F(0x079a84f5) /* 0.475224456 */, 18 }, + /* 6632 */ { MAD_F(0x079ae929) /* 0.475320014 */, 18 }, + /* 6633 */ { MAD_F(0x079b4d5d) /* 0.475415578 */, 18 }, + /* 6634 */ { MAD_F(0x079bb193) /* 0.475511146 */, 18 }, + /* 6635 */ { MAD_F(0x079c15ca) /* 0.475606719 */, 18 }, + /* 6636 */ { MAD_F(0x079c7a03) /* 0.475702296 */, 18 }, + /* 6637 */ { MAD_F(0x079cde3c) /* 0.475797879 */, 18 }, + /* 6638 */ { MAD_F(0x079d4277) /* 0.475893466 */, 18 }, + /* 6639 */ { MAD_F(0x079da6b4) /* 0.475989058 */, 18 }, + + /* 6640 */ { MAD_F(0x079e0af1) /* 0.476084655 */, 18 }, + /* 6641 */ { MAD_F(0x079e6f30) /* 0.476180257 */, 18 }, + /* 6642 */ { MAD_F(0x079ed370) /* 0.476275863 */, 18 }, + /* 6643 */ { MAD_F(0x079f37b2) /* 0.476371475 */, 18 }, + /* 6644 */ { MAD_F(0x079f9bf5) /* 0.476467091 */, 18 }, + /* 6645 */ { MAD_F(0x07a00039) /* 0.476562712 */, 18 }, + /* 6646 */ { MAD_F(0x07a0647e) /* 0.476658338 */, 18 }, + /* 6647 */ { MAD_F(0x07a0c8c5) /* 0.476753968 */, 18 }, + /* 6648 */ { MAD_F(0x07a12d0c) /* 0.476849603 */, 18 }, + /* 6649 */ { MAD_F(0x07a19156) /* 0.476945243 */, 18 }, + /* 6650 */ { MAD_F(0x07a1f5a0) /* 0.477040888 */, 18 }, + /* 6651 */ { MAD_F(0x07a259ec) /* 0.477136538 */, 18 }, + /* 6652 */ { MAD_F(0x07a2be39) /* 0.477232193 */, 18 }, + /* 6653 */ { MAD_F(0x07a32287) /* 0.477327852 */, 18 }, + /* 6654 */ { MAD_F(0x07a386d7) /* 0.477423516 */, 18 }, + /* 6655 */ { MAD_F(0x07a3eb28) /* 0.477519185 */, 18 }, + + /* 6656 */ { MAD_F(0x07a44f7a) /* 0.477614858 */, 18 }, + /* 6657 */ { MAD_F(0x07a4b3ce) /* 0.477710537 */, 18 }, + /* 6658 */ { MAD_F(0x07a51822) /* 0.477806220 */, 18 }, + /* 6659 */ { MAD_F(0x07a57c78) /* 0.477901908 */, 18 }, + /* 6660 */ { MAD_F(0x07a5e0d0) /* 0.477997601 */, 18 }, + /* 6661 */ { MAD_F(0x07a64528) /* 0.478093299 */, 18 }, + /* 6662 */ { MAD_F(0x07a6a982) /* 0.478189001 */, 18 }, + /* 6663 */ { MAD_F(0x07a70ddd) /* 0.478284708 */, 18 }, + /* 6664 */ { MAD_F(0x07a7723a) /* 0.478380420 */, 18 }, + /* 6665 */ { MAD_F(0x07a7d698) /* 0.478476137 */, 18 }, + /* 6666 */ { MAD_F(0x07a83af7) /* 0.478571858 */, 18 }, + /* 6667 */ { MAD_F(0x07a89f57) /* 0.478667585 */, 18 }, + /* 6668 */ { MAD_F(0x07a903b9) /* 0.478763316 */, 18 }, + /* 6669 */ { MAD_F(0x07a9681c) /* 0.478859052 */, 18 }, + /* 6670 */ { MAD_F(0x07a9cc80) /* 0.478954793 */, 18 }, + /* 6671 */ { MAD_F(0x07aa30e5) /* 0.479050538 */, 18 }, + + /* 6672 */ { MAD_F(0x07aa954c) /* 0.479146288 */, 18 }, + /* 6673 */ { MAD_F(0x07aaf9b4) /* 0.479242043 */, 18 }, + /* 6674 */ { MAD_F(0x07ab5e1e) /* 0.479337803 */, 18 }, + /* 6675 */ { MAD_F(0x07abc288) /* 0.479433568 */, 18 }, + /* 6676 */ { MAD_F(0x07ac26f4) /* 0.479529337 */, 18 }, + /* 6677 */ { MAD_F(0x07ac8b61) /* 0.479625111 */, 18 }, + /* 6678 */ { MAD_F(0x07acefd0) /* 0.479720890 */, 18 }, + /* 6679 */ { MAD_F(0x07ad543f) /* 0.479816674 */, 18 }, + /* 6680 */ { MAD_F(0x07adb8b0) /* 0.479912463 */, 18 }, + /* 6681 */ { MAD_F(0x07ae1d23) /* 0.480008256 */, 18 }, + /* 6682 */ { MAD_F(0x07ae8196) /* 0.480104054 */, 18 }, + /* 6683 */ { MAD_F(0x07aee60b) /* 0.480199857 */, 18 }, + /* 6684 */ { MAD_F(0x07af4a81) /* 0.480295664 */, 18 }, + /* 6685 */ { MAD_F(0x07afaef9) /* 0.480391477 */, 18 }, + /* 6686 */ { MAD_F(0x07b01372) /* 0.480487294 */, 18 }, + /* 6687 */ { MAD_F(0x07b077ec) /* 0.480583116 */, 18 }, + + /* 6688 */ { MAD_F(0x07b0dc67) /* 0.480678943 */, 18 }, + /* 6689 */ { MAD_F(0x07b140e4) /* 0.480774774 */, 18 }, + /* 6690 */ { MAD_F(0x07b1a561) /* 0.480870611 */, 18 }, + /* 6691 */ { MAD_F(0x07b209e1) /* 0.480966452 */, 18 }, + /* 6692 */ { MAD_F(0x07b26e61) /* 0.481062298 */, 18 }, + /* 6693 */ { MAD_F(0x07b2d2e3) /* 0.481158148 */, 18 }, + /* 6694 */ { MAD_F(0x07b33766) /* 0.481254004 */, 18 }, + /* 6695 */ { MAD_F(0x07b39bea) /* 0.481349864 */, 18 }, + /* 6696 */ { MAD_F(0x07b4006f) /* 0.481445729 */, 18 }, + /* 6697 */ { MAD_F(0x07b464f6) /* 0.481541598 */, 18 }, + /* 6698 */ { MAD_F(0x07b4c97e) /* 0.481637473 */, 18 }, + /* 6699 */ { MAD_F(0x07b52e08) /* 0.481733352 */, 18 }, + /* 6700 */ { MAD_F(0x07b59292) /* 0.481829236 */, 18 }, + /* 6701 */ { MAD_F(0x07b5f71e) /* 0.481925125 */, 18 }, + /* 6702 */ { MAD_F(0x07b65bac) /* 0.482021019 */, 18 }, + /* 6703 */ { MAD_F(0x07b6c03a) /* 0.482116917 */, 18 }, + + /* 6704 */ { MAD_F(0x07b724ca) /* 0.482212820 */, 18 }, + /* 6705 */ { MAD_F(0x07b7895b) /* 0.482308728 */, 18 }, + /* 6706 */ { MAD_F(0x07b7eded) /* 0.482404640 */, 18 }, + /* 6707 */ { MAD_F(0x07b85281) /* 0.482500558 */, 18 }, + /* 6708 */ { MAD_F(0x07b8b716) /* 0.482596480 */, 18 }, + /* 6709 */ { MAD_F(0x07b91bac) /* 0.482692407 */, 18 }, + /* 6710 */ { MAD_F(0x07b98044) /* 0.482788339 */, 18 }, + /* 6711 */ { MAD_F(0x07b9e4dc) /* 0.482884275 */, 18 }, + /* 6712 */ { MAD_F(0x07ba4976) /* 0.482980216 */, 18 }, + /* 6713 */ { MAD_F(0x07baae12) /* 0.483076162 */, 18 }, + /* 6714 */ { MAD_F(0x07bb12ae) /* 0.483172113 */, 18 }, + /* 6715 */ { MAD_F(0x07bb774c) /* 0.483268069 */, 18 }, + /* 6716 */ { MAD_F(0x07bbdbeb) /* 0.483364029 */, 18 }, + /* 6717 */ { MAD_F(0x07bc408c) /* 0.483459994 */, 18 }, + /* 6718 */ { MAD_F(0x07bca52d) /* 0.483555964 */, 18 }, + /* 6719 */ { MAD_F(0x07bd09d0) /* 0.483651939 */, 18 }, + + /* 6720 */ { MAD_F(0x07bd6e75) /* 0.483747918 */, 18 }, + /* 6721 */ { MAD_F(0x07bdd31a) /* 0.483843902 */, 18 }, + /* 6722 */ { MAD_F(0x07be37c1) /* 0.483939891 */, 18 }, + /* 6723 */ { MAD_F(0x07be9c69) /* 0.484035885 */, 18 }, + /* 6724 */ { MAD_F(0x07bf0113) /* 0.484131883 */, 18 }, + /* 6725 */ { MAD_F(0x07bf65bd) /* 0.484227886 */, 18 }, + /* 6726 */ { MAD_F(0x07bfca69) /* 0.484323894 */, 18 }, + /* 6727 */ { MAD_F(0x07c02f16) /* 0.484419907 */, 18 }, + /* 6728 */ { MAD_F(0x07c093c5) /* 0.484515924 */, 18 }, + /* 6729 */ { MAD_F(0x07c0f875) /* 0.484611946 */, 18 }, + /* 6730 */ { MAD_F(0x07c15d26) /* 0.484707973 */, 18 }, + /* 6731 */ { MAD_F(0x07c1c1d8) /* 0.484804005 */, 18 }, + /* 6732 */ { MAD_F(0x07c2268b) /* 0.484900041 */, 18 }, + /* 6733 */ { MAD_F(0x07c28b40) /* 0.484996083 */, 18 }, + /* 6734 */ { MAD_F(0x07c2eff6) /* 0.485092128 */, 18 }, + /* 6735 */ { MAD_F(0x07c354ae) /* 0.485188179 */, 18 }, + + /* 6736 */ { MAD_F(0x07c3b967) /* 0.485284235 */, 18 }, + /* 6737 */ { MAD_F(0x07c41e21) /* 0.485380295 */, 18 }, + /* 6738 */ { MAD_F(0x07c482dc) /* 0.485476360 */, 18 }, + /* 6739 */ { MAD_F(0x07c4e798) /* 0.485572430 */, 18 }, + /* 6740 */ { MAD_F(0x07c54c56) /* 0.485668504 */, 18 }, + /* 6741 */ { MAD_F(0x07c5b115) /* 0.485764583 */, 18 }, + /* 6742 */ { MAD_F(0x07c615d6) /* 0.485860667 */, 18 }, + /* 6743 */ { MAD_F(0x07c67a97) /* 0.485956756 */, 18 }, + /* 6744 */ { MAD_F(0x07c6df5a) /* 0.486052849 */, 18 }, + /* 6745 */ { MAD_F(0x07c7441e) /* 0.486148948 */, 18 }, + /* 6746 */ { MAD_F(0x07c7a8e4) /* 0.486245051 */, 18 }, + /* 6747 */ { MAD_F(0x07c80daa) /* 0.486341158 */, 18 }, + /* 6748 */ { MAD_F(0x07c87272) /* 0.486437271 */, 18 }, + /* 6749 */ { MAD_F(0x07c8d73c) /* 0.486533388 */, 18 }, + /* 6750 */ { MAD_F(0x07c93c06) /* 0.486629510 */, 18 }, + /* 6751 */ { MAD_F(0x07c9a0d2) /* 0.486725637 */, 18 }, + + /* 6752 */ { MAD_F(0x07ca059f) /* 0.486821768 */, 18 }, + /* 6753 */ { MAD_F(0x07ca6a6d) /* 0.486917905 */, 18 }, + /* 6754 */ { MAD_F(0x07cacf3d) /* 0.487014045 */, 18 }, + /* 6755 */ { MAD_F(0x07cb340e) /* 0.487110191 */, 18 }, + /* 6756 */ { MAD_F(0x07cb98e0) /* 0.487206342 */, 18 }, + /* 6757 */ { MAD_F(0x07cbfdb4) /* 0.487302497 */, 18 }, + /* 6758 */ { MAD_F(0x07cc6288) /* 0.487398657 */, 18 }, + /* 6759 */ { MAD_F(0x07ccc75e) /* 0.487494821 */, 18 }, + /* 6760 */ { MAD_F(0x07cd2c36) /* 0.487590991 */, 18 }, + /* 6761 */ { MAD_F(0x07cd910e) /* 0.487687165 */, 18 }, + /* 6762 */ { MAD_F(0x07cdf5e8) /* 0.487783344 */, 18 }, + /* 6763 */ { MAD_F(0x07ce5ac3) /* 0.487879528 */, 18 }, + /* 6764 */ { MAD_F(0x07cebfa0) /* 0.487975716 */, 18 }, + /* 6765 */ { MAD_F(0x07cf247d) /* 0.488071909 */, 18 }, + /* 6766 */ { MAD_F(0x07cf895c) /* 0.488168107 */, 18 }, + /* 6767 */ { MAD_F(0x07cfee3c) /* 0.488264310 */, 18 }, + + /* 6768 */ { MAD_F(0x07d0531e) /* 0.488360517 */, 18 }, + /* 6769 */ { MAD_F(0x07d0b801) /* 0.488456729 */, 18 }, + /* 6770 */ { MAD_F(0x07d11ce5) /* 0.488552946 */, 18 }, + /* 6771 */ { MAD_F(0x07d181ca) /* 0.488649167 */, 18 }, + /* 6772 */ { MAD_F(0x07d1e6b0) /* 0.488745394 */, 18 }, + /* 6773 */ { MAD_F(0x07d24b98) /* 0.488841625 */, 18 }, + /* 6774 */ { MAD_F(0x07d2b081) /* 0.488937860 */, 18 }, + /* 6775 */ { MAD_F(0x07d3156c) /* 0.489034101 */, 18 }, + /* 6776 */ { MAD_F(0x07d37a57) /* 0.489130346 */, 18 }, + /* 6777 */ { MAD_F(0x07d3df44) /* 0.489226596 */, 18 }, + /* 6778 */ { MAD_F(0x07d44432) /* 0.489322851 */, 18 }, + /* 6779 */ { MAD_F(0x07d4a922) /* 0.489419110 */, 18 }, + /* 6780 */ { MAD_F(0x07d50e13) /* 0.489515375 */, 18 }, + /* 6781 */ { MAD_F(0x07d57305) /* 0.489611643 */, 18 }, + /* 6782 */ { MAD_F(0x07d5d7f8) /* 0.489707917 */, 18 }, + /* 6783 */ { MAD_F(0x07d63cec) /* 0.489804195 */, 18 }, + + /* 6784 */ { MAD_F(0x07d6a1e2) /* 0.489900479 */, 18 }, + /* 6785 */ { MAD_F(0x07d706d9) /* 0.489996766 */, 18 }, + /* 6786 */ { MAD_F(0x07d76bd2) /* 0.490093059 */, 18 }, + /* 6787 */ { MAD_F(0x07d7d0cb) /* 0.490189356 */, 18 }, + /* 6788 */ { MAD_F(0x07d835c6) /* 0.490285658 */, 18 }, + /* 6789 */ { MAD_F(0x07d89ac2) /* 0.490381965 */, 18 }, + /* 6790 */ { MAD_F(0x07d8ffc0) /* 0.490478277 */, 18 }, + /* 6791 */ { MAD_F(0x07d964be) /* 0.490574593 */, 18 }, + /* 6792 */ { MAD_F(0x07d9c9be) /* 0.490670914 */, 18 }, + /* 6793 */ { MAD_F(0x07da2ebf) /* 0.490767239 */, 18 }, + /* 6794 */ { MAD_F(0x07da93c2) /* 0.490863570 */, 18 }, + /* 6795 */ { MAD_F(0x07daf8c6) /* 0.490959905 */, 18 }, + /* 6796 */ { MAD_F(0x07db5dcb) /* 0.491056245 */, 18 }, + /* 6797 */ { MAD_F(0x07dbc2d1) /* 0.491152589 */, 18 }, + /* 6798 */ { MAD_F(0x07dc27d9) /* 0.491248939 */, 18 }, + /* 6799 */ { MAD_F(0x07dc8ce1) /* 0.491345293 */, 18 }, + + /* 6800 */ { MAD_F(0x07dcf1ec) /* 0.491441651 */, 18 }, + /* 6801 */ { MAD_F(0x07dd56f7) /* 0.491538015 */, 18 }, + /* 6802 */ { MAD_F(0x07ddbc04) /* 0.491634383 */, 18 }, + /* 6803 */ { MAD_F(0x07de2111) /* 0.491730756 */, 18 }, + /* 6804 */ { MAD_F(0x07de8621) /* 0.491827134 */, 18 }, + /* 6805 */ { MAD_F(0x07deeb31) /* 0.491923516 */, 18 }, + /* 6806 */ { MAD_F(0x07df5043) /* 0.492019903 */, 18 }, + /* 6807 */ { MAD_F(0x07dfb556) /* 0.492116295 */, 18 }, + /* 6808 */ { MAD_F(0x07e01a6a) /* 0.492212691 */, 18 }, + /* 6809 */ { MAD_F(0x07e07f80) /* 0.492309093 */, 18 }, + /* 6810 */ { MAD_F(0x07e0e496) /* 0.492405499 */, 18 }, + /* 6811 */ { MAD_F(0x07e149ae) /* 0.492501909 */, 18 }, + /* 6812 */ { MAD_F(0x07e1aec8) /* 0.492598325 */, 18 }, + /* 6813 */ { MAD_F(0x07e213e2) /* 0.492694745 */, 18 }, + /* 6814 */ { MAD_F(0x07e278fe) /* 0.492791170 */, 18 }, + /* 6815 */ { MAD_F(0x07e2de1b) /* 0.492887599 */, 18 }, + + /* 6816 */ { MAD_F(0x07e3433a) /* 0.492984033 */, 18 }, + /* 6817 */ { MAD_F(0x07e3a859) /* 0.493080472 */, 18 }, + /* 6818 */ { MAD_F(0x07e40d7a) /* 0.493176916 */, 18 }, + /* 6819 */ { MAD_F(0x07e4729c) /* 0.493273365 */, 18 }, + /* 6820 */ { MAD_F(0x07e4d7c0) /* 0.493369818 */, 18 }, + /* 6821 */ { MAD_F(0x07e53ce4) /* 0.493466275 */, 18 }, + /* 6822 */ { MAD_F(0x07e5a20a) /* 0.493562738 */, 18 }, + /* 6823 */ { MAD_F(0x07e60732) /* 0.493659205 */, 18 }, + /* 6824 */ { MAD_F(0x07e66c5a) /* 0.493755677 */, 18 }, + /* 6825 */ { MAD_F(0x07e6d184) /* 0.493852154 */, 18 }, + /* 6826 */ { MAD_F(0x07e736af) /* 0.493948635 */, 18 }, + /* 6827 */ { MAD_F(0x07e79bdb) /* 0.494045122 */, 18 }, + /* 6828 */ { MAD_F(0x07e80109) /* 0.494141612 */, 18 }, + /* 6829 */ { MAD_F(0x07e86638) /* 0.494238108 */, 18 }, + /* 6830 */ { MAD_F(0x07e8cb68) /* 0.494334608 */, 18 }, + /* 6831 */ { MAD_F(0x07e93099) /* 0.494431113 */, 18 }, + + /* 6832 */ { MAD_F(0x07e995cc) /* 0.494527623 */, 18 }, + /* 6833 */ { MAD_F(0x07e9fb00) /* 0.494624137 */, 18 }, + /* 6834 */ { MAD_F(0x07ea6035) /* 0.494720656 */, 18 }, + /* 6835 */ { MAD_F(0x07eac56b) /* 0.494817180 */, 18 }, + /* 6836 */ { MAD_F(0x07eb2aa3) /* 0.494913709 */, 18 }, + /* 6837 */ { MAD_F(0x07eb8fdc) /* 0.495010242 */, 18 }, + /* 6838 */ { MAD_F(0x07ebf516) /* 0.495106780 */, 18 }, + /* 6839 */ { MAD_F(0x07ec5a51) /* 0.495203322 */, 18 }, + /* 6840 */ { MAD_F(0x07ecbf8e) /* 0.495299870 */, 18 }, + /* 6841 */ { MAD_F(0x07ed24cc) /* 0.495396422 */, 18 }, + /* 6842 */ { MAD_F(0x07ed8a0b) /* 0.495492978 */, 18 }, + /* 6843 */ { MAD_F(0x07edef4c) /* 0.495589540 */, 18 }, + /* 6844 */ { MAD_F(0x07ee548e) /* 0.495686106 */, 18 }, + /* 6845 */ { MAD_F(0x07eeb9d1) /* 0.495782677 */, 18 }, + /* 6846 */ { MAD_F(0x07ef1f15) /* 0.495879252 */, 18 }, + /* 6847 */ { MAD_F(0x07ef845b) /* 0.495975833 */, 18 }, + + /* 6848 */ { MAD_F(0x07efe9a1) /* 0.496072418 */, 18 }, + /* 6849 */ { MAD_F(0x07f04ee9) /* 0.496169007 */, 18 }, + /* 6850 */ { MAD_F(0x07f0b433) /* 0.496265602 */, 18 }, + /* 6851 */ { MAD_F(0x07f1197d) /* 0.496362201 */, 18 }, + /* 6852 */ { MAD_F(0x07f17ec9) /* 0.496458804 */, 18 }, + /* 6853 */ { MAD_F(0x07f1e416) /* 0.496555413 */, 18 }, + /* 6854 */ { MAD_F(0x07f24965) /* 0.496652026 */, 18 }, + /* 6855 */ { MAD_F(0x07f2aeb5) /* 0.496748644 */, 18 }, + /* 6856 */ { MAD_F(0x07f31405) /* 0.496845266 */, 18 }, + /* 6857 */ { MAD_F(0x07f37958) /* 0.496941894 */, 18 }, + /* 6858 */ { MAD_F(0x07f3deab) /* 0.497038526 */, 18 }, + /* 6859 */ { MAD_F(0x07f44400) /* 0.497135162 */, 18 }, + /* 6860 */ { MAD_F(0x07f4a956) /* 0.497231804 */, 18 }, + /* 6861 */ { MAD_F(0x07f50ead) /* 0.497328450 */, 18 }, + /* 6862 */ { MAD_F(0x07f57405) /* 0.497425100 */, 18 }, + /* 6863 */ { MAD_F(0x07f5d95f) /* 0.497521756 */, 18 }, + + /* 6864 */ { MAD_F(0x07f63eba) /* 0.497618416 */, 18 }, + /* 6865 */ { MAD_F(0x07f6a416) /* 0.497715081 */, 18 }, + /* 6866 */ { MAD_F(0x07f70974) /* 0.497811750 */, 18 }, + /* 6867 */ { MAD_F(0x07f76ed3) /* 0.497908425 */, 18 }, + /* 6868 */ { MAD_F(0x07f7d433) /* 0.498005103 */, 18 }, + /* 6869 */ { MAD_F(0x07f83994) /* 0.498101787 */, 18 }, + /* 6870 */ { MAD_F(0x07f89ef7) /* 0.498198475 */, 18 }, + /* 6871 */ { MAD_F(0x07f9045a) /* 0.498295168 */, 18 }, + /* 6872 */ { MAD_F(0x07f969c0) /* 0.498391866 */, 18 }, + /* 6873 */ { MAD_F(0x07f9cf26) /* 0.498488568 */, 18 }, + /* 6874 */ { MAD_F(0x07fa348e) /* 0.498585275 */, 18 }, + /* 6875 */ { MAD_F(0x07fa99f6) /* 0.498681987 */, 18 }, + /* 6876 */ { MAD_F(0x07faff60) /* 0.498778704 */, 18 }, + /* 6877 */ { MAD_F(0x07fb64cc) /* 0.498875425 */, 18 }, + /* 6878 */ { MAD_F(0x07fbca38) /* 0.498972150 */, 18 }, + /* 6879 */ { MAD_F(0x07fc2fa6) /* 0.499068881 */, 18 }, + + /* 6880 */ { MAD_F(0x07fc9516) /* 0.499165616 */, 18 }, + /* 6881 */ { MAD_F(0x07fcfa86) /* 0.499262356 */, 18 }, + /* 6882 */ { MAD_F(0x07fd5ff8) /* 0.499359101 */, 18 }, + /* 6883 */ { MAD_F(0x07fdc56b) /* 0.499455850 */, 18 }, + /* 6884 */ { MAD_F(0x07fe2adf) /* 0.499552604 */, 18 }, + /* 6885 */ { MAD_F(0x07fe9054) /* 0.499649362 */, 18 }, + /* 6886 */ { MAD_F(0x07fef5cb) /* 0.499746126 */, 18 }, + /* 6887 */ { MAD_F(0x07ff5b43) /* 0.499842894 */, 18 }, + /* 6888 */ { MAD_F(0x07ffc0bc) /* 0.499939666 */, 18 }, + /* 6889 */ { MAD_F(0x0400131b) /* 0.250018222 */, 19 }, + /* 6890 */ { MAD_F(0x040045d9) /* 0.250066613 */, 19 }, + /* 6891 */ { MAD_F(0x04007897) /* 0.250115006 */, 19 }, + /* 6892 */ { MAD_F(0x0400ab57) /* 0.250163402 */, 19 }, + /* 6893 */ { MAD_F(0x0400de16) /* 0.250211800 */, 19 }, + /* 6894 */ { MAD_F(0x040110d7) /* 0.250260200 */, 19 }, + /* 6895 */ { MAD_F(0x04014398) /* 0.250308603 */, 19 }, + + /* 6896 */ { MAD_F(0x04017659) /* 0.250357008 */, 19 }, + /* 6897 */ { MAD_F(0x0401a91c) /* 0.250405415 */, 19 }, + /* 6898 */ { MAD_F(0x0401dbdf) /* 0.250453825 */, 19 }, + /* 6899 */ { MAD_F(0x04020ea2) /* 0.250502237 */, 19 }, + /* 6900 */ { MAD_F(0x04024166) /* 0.250550652 */, 19 }, + /* 6901 */ { MAD_F(0x0402742b) /* 0.250599068 */, 19 }, + /* 6902 */ { MAD_F(0x0402a6f0) /* 0.250647488 */, 19 }, + /* 6903 */ { MAD_F(0x0402d9b6) /* 0.250695909 */, 19 }, + /* 6904 */ { MAD_F(0x04030c7d) /* 0.250744333 */, 19 }, + /* 6905 */ { MAD_F(0x04033f44) /* 0.250792759 */, 19 }, + /* 6906 */ { MAD_F(0x0403720c) /* 0.250841187 */, 19 }, + /* 6907 */ { MAD_F(0x0403a4d5) /* 0.250889618 */, 19 }, + /* 6908 */ { MAD_F(0x0403d79e) /* 0.250938051 */, 19 }, + /* 6909 */ { MAD_F(0x04040a68) /* 0.250986487 */, 19 }, + /* 6910 */ { MAD_F(0x04043d32) /* 0.251034924 */, 19 }, + /* 6911 */ { MAD_F(0x04046ffd) /* 0.251083365 */, 19 }, + + /* 6912 */ { MAD_F(0x0404a2c9) /* 0.251131807 */, 19 }, + /* 6913 */ { MAD_F(0x0404d595) /* 0.251180252 */, 19 }, + /* 6914 */ { MAD_F(0x04050862) /* 0.251228699 */, 19 }, + /* 6915 */ { MAD_F(0x04053b30) /* 0.251277148 */, 19 }, + /* 6916 */ { MAD_F(0x04056dfe) /* 0.251325600 */, 19 }, + /* 6917 */ { MAD_F(0x0405a0cd) /* 0.251374054 */, 19 }, + /* 6918 */ { MAD_F(0x0405d39c) /* 0.251422511 */, 19 }, + /* 6919 */ { MAD_F(0x0406066c) /* 0.251470970 */, 19 }, + /* 6920 */ { MAD_F(0x0406393d) /* 0.251519431 */, 19 }, + /* 6921 */ { MAD_F(0x04066c0e) /* 0.251567894 */, 19 }, + /* 6922 */ { MAD_F(0x04069ee0) /* 0.251616360 */, 19 }, + /* 6923 */ { MAD_F(0x0406d1b3) /* 0.251664828 */, 19 }, + /* 6924 */ { MAD_F(0x04070486) /* 0.251713299 */, 19 }, + /* 6925 */ { MAD_F(0x0407375a) /* 0.251761772 */, 19 }, + /* 6926 */ { MAD_F(0x04076a2e) /* 0.251810247 */, 19 }, + /* 6927 */ { MAD_F(0x04079d03) /* 0.251858724 */, 19 }, + + /* 6928 */ { MAD_F(0x0407cfd9) /* 0.251907204 */, 19 }, + /* 6929 */ { MAD_F(0x040802af) /* 0.251955686 */, 19 }, + /* 6930 */ { MAD_F(0x04083586) /* 0.252004171 */, 19 }, + /* 6931 */ { MAD_F(0x0408685e) /* 0.252052658 */, 19 }, + /* 6932 */ { MAD_F(0x04089b36) /* 0.252101147 */, 19 }, + /* 6933 */ { MAD_F(0x0408ce0f) /* 0.252149638 */, 19 }, + /* 6934 */ { MAD_F(0x040900e8) /* 0.252198132 */, 19 }, + /* 6935 */ { MAD_F(0x040933c2) /* 0.252246628 */, 19 }, + /* 6936 */ { MAD_F(0x0409669d) /* 0.252295127 */, 19 }, + /* 6937 */ { MAD_F(0x04099978) /* 0.252343627 */, 19 }, + /* 6938 */ { MAD_F(0x0409cc54) /* 0.252392131 */, 19 }, + /* 6939 */ { MAD_F(0x0409ff31) /* 0.252440636 */, 19 }, + /* 6940 */ { MAD_F(0x040a320e) /* 0.252489144 */, 19 }, + /* 6941 */ { MAD_F(0x040a64ec) /* 0.252537654 */, 19 }, + /* 6942 */ { MAD_F(0x040a97cb) /* 0.252586166 */, 19 }, + /* 6943 */ { MAD_F(0x040acaaa) /* 0.252634681 */, 19 }, + + /* 6944 */ { MAD_F(0x040afd89) /* 0.252683198 */, 19 }, + /* 6945 */ { MAD_F(0x040b306a) /* 0.252731718 */, 19 }, + /* 6946 */ { MAD_F(0x040b634b) /* 0.252780240 */, 19 }, + /* 6947 */ { MAD_F(0x040b962c) /* 0.252828764 */, 19 }, + /* 6948 */ { MAD_F(0x040bc90e) /* 0.252877290 */, 19 }, + /* 6949 */ { MAD_F(0x040bfbf1) /* 0.252925819 */, 19 }, + /* 6950 */ { MAD_F(0x040c2ed5) /* 0.252974350 */, 19 }, + /* 6951 */ { MAD_F(0x040c61b9) /* 0.253022883 */, 19 }, + /* 6952 */ { MAD_F(0x040c949e) /* 0.253071419 */, 19 }, + /* 6953 */ { MAD_F(0x040cc783) /* 0.253119957 */, 19 }, + /* 6954 */ { MAD_F(0x040cfa69) /* 0.253168498 */, 19 }, + /* 6955 */ { MAD_F(0x040d2d4f) /* 0.253217040 */, 19 }, + /* 6956 */ { MAD_F(0x040d6037) /* 0.253265585 */, 19 }, + /* 6957 */ { MAD_F(0x040d931e) /* 0.253314133 */, 19 }, + /* 6958 */ { MAD_F(0x040dc607) /* 0.253362682 */, 19 }, + /* 6959 */ { MAD_F(0x040df8f0) /* 0.253411234 */, 19 }, + + /* 6960 */ { MAD_F(0x040e2bda) /* 0.253459789 */, 19 }, + /* 6961 */ { MAD_F(0x040e5ec4) /* 0.253508345 */, 19 }, + /* 6962 */ { MAD_F(0x040e91af) /* 0.253556904 */, 19 }, + /* 6963 */ { MAD_F(0x040ec49b) /* 0.253605466 */, 19 }, + /* 6964 */ { MAD_F(0x040ef787) /* 0.253654029 */, 19 }, + /* 6965 */ { MAD_F(0x040f2a74) /* 0.253702595 */, 19 }, + /* 6966 */ { MAD_F(0x040f5d61) /* 0.253751164 */, 19 }, + /* 6967 */ { MAD_F(0x040f904f) /* 0.253799734 */, 19 }, + /* 6968 */ { MAD_F(0x040fc33e) /* 0.253848307 */, 19 }, + /* 6969 */ { MAD_F(0x040ff62d) /* 0.253896883 */, 19 }, + /* 6970 */ { MAD_F(0x0410291d) /* 0.253945460 */, 19 }, + /* 6971 */ { MAD_F(0x04105c0e) /* 0.253994040 */, 19 }, + /* 6972 */ { MAD_F(0x04108eff) /* 0.254042622 */, 19 }, + /* 6973 */ { MAD_F(0x0410c1f1) /* 0.254091207 */, 19 }, + /* 6974 */ { MAD_F(0x0410f4e3) /* 0.254139794 */, 19 }, + /* 6975 */ { MAD_F(0x041127d6) /* 0.254188383 */, 19 }, + + /* 6976 */ { MAD_F(0x04115aca) /* 0.254236974 */, 19 }, + /* 6977 */ { MAD_F(0x04118dbe) /* 0.254285568 */, 19 }, + /* 6978 */ { MAD_F(0x0411c0b3) /* 0.254334165 */, 19 }, + /* 6979 */ { MAD_F(0x0411f3a9) /* 0.254382763 */, 19 }, + /* 6980 */ { MAD_F(0x0412269f) /* 0.254431364 */, 19 }, + /* 6981 */ { MAD_F(0x04125996) /* 0.254479967 */, 19 }, + /* 6982 */ { MAD_F(0x04128c8d) /* 0.254528572 */, 19 }, + /* 6983 */ { MAD_F(0x0412bf85) /* 0.254577180 */, 19 }, + /* 6984 */ { MAD_F(0x0412f27e) /* 0.254625790 */, 19 }, + /* 6985 */ { MAD_F(0x04132577) /* 0.254674403 */, 19 }, + /* 6986 */ { MAD_F(0x04135871) /* 0.254723017 */, 19 }, + /* 6987 */ { MAD_F(0x04138b6c) /* 0.254771635 */, 19 }, + /* 6988 */ { MAD_F(0x0413be67) /* 0.254820254 */, 19 }, + /* 6989 */ { MAD_F(0x0413f163) /* 0.254868876 */, 19 }, + /* 6990 */ { MAD_F(0x0414245f) /* 0.254917500 */, 19 }, + /* 6991 */ { MAD_F(0x0414575c) /* 0.254966126 */, 19 }, + + /* 6992 */ { MAD_F(0x04148a5a) /* 0.255014755 */, 19 }, + /* 6993 */ { MAD_F(0x0414bd58) /* 0.255063386 */, 19 }, + /* 6994 */ { MAD_F(0x0414f057) /* 0.255112019 */, 19 }, + /* 6995 */ { MAD_F(0x04152356) /* 0.255160655 */, 19 }, + /* 6996 */ { MAD_F(0x04155657) /* 0.255209292 */, 19 }, + /* 6997 */ { MAD_F(0x04158957) /* 0.255257933 */, 19 }, + /* 6998 */ { MAD_F(0x0415bc59) /* 0.255306575 */, 19 }, + /* 6999 */ { MAD_F(0x0415ef5b) /* 0.255355220 */, 19 }, + /* 7000 */ { MAD_F(0x0416225d) /* 0.255403867 */, 19 }, + /* 7001 */ { MAD_F(0x04165561) /* 0.255452517 */, 19 }, + /* 7002 */ { MAD_F(0x04168864) /* 0.255501169 */, 19 }, + /* 7003 */ { MAD_F(0x0416bb69) /* 0.255549823 */, 19 }, + /* 7004 */ { MAD_F(0x0416ee6e) /* 0.255598479 */, 19 }, + /* 7005 */ { MAD_F(0x04172174) /* 0.255647138 */, 19 }, + /* 7006 */ { MAD_F(0x0417547a) /* 0.255695799 */, 19 }, + /* 7007 */ { MAD_F(0x04178781) /* 0.255744463 */, 19 }, + + /* 7008 */ { MAD_F(0x0417ba89) /* 0.255793128 */, 19 }, + /* 7009 */ { MAD_F(0x0417ed91) /* 0.255841796 */, 19 }, + /* 7010 */ { MAD_F(0x0418209a) /* 0.255890467 */, 19 }, + /* 7011 */ { MAD_F(0x041853a3) /* 0.255939139 */, 19 }, + /* 7012 */ { MAD_F(0x041886ad) /* 0.255987814 */, 19 }, + /* 7013 */ { MAD_F(0x0418b9b8) /* 0.256036492 */, 19 }, + /* 7014 */ { MAD_F(0x0418ecc3) /* 0.256085171 */, 19 }, + /* 7015 */ { MAD_F(0x04191fcf) /* 0.256133853 */, 19 }, + /* 7016 */ { MAD_F(0x041952dc) /* 0.256182537 */, 19 }, + /* 7017 */ { MAD_F(0x041985e9) /* 0.256231224 */, 19 }, + /* 7018 */ { MAD_F(0x0419b8f7) /* 0.256279913 */, 19 }, + /* 7019 */ { MAD_F(0x0419ec05) /* 0.256328604 */, 19 }, + /* 7020 */ { MAD_F(0x041a1f15) /* 0.256377297 */, 19 }, + /* 7021 */ { MAD_F(0x041a5224) /* 0.256425993 */, 19 }, + /* 7022 */ { MAD_F(0x041a8534) /* 0.256474691 */, 19 }, + /* 7023 */ { MAD_F(0x041ab845) /* 0.256523392 */, 19 }, + + /* 7024 */ { MAD_F(0x041aeb57) /* 0.256572095 */, 19 }, + /* 7025 */ { MAD_F(0x041b1e69) /* 0.256620800 */, 19 }, + /* 7026 */ { MAD_F(0x041b517c) /* 0.256669507 */, 19 }, + /* 7027 */ { MAD_F(0x041b848f) /* 0.256718217 */, 19 }, + /* 7028 */ { MAD_F(0x041bb7a3) /* 0.256766929 */, 19 }, + /* 7029 */ { MAD_F(0x041beab8) /* 0.256815643 */, 19 }, + /* 7030 */ { MAD_F(0x041c1dcd) /* 0.256864359 */, 19 }, + /* 7031 */ { MAD_F(0x041c50e3) /* 0.256913078 */, 19 }, + /* 7032 */ { MAD_F(0x041c83fa) /* 0.256961800 */, 19 }, + /* 7033 */ { MAD_F(0x041cb711) /* 0.257010523 */, 19 }, + /* 7034 */ { MAD_F(0x041cea28) /* 0.257059249 */, 19 }, + /* 7035 */ { MAD_F(0x041d1d41) /* 0.257107977 */, 19 }, + /* 7036 */ { MAD_F(0x041d505a) /* 0.257156708 */, 19 }, + /* 7037 */ { MAD_F(0x041d8373) /* 0.257205440 */, 19 }, + /* 7038 */ { MAD_F(0x041db68e) /* 0.257254175 */, 19 }, + /* 7039 */ { MAD_F(0x041de9a8) /* 0.257302913 */, 19 }, + + /* 7040 */ { MAD_F(0x041e1cc4) /* 0.257351652 */, 19 }, + /* 7041 */ { MAD_F(0x041e4fe0) /* 0.257400394 */, 19 }, + /* 7042 */ { MAD_F(0x041e82fd) /* 0.257449139 */, 19 }, + /* 7043 */ { MAD_F(0x041eb61a) /* 0.257497885 */, 19 }, + /* 7044 */ { MAD_F(0x041ee938) /* 0.257546634 */, 19 }, + /* 7045 */ { MAD_F(0x041f1c57) /* 0.257595386 */, 19 }, + /* 7046 */ { MAD_F(0x041f4f76) /* 0.257644139 */, 19 }, + /* 7047 */ { MAD_F(0x041f8296) /* 0.257692895 */, 19 }, + /* 7048 */ { MAD_F(0x041fb5b6) /* 0.257741653 */, 19 }, + /* 7049 */ { MAD_F(0x041fe8d7) /* 0.257790414 */, 19 }, + /* 7050 */ { MAD_F(0x04201bf9) /* 0.257839176 */, 19 }, + /* 7051 */ { MAD_F(0x04204f1b) /* 0.257887941 */, 19 }, + /* 7052 */ { MAD_F(0x0420823e) /* 0.257936709 */, 19 }, + /* 7053 */ { MAD_F(0x0420b561) /* 0.257985478 */, 19 }, + /* 7054 */ { MAD_F(0x0420e885) /* 0.258034250 */, 19 }, + /* 7055 */ { MAD_F(0x04211baa) /* 0.258083025 */, 19 }, + + /* 7056 */ { MAD_F(0x04214ed0) /* 0.258131801 */, 19 }, + /* 7057 */ { MAD_F(0x042181f6) /* 0.258180580 */, 19 }, + /* 7058 */ { MAD_F(0x0421b51c) /* 0.258229361 */, 19 }, + /* 7059 */ { MAD_F(0x0421e843) /* 0.258278145 */, 19 }, + /* 7060 */ { MAD_F(0x04221b6b) /* 0.258326931 */, 19 }, + /* 7061 */ { MAD_F(0x04224e94) /* 0.258375719 */, 19 }, + /* 7062 */ { MAD_F(0x042281bd) /* 0.258424509 */, 19 }, + /* 7063 */ { MAD_F(0x0422b4e6) /* 0.258473302 */, 19 }, + /* 7064 */ { MAD_F(0x0422e811) /* 0.258522097 */, 19 }, + /* 7065 */ { MAD_F(0x04231b3c) /* 0.258570894 */, 19 }, + /* 7066 */ { MAD_F(0x04234e67) /* 0.258619694 */, 19 }, + /* 7067 */ { MAD_F(0x04238193) /* 0.258668496 */, 19 }, + /* 7068 */ { MAD_F(0x0423b4c0) /* 0.258717300 */, 19 }, + /* 7069 */ { MAD_F(0x0423e7ee) /* 0.258766106 */, 19 }, + /* 7070 */ { MAD_F(0x04241b1c) /* 0.258814915 */, 19 }, + /* 7071 */ { MAD_F(0x04244e4a) /* 0.258863726 */, 19 }, + + /* 7072 */ { MAD_F(0x04248179) /* 0.258912540 */, 19 }, + /* 7073 */ { MAD_F(0x0424b4a9) /* 0.258961356 */, 19 }, + /* 7074 */ { MAD_F(0x0424e7da) /* 0.259010174 */, 19 }, + /* 7075 */ { MAD_F(0x04251b0b) /* 0.259058994 */, 19 }, + /* 7076 */ { MAD_F(0x04254e3d) /* 0.259107817 */, 19 }, + /* 7077 */ { MAD_F(0x0425816f) /* 0.259156642 */, 19 }, + /* 7078 */ { MAD_F(0x0425b4a2) /* 0.259205469 */, 19 }, + /* 7079 */ { MAD_F(0x0425e7d6) /* 0.259254298 */, 19 }, + /* 7080 */ { MAD_F(0x04261b0a) /* 0.259303130 */, 19 }, + /* 7081 */ { MAD_F(0x04264e3f) /* 0.259351964 */, 19 }, + /* 7082 */ { MAD_F(0x04268174) /* 0.259400801 */, 19 }, + /* 7083 */ { MAD_F(0x0426b4aa) /* 0.259449639 */, 19 }, + /* 7084 */ { MAD_F(0x0426e7e1) /* 0.259498480 */, 19 }, + /* 7085 */ { MAD_F(0x04271b18) /* 0.259547324 */, 19 }, + /* 7086 */ { MAD_F(0x04274e50) /* 0.259596169 */, 19 }, + /* 7087 */ { MAD_F(0x04278188) /* 0.259645017 */, 19 }, + + /* 7088 */ { MAD_F(0x0427b4c2) /* 0.259693868 */, 19 }, + /* 7089 */ { MAD_F(0x0427e7fb) /* 0.259742720 */, 19 }, + /* 7090 */ { MAD_F(0x04281b36) /* 0.259791575 */, 19 }, + /* 7091 */ { MAD_F(0x04284e71) /* 0.259840432 */, 19 }, + /* 7092 */ { MAD_F(0x042881ac) /* 0.259889291 */, 19 }, + /* 7093 */ { MAD_F(0x0428b4e8) /* 0.259938153 */, 19 }, + /* 7094 */ { MAD_F(0x0428e825) /* 0.259987017 */, 19 }, + /* 7095 */ { MAD_F(0x04291b63) /* 0.260035883 */, 19 }, + /* 7096 */ { MAD_F(0x04294ea1) /* 0.260084752 */, 19 }, + /* 7097 */ { MAD_F(0x042981df) /* 0.260133623 */, 19 }, + /* 7098 */ { MAD_F(0x0429b51f) /* 0.260182496 */, 19 }, + /* 7099 */ { MAD_F(0x0429e85f) /* 0.260231372 */, 19 }, + /* 7100 */ { MAD_F(0x042a1b9f) /* 0.260280249 */, 19 }, + /* 7101 */ { MAD_F(0x042a4ee0) /* 0.260329129 */, 19 }, + /* 7102 */ { MAD_F(0x042a8222) /* 0.260378012 */, 19 }, + /* 7103 */ { MAD_F(0x042ab564) /* 0.260426896 */, 19 }, + + /* 7104 */ { MAD_F(0x042ae8a7) /* 0.260475783 */, 19 }, + /* 7105 */ { MAD_F(0x042b1beb) /* 0.260524673 */, 19 }, + /* 7106 */ { MAD_F(0x042b4f2f) /* 0.260573564 */, 19 }, + /* 7107 */ { MAD_F(0x042b8274) /* 0.260622458 */, 19 }, + /* 7108 */ { MAD_F(0x042bb5ba) /* 0.260671354 */, 19 }, + /* 7109 */ { MAD_F(0x042be900) /* 0.260720252 */, 19 }, + /* 7110 */ { MAD_F(0x042c1c46) /* 0.260769153 */, 19 }, + /* 7111 */ { MAD_F(0x042c4f8e) /* 0.260818056 */, 19 }, + /* 7112 */ { MAD_F(0x042c82d6) /* 0.260866961 */, 19 }, + /* 7113 */ { MAD_F(0x042cb61e) /* 0.260915869 */, 19 }, + /* 7114 */ { MAD_F(0x042ce967) /* 0.260964779 */, 19 }, + /* 7115 */ { MAD_F(0x042d1cb1) /* 0.261013691 */, 19 }, + /* 7116 */ { MAD_F(0x042d4ffb) /* 0.261062606 */, 19 }, + /* 7117 */ { MAD_F(0x042d8346) /* 0.261111522 */, 19 }, + /* 7118 */ { MAD_F(0x042db692) /* 0.261160441 */, 19 }, + /* 7119 */ { MAD_F(0x042de9de) /* 0.261209363 */, 19 }, + + /* 7120 */ { MAD_F(0x042e1d2b) /* 0.261258286 */, 19 }, + /* 7121 */ { MAD_F(0x042e5078) /* 0.261307212 */, 19 }, + /* 7122 */ { MAD_F(0x042e83c6) /* 0.261356140 */, 19 }, + /* 7123 */ { MAD_F(0x042eb715) /* 0.261405071 */, 19 }, + /* 7124 */ { MAD_F(0x042eea64) /* 0.261454004 */, 19 }, + /* 7125 */ { MAD_F(0x042f1db4) /* 0.261502939 */, 19 }, + /* 7126 */ { MAD_F(0x042f5105) /* 0.261551876 */, 19 }, + /* 7127 */ { MAD_F(0x042f8456) /* 0.261600816 */, 19 }, + /* 7128 */ { MAD_F(0x042fb7a8) /* 0.261649758 */, 19 }, + /* 7129 */ { MAD_F(0x042feafa) /* 0.261698702 */, 19 }, + /* 7130 */ { MAD_F(0x04301e4d) /* 0.261747649 */, 19 }, + /* 7131 */ { MAD_F(0x043051a1) /* 0.261796597 */, 19 }, + /* 7132 */ { MAD_F(0x043084f5) /* 0.261845548 */, 19 }, + /* 7133 */ { MAD_F(0x0430b84a) /* 0.261894502 */, 19 }, + /* 7134 */ { MAD_F(0x0430eb9f) /* 0.261943458 */, 19 }, + /* 7135 */ { MAD_F(0x04311ef5) /* 0.261992416 */, 19 }, + + /* 7136 */ { MAD_F(0x0431524c) /* 0.262041376 */, 19 }, + /* 7137 */ { MAD_F(0x043185a3) /* 0.262090338 */, 19 }, + /* 7138 */ { MAD_F(0x0431b8fb) /* 0.262139303 */, 19 }, + /* 7139 */ { MAD_F(0x0431ec54) /* 0.262188270 */, 19 }, + /* 7140 */ { MAD_F(0x04321fad) /* 0.262237240 */, 19 }, + /* 7141 */ { MAD_F(0x04325306) /* 0.262286211 */, 19 }, + /* 7142 */ { MAD_F(0x04328661) /* 0.262335185 */, 19 }, + /* 7143 */ { MAD_F(0x0432b9bc) /* 0.262384162 */, 19 }, + /* 7144 */ { MAD_F(0x0432ed17) /* 0.262433140 */, 19 }, + /* 7145 */ { MAD_F(0x04332074) /* 0.262482121 */, 19 }, + /* 7146 */ { MAD_F(0x043353d0) /* 0.262531104 */, 19 }, + /* 7147 */ { MAD_F(0x0433872e) /* 0.262580089 */, 19 }, + /* 7148 */ { MAD_F(0x0433ba8c) /* 0.262629077 */, 19 }, + /* 7149 */ { MAD_F(0x0433edea) /* 0.262678067 */, 19 }, + /* 7150 */ { MAD_F(0x0434214a) /* 0.262727059 */, 19 }, + /* 7151 */ { MAD_F(0x043454aa) /* 0.262776054 */, 19 }, + + /* 7152 */ { MAD_F(0x0434880a) /* 0.262825051 */, 19 }, + /* 7153 */ { MAD_F(0x0434bb6b) /* 0.262874050 */, 19 }, + /* 7154 */ { MAD_F(0x0434eecd) /* 0.262923051 */, 19 }, + /* 7155 */ { MAD_F(0x0435222f) /* 0.262972055 */, 19 }, + /* 7156 */ { MAD_F(0x04355592) /* 0.263021061 */, 19 }, + /* 7157 */ { MAD_F(0x043588f6) /* 0.263070069 */, 19 }, + /* 7158 */ { MAD_F(0x0435bc5a) /* 0.263119079 */, 19 }, + /* 7159 */ { MAD_F(0x0435efbf) /* 0.263168092 */, 19 }, + /* 7160 */ { MAD_F(0x04362324) /* 0.263217107 */, 19 }, + /* 7161 */ { MAD_F(0x0436568a) /* 0.263266125 */, 19 }, + /* 7162 */ { MAD_F(0x043689f1) /* 0.263315144 */, 19 }, + /* 7163 */ { MAD_F(0x0436bd58) /* 0.263364166 */, 19 }, + /* 7164 */ { MAD_F(0x0436f0c0) /* 0.263413191 */, 19 }, + /* 7165 */ { MAD_F(0x04372428) /* 0.263462217 */, 19 }, + /* 7166 */ { MAD_F(0x04375791) /* 0.263511246 */, 19 }, + /* 7167 */ { MAD_F(0x04378afb) /* 0.263560277 */, 19 }, + + /* 7168 */ { MAD_F(0x0437be65) /* 0.263609310 */, 19 }, + /* 7169 */ { MAD_F(0x0437f1d0) /* 0.263658346 */, 19 }, + /* 7170 */ { MAD_F(0x0438253c) /* 0.263707384 */, 19 }, + /* 7171 */ { MAD_F(0x043858a8) /* 0.263756424 */, 19 }, + /* 7172 */ { MAD_F(0x04388c14) /* 0.263805466 */, 19 }, + /* 7173 */ { MAD_F(0x0438bf82) /* 0.263854511 */, 19 }, + /* 7174 */ { MAD_F(0x0438f2f0) /* 0.263903558 */, 19 }, + /* 7175 */ { MAD_F(0x0439265e) /* 0.263952607 */, 19 }, + /* 7176 */ { MAD_F(0x043959cd) /* 0.264001659 */, 19 }, + /* 7177 */ { MAD_F(0x04398d3d) /* 0.264050713 */, 19 }, + /* 7178 */ { MAD_F(0x0439c0ae) /* 0.264099769 */, 19 }, + /* 7179 */ { MAD_F(0x0439f41f) /* 0.264148827 */, 19 }, + /* 7180 */ { MAD_F(0x043a2790) /* 0.264197888 */, 19 }, + /* 7181 */ { MAD_F(0x043a5b02) /* 0.264246951 */, 19 }, + /* 7182 */ { MAD_F(0x043a8e75) /* 0.264296016 */, 19 }, + /* 7183 */ { MAD_F(0x043ac1e9) /* 0.264345084 */, 19 }, + + /* 7184 */ { MAD_F(0x043af55d) /* 0.264394153 */, 19 }, + /* 7185 */ { MAD_F(0x043b28d2) /* 0.264443225 */, 19 }, + /* 7186 */ { MAD_F(0x043b5c47) /* 0.264492300 */, 19 }, + /* 7187 */ { MAD_F(0x043b8fbd) /* 0.264541376 */, 19 }, + /* 7188 */ { MAD_F(0x043bc333) /* 0.264590455 */, 19 }, + /* 7189 */ { MAD_F(0x043bf6aa) /* 0.264639536 */, 19 }, + /* 7190 */ { MAD_F(0x043c2a22) /* 0.264688620 */, 19 }, + /* 7191 */ { MAD_F(0x043c5d9a) /* 0.264737706 */, 19 }, + /* 7192 */ { MAD_F(0x043c9113) /* 0.264786794 */, 19 }, + /* 7193 */ { MAD_F(0x043cc48d) /* 0.264835884 */, 19 }, + /* 7194 */ { MAD_F(0x043cf807) /* 0.264884976 */, 19 }, + /* 7195 */ { MAD_F(0x043d2b82) /* 0.264934071 */, 19 }, + /* 7196 */ { MAD_F(0x043d5efd) /* 0.264983168 */, 19 }, + /* 7197 */ { MAD_F(0x043d9279) /* 0.265032268 */, 19 }, + /* 7198 */ { MAD_F(0x043dc5f6) /* 0.265081369 */, 19 }, + /* 7199 */ { MAD_F(0x043df973) /* 0.265130473 */, 19 }, + + /* 7200 */ { MAD_F(0x043e2cf1) /* 0.265179580 */, 19 }, + /* 7201 */ { MAD_F(0x043e6070) /* 0.265228688 */, 19 }, + /* 7202 */ { MAD_F(0x043e93ef) /* 0.265277799 */, 19 }, + /* 7203 */ { MAD_F(0x043ec76e) /* 0.265326912 */, 19 }, + /* 7204 */ { MAD_F(0x043efaef) /* 0.265376027 */, 19 }, + /* 7205 */ { MAD_F(0x043f2e6f) /* 0.265425145 */, 19 }, + /* 7206 */ { MAD_F(0x043f61f1) /* 0.265474264 */, 19 }, + /* 7207 */ { MAD_F(0x043f9573) /* 0.265523387 */, 19 }, + /* 7208 */ { MAD_F(0x043fc8f6) /* 0.265572511 */, 19 }, + /* 7209 */ { MAD_F(0x043ffc79) /* 0.265621638 */, 19 }, + /* 7210 */ { MAD_F(0x04402ffd) /* 0.265670766 */, 19 }, + /* 7211 */ { MAD_F(0x04406382) /* 0.265719898 */, 19 }, + /* 7212 */ { MAD_F(0x04409707) /* 0.265769031 */, 19 }, + /* 7213 */ { MAD_F(0x0440ca8d) /* 0.265818167 */, 19 }, + /* 7214 */ { MAD_F(0x0440fe13) /* 0.265867305 */, 19 }, + /* 7215 */ { MAD_F(0x0441319a) /* 0.265916445 */, 19 }, + + /* 7216 */ { MAD_F(0x04416522) /* 0.265965588 */, 19 }, + /* 7217 */ { MAD_F(0x044198aa) /* 0.266014732 */, 19 }, + /* 7218 */ { MAD_F(0x0441cc33) /* 0.266063880 */, 19 }, + /* 7219 */ { MAD_F(0x0441ffbc) /* 0.266113029 */, 19 }, + /* 7220 */ { MAD_F(0x04423346) /* 0.266162181 */, 19 }, + /* 7221 */ { MAD_F(0x044266d1) /* 0.266211334 */, 19 }, + /* 7222 */ { MAD_F(0x04429a5c) /* 0.266260491 */, 19 }, + /* 7223 */ { MAD_F(0x0442cde8) /* 0.266309649 */, 19 }, + /* 7224 */ { MAD_F(0x04430174) /* 0.266358810 */, 19 }, + /* 7225 */ { MAD_F(0x04433501) /* 0.266407973 */, 19 }, + /* 7226 */ { MAD_F(0x0443688f) /* 0.266457138 */, 19 }, + /* 7227 */ { MAD_F(0x04439c1d) /* 0.266506305 */, 19 }, + /* 7228 */ { MAD_F(0x0443cfac) /* 0.266555475 */, 19 }, + /* 7229 */ { MAD_F(0x0444033c) /* 0.266604647 */, 19 }, + /* 7230 */ { MAD_F(0x044436cc) /* 0.266653822 */, 19 }, + /* 7231 */ { MAD_F(0x04446a5d) /* 0.266702998 */, 19 }, + + /* 7232 */ { MAD_F(0x04449dee) /* 0.266752177 */, 19 }, + /* 7233 */ { MAD_F(0x0444d180) /* 0.266801358 */, 19 }, + /* 7234 */ { MAD_F(0x04450513) /* 0.266850541 */, 19 }, + /* 7235 */ { MAD_F(0x044538a6) /* 0.266899727 */, 19 }, + /* 7236 */ { MAD_F(0x04456c39) /* 0.266948915 */, 19 }, + /* 7237 */ { MAD_F(0x04459fce) /* 0.266998105 */, 19 }, + /* 7238 */ { MAD_F(0x0445d363) /* 0.267047298 */, 19 }, + /* 7239 */ { MAD_F(0x044606f8) /* 0.267096492 */, 19 }, + /* 7240 */ { MAD_F(0x04463a8f) /* 0.267145689 */, 19 }, + /* 7241 */ { MAD_F(0x04466e25) /* 0.267194888 */, 19 }, + /* 7242 */ { MAD_F(0x0446a1bd) /* 0.267244090 */, 19 }, + /* 7243 */ { MAD_F(0x0446d555) /* 0.267293294 */, 19 }, + /* 7244 */ { MAD_F(0x044708ee) /* 0.267342500 */, 19 }, + /* 7245 */ { MAD_F(0x04473c87) /* 0.267391708 */, 19 }, + /* 7246 */ { MAD_F(0x04477021) /* 0.267440919 */, 19 }, + /* 7247 */ { MAD_F(0x0447a3bb) /* 0.267490131 */, 19 }, + + /* 7248 */ { MAD_F(0x0447d756) /* 0.267539347 */, 19 }, + /* 7249 */ { MAD_F(0x04480af2) /* 0.267588564 */, 19 }, + /* 7250 */ { MAD_F(0x04483e8e) /* 0.267637783 */, 19 }, + /* 7251 */ { MAD_F(0x0448722b) /* 0.267687005 */, 19 }, + /* 7252 */ { MAD_F(0x0448a5c9) /* 0.267736229 */, 19 }, + /* 7253 */ { MAD_F(0x0448d967) /* 0.267785456 */, 19 }, + /* 7254 */ { MAD_F(0x04490d05) /* 0.267834685 */, 19 }, + /* 7255 */ { MAD_F(0x044940a5) /* 0.267883915 */, 19 }, + /* 7256 */ { MAD_F(0x04497445) /* 0.267933149 */, 19 }, + /* 7257 */ { MAD_F(0x0449a7e5) /* 0.267982384 */, 19 }, + /* 7258 */ { MAD_F(0x0449db86) /* 0.268031622 */, 19 }, + /* 7259 */ { MAD_F(0x044a0f28) /* 0.268080862 */, 19 }, + /* 7260 */ { MAD_F(0x044a42ca) /* 0.268130104 */, 19 }, + /* 7261 */ { MAD_F(0x044a766d) /* 0.268179349 */, 19 }, + /* 7262 */ { MAD_F(0x044aaa11) /* 0.268228595 */, 19 }, + /* 7263 */ { MAD_F(0x044addb5) /* 0.268277844 */, 19 }, + + /* 7264 */ { MAD_F(0x044b115a) /* 0.268327096 */, 19 }, + /* 7265 */ { MAD_F(0x044b44ff) /* 0.268376349 */, 19 }, + /* 7266 */ { MAD_F(0x044b78a5) /* 0.268425605 */, 19 }, + /* 7267 */ { MAD_F(0x044bac4c) /* 0.268474863 */, 19 }, + /* 7268 */ { MAD_F(0x044bdff3) /* 0.268524123 */, 19 }, + /* 7269 */ { MAD_F(0x044c139b) /* 0.268573386 */, 19 }, + /* 7270 */ { MAD_F(0x044c4743) /* 0.268622651 */, 19 }, + /* 7271 */ { MAD_F(0x044c7aec) /* 0.268671918 */, 19 }, + /* 7272 */ { MAD_F(0x044cae96) /* 0.268721187 */, 19 }, + /* 7273 */ { MAD_F(0x044ce240) /* 0.268770459 */, 19 }, + /* 7274 */ { MAD_F(0x044d15eb) /* 0.268819733 */, 19 }, + /* 7275 */ { MAD_F(0x044d4997) /* 0.268869009 */, 19 }, + /* 7276 */ { MAD_F(0x044d7d43) /* 0.268918287 */, 19 }, + /* 7277 */ { MAD_F(0x044db0ef) /* 0.268967568 */, 19 }, + /* 7278 */ { MAD_F(0x044de49d) /* 0.269016851 */, 19 }, + /* 7279 */ { MAD_F(0x044e184b) /* 0.269066136 */, 19 }, + + /* 7280 */ { MAD_F(0x044e4bf9) /* 0.269115423 */, 19 }, + /* 7281 */ { MAD_F(0x044e7fa8) /* 0.269164713 */, 19 }, + /* 7282 */ { MAD_F(0x044eb358) /* 0.269214005 */, 19 }, + /* 7283 */ { MAD_F(0x044ee708) /* 0.269263299 */, 19 }, + /* 7284 */ { MAD_F(0x044f1ab9) /* 0.269312595 */, 19 }, + /* 7285 */ { MAD_F(0x044f4e6b) /* 0.269361894 */, 19 }, + /* 7286 */ { MAD_F(0x044f821d) /* 0.269411195 */, 19 }, + /* 7287 */ { MAD_F(0x044fb5cf) /* 0.269460498 */, 19 }, + /* 7288 */ { MAD_F(0x044fe983) /* 0.269509804 */, 19 }, + /* 7289 */ { MAD_F(0x04501d37) /* 0.269559111 */, 19 }, + /* 7290 */ { MAD_F(0x045050eb) /* 0.269608421 */, 19 }, + /* 7291 */ { MAD_F(0x045084a0) /* 0.269657734 */, 19 }, + /* 7292 */ { MAD_F(0x0450b856) /* 0.269707048 */, 19 }, + /* 7293 */ { MAD_F(0x0450ec0d) /* 0.269756365 */, 19 }, + /* 7294 */ { MAD_F(0x04511fc4) /* 0.269805684 */, 19 }, + /* 7295 */ { MAD_F(0x0451537b) /* 0.269855005 */, 19 }, + + /* 7296 */ { MAD_F(0x04518733) /* 0.269904329 */, 19 }, + /* 7297 */ { MAD_F(0x0451baec) /* 0.269953654 */, 19 }, + /* 7298 */ { MAD_F(0x0451eea5) /* 0.270002982 */, 19 }, + /* 7299 */ { MAD_F(0x0452225f) /* 0.270052313 */, 19 }, + /* 7300 */ { MAD_F(0x0452561a) /* 0.270101645 */, 19 }, + /* 7301 */ { MAD_F(0x045289d5) /* 0.270150980 */, 19 }, + /* 7302 */ { MAD_F(0x0452bd91) /* 0.270200317 */, 19 }, + /* 7303 */ { MAD_F(0x0452f14d) /* 0.270249656 */, 19 }, + /* 7304 */ { MAD_F(0x0453250a) /* 0.270298998 */, 19 }, + /* 7305 */ { MAD_F(0x045358c8) /* 0.270348341 */, 19 }, + /* 7306 */ { MAD_F(0x04538c86) /* 0.270397687 */, 19 }, + /* 7307 */ { MAD_F(0x0453c045) /* 0.270447036 */, 19 }, + /* 7308 */ { MAD_F(0x0453f405) /* 0.270496386 */, 19 }, + /* 7309 */ { MAD_F(0x045427c5) /* 0.270545739 */, 19 }, + /* 7310 */ { MAD_F(0x04545b85) /* 0.270595094 */, 19 }, + /* 7311 */ { MAD_F(0x04548f46) /* 0.270644451 */, 19 }, + + /* 7312 */ { MAD_F(0x0454c308) /* 0.270693811 */, 19 }, + /* 7313 */ { MAD_F(0x0454f6cb) /* 0.270743173 */, 19 }, + /* 7314 */ { MAD_F(0x04552a8e) /* 0.270792537 */, 19 }, + /* 7315 */ { MAD_F(0x04555e51) /* 0.270841903 */, 19 }, + /* 7316 */ { MAD_F(0x04559216) /* 0.270891271 */, 19 }, + /* 7317 */ { MAD_F(0x0455c5db) /* 0.270940642 */, 19 }, + /* 7318 */ { MAD_F(0x0455f9a0) /* 0.270990015 */, 19 }, + /* 7319 */ { MAD_F(0x04562d66) /* 0.271039390 */, 19 }, + /* 7320 */ { MAD_F(0x0456612d) /* 0.271088768 */, 19 }, + /* 7321 */ { MAD_F(0x045694f4) /* 0.271138148 */, 19 }, + /* 7322 */ { MAD_F(0x0456c8bc) /* 0.271187530 */, 19 }, + /* 7323 */ { MAD_F(0x0456fc84) /* 0.271236914 */, 19 }, + /* 7324 */ { MAD_F(0x0457304e) /* 0.271286301 */, 19 }, + /* 7325 */ { MAD_F(0x04576417) /* 0.271335689 */, 19 }, + /* 7326 */ { MAD_F(0x045797e2) /* 0.271385080 */, 19 }, + /* 7327 */ { MAD_F(0x0457cbac) /* 0.271434474 */, 19 }, + + /* 7328 */ { MAD_F(0x0457ff78) /* 0.271483869 */, 19 }, + /* 7329 */ { MAD_F(0x04583344) /* 0.271533267 */, 19 }, + /* 7330 */ { MAD_F(0x04586711) /* 0.271582667 */, 19 }, + /* 7331 */ { MAD_F(0x04589ade) /* 0.271632069 */, 19 }, + /* 7332 */ { MAD_F(0x0458ceac) /* 0.271681474 */, 19 }, + /* 7333 */ { MAD_F(0x0459027b) /* 0.271730880 */, 19 }, + /* 7334 */ { MAD_F(0x0459364a) /* 0.271780289 */, 19 }, + /* 7335 */ { MAD_F(0x04596a19) /* 0.271829701 */, 19 }, + /* 7336 */ { MAD_F(0x04599dea) /* 0.271879114 */, 19 }, + /* 7337 */ { MAD_F(0x0459d1bb) /* 0.271928530 */, 19 }, + /* 7338 */ { MAD_F(0x045a058c) /* 0.271977948 */, 19 }, + /* 7339 */ { MAD_F(0x045a395e) /* 0.272027368 */, 19 }, + /* 7340 */ { MAD_F(0x045a6d31) /* 0.272076790 */, 19 }, + /* 7341 */ { MAD_F(0x045aa104) /* 0.272126215 */, 19 }, + /* 7342 */ { MAD_F(0x045ad4d8) /* 0.272175642 */, 19 }, + /* 7343 */ { MAD_F(0x045b08ad) /* 0.272225071 */, 19 }, + + /* 7344 */ { MAD_F(0x045b3c82) /* 0.272274503 */, 19 }, + /* 7345 */ { MAD_F(0x045b7058) /* 0.272323936 */, 19 }, + /* 7346 */ { MAD_F(0x045ba42e) /* 0.272373372 */, 19 }, + /* 7347 */ { MAD_F(0x045bd805) /* 0.272422810 */, 19 }, + /* 7348 */ { MAD_F(0x045c0bdd) /* 0.272472251 */, 19 }, + /* 7349 */ { MAD_F(0x045c3fb5) /* 0.272521693 */, 19 }, + /* 7350 */ { MAD_F(0x045c738e) /* 0.272571138 */, 19 }, + /* 7351 */ { MAD_F(0x045ca767) /* 0.272620585 */, 19 }, + /* 7352 */ { MAD_F(0x045cdb41) /* 0.272670035 */, 19 }, + /* 7353 */ { MAD_F(0x045d0f1b) /* 0.272719486 */, 19 }, + /* 7354 */ { MAD_F(0x045d42f7) /* 0.272768940 */, 19 }, + /* 7355 */ { MAD_F(0x045d76d2) /* 0.272818396 */, 19 }, + /* 7356 */ { MAD_F(0x045daaaf) /* 0.272867855 */, 19 }, + /* 7357 */ { MAD_F(0x045dde8c) /* 0.272917315 */, 19 }, + /* 7358 */ { MAD_F(0x045e1269) /* 0.272966778 */, 19 }, + /* 7359 */ { MAD_F(0x045e4647) /* 0.273016243 */, 19 }, + + /* 7360 */ { MAD_F(0x045e7a26) /* 0.273065710 */, 19 }, + /* 7361 */ { MAD_F(0x045eae06) /* 0.273115180 */, 19 }, + /* 7362 */ { MAD_F(0x045ee1e6) /* 0.273164652 */, 19 }, + /* 7363 */ { MAD_F(0x045f15c6) /* 0.273214126 */, 19 }, + /* 7364 */ { MAD_F(0x045f49a7) /* 0.273263602 */, 19 }, + /* 7365 */ { MAD_F(0x045f7d89) /* 0.273313081 */, 19 }, + /* 7366 */ { MAD_F(0x045fb16c) /* 0.273362561 */, 19 }, + /* 7367 */ { MAD_F(0x045fe54f) /* 0.273412044 */, 19 }, + /* 7368 */ { MAD_F(0x04601932) /* 0.273461530 */, 19 }, + /* 7369 */ { MAD_F(0x04604d16) /* 0.273511017 */, 19 }, + /* 7370 */ { MAD_F(0x046080fb) /* 0.273560507 */, 19 }, + /* 7371 */ { MAD_F(0x0460b4e1) /* 0.273609999 */, 19 }, + /* 7372 */ { MAD_F(0x0460e8c7) /* 0.273659493 */, 19 }, + /* 7373 */ { MAD_F(0x04611cad) /* 0.273708989 */, 19 }, + /* 7374 */ { MAD_F(0x04615094) /* 0.273758488 */, 19 }, + /* 7375 */ { MAD_F(0x0461847c) /* 0.273807989 */, 19 }, + + /* 7376 */ { MAD_F(0x0461b864) /* 0.273857492 */, 19 }, + /* 7377 */ { MAD_F(0x0461ec4d) /* 0.273906997 */, 19 }, + /* 7378 */ { MAD_F(0x04622037) /* 0.273956505 */, 19 }, + /* 7379 */ { MAD_F(0x04625421) /* 0.274006015 */, 19 }, + /* 7380 */ { MAD_F(0x0462880c) /* 0.274055527 */, 19 }, + /* 7381 */ { MAD_F(0x0462bbf7) /* 0.274105041 */, 19 }, + /* 7382 */ { MAD_F(0x0462efe3) /* 0.274154558 */, 19 }, + /* 7383 */ { MAD_F(0x046323d0) /* 0.274204076 */, 19 }, + /* 7384 */ { MAD_F(0x046357bd) /* 0.274253597 */, 19 }, + /* 7385 */ { MAD_F(0x04638bab) /* 0.274303121 */, 19 }, + /* 7386 */ { MAD_F(0x0463bf99) /* 0.274352646 */, 19 }, + /* 7387 */ { MAD_F(0x0463f388) /* 0.274402174 */, 19 }, + /* 7388 */ { MAD_F(0x04642778) /* 0.274451704 */, 19 }, + /* 7389 */ { MAD_F(0x04645b68) /* 0.274501236 */, 19 }, + /* 7390 */ { MAD_F(0x04648f59) /* 0.274550771 */, 19 }, + /* 7391 */ { MAD_F(0x0464c34a) /* 0.274600307 */, 19 }, + + /* 7392 */ { MAD_F(0x0464f73c) /* 0.274649846 */, 19 }, + /* 7393 */ { MAD_F(0x04652b2f) /* 0.274699387 */, 19 }, + /* 7394 */ { MAD_F(0x04655f22) /* 0.274748931 */, 19 }, + /* 7395 */ { MAD_F(0x04659316) /* 0.274798476 */, 19 }, + /* 7396 */ { MAD_F(0x0465c70a) /* 0.274848024 */, 19 }, + /* 7397 */ { MAD_F(0x0465faff) /* 0.274897574 */, 19 }, + /* 7398 */ { MAD_F(0x04662ef5) /* 0.274947126 */, 19 }, + /* 7399 */ { MAD_F(0x046662eb) /* 0.274996681 */, 19 }, + /* 7400 */ { MAD_F(0x046696e2) /* 0.275046238 */, 19 }, + /* 7401 */ { MAD_F(0x0466cad9) /* 0.275095797 */, 19 }, + /* 7402 */ { MAD_F(0x0466fed1) /* 0.275145358 */, 19 }, + /* 7403 */ { MAD_F(0x046732ca) /* 0.275194921 */, 19 }, + /* 7404 */ { MAD_F(0x046766c3) /* 0.275244487 */, 19 }, + /* 7405 */ { MAD_F(0x04679abd) /* 0.275294055 */, 19 }, + /* 7406 */ { MAD_F(0x0467ceb7) /* 0.275343625 */, 19 }, + /* 7407 */ { MAD_F(0x046802b2) /* 0.275393198 */, 19 }, + + /* 7408 */ { MAD_F(0x046836ae) /* 0.275442772 */, 19 }, + /* 7409 */ { MAD_F(0x04686aaa) /* 0.275492349 */, 19 }, + /* 7410 */ { MAD_F(0x04689ea7) /* 0.275541928 */, 19 }, + /* 7411 */ { MAD_F(0x0468d2a4) /* 0.275591509 */, 19 }, + /* 7412 */ { MAD_F(0x046906a2) /* 0.275641093 */, 19 }, + /* 7413 */ { MAD_F(0x04693aa1) /* 0.275690679 */, 19 }, + /* 7414 */ { MAD_F(0x04696ea0) /* 0.275740267 */, 19 }, + /* 7415 */ { MAD_F(0x0469a2a0) /* 0.275789857 */, 19 }, + /* 7416 */ { MAD_F(0x0469d6a0) /* 0.275839449 */, 19 }, + /* 7417 */ { MAD_F(0x046a0aa1) /* 0.275889044 */, 19 }, + /* 7418 */ { MAD_F(0x046a3ea3) /* 0.275938641 */, 19 }, + /* 7419 */ { MAD_F(0x046a72a5) /* 0.275988240 */, 19 }, + /* 7420 */ { MAD_F(0x046aa6a8) /* 0.276037842 */, 19 }, + /* 7421 */ { MAD_F(0x046adaab) /* 0.276087445 */, 19 }, + /* 7422 */ { MAD_F(0x046b0eaf) /* 0.276137051 */, 19 }, + /* 7423 */ { MAD_F(0x046b42b3) /* 0.276186659 */, 19 }, + + /* 7424 */ { MAD_F(0x046b76b9) /* 0.276236269 */, 19 }, + /* 7425 */ { MAD_F(0x046baabe) /* 0.276285882 */, 19 }, + /* 7426 */ { MAD_F(0x046bdec5) /* 0.276335497 */, 19 }, + /* 7427 */ { MAD_F(0x046c12cc) /* 0.276385113 */, 19 }, + /* 7428 */ { MAD_F(0x046c46d3) /* 0.276434733 */, 19 }, + /* 7429 */ { MAD_F(0x046c7adb) /* 0.276484354 */, 19 }, + /* 7430 */ { MAD_F(0x046caee4) /* 0.276533978 */, 19 }, + /* 7431 */ { MAD_F(0x046ce2ee) /* 0.276583604 */, 19 }, + /* 7432 */ { MAD_F(0x046d16f7) /* 0.276633232 */, 19 }, + /* 7433 */ { MAD_F(0x046d4b02) /* 0.276682862 */, 19 }, + /* 7434 */ { MAD_F(0x046d7f0d) /* 0.276732495 */, 19 }, + /* 7435 */ { MAD_F(0x046db319) /* 0.276782129 */, 19 }, + /* 7436 */ { MAD_F(0x046de725) /* 0.276831766 */, 19 }, + /* 7437 */ { MAD_F(0x046e1b32) /* 0.276881406 */, 19 }, + /* 7438 */ { MAD_F(0x046e4f40) /* 0.276931047 */, 19 }, + /* 7439 */ { MAD_F(0x046e834e) /* 0.276980691 */, 19 }, + + /* 7440 */ { MAD_F(0x046eb75c) /* 0.277030337 */, 19 }, + /* 7441 */ { MAD_F(0x046eeb6c) /* 0.277079985 */, 19 }, + /* 7442 */ { MAD_F(0x046f1f7c) /* 0.277129635 */, 19 }, + /* 7443 */ { MAD_F(0x046f538c) /* 0.277179288 */, 19 }, + /* 7444 */ { MAD_F(0x046f879d) /* 0.277228942 */, 19 }, + /* 7445 */ { MAD_F(0x046fbbaf) /* 0.277278600 */, 19 }, + /* 7446 */ { MAD_F(0x046fefc1) /* 0.277328259 */, 19 }, + /* 7447 */ { MAD_F(0x047023d4) /* 0.277377920 */, 19 }, + /* 7448 */ { MAD_F(0x047057e8) /* 0.277427584 */, 19 }, + /* 7449 */ { MAD_F(0x04708bfc) /* 0.277477250 */, 19 }, + /* 7450 */ { MAD_F(0x0470c011) /* 0.277526918 */, 19 }, + /* 7451 */ { MAD_F(0x0470f426) /* 0.277576588 */, 19 }, + /* 7452 */ { MAD_F(0x0471283c) /* 0.277626261 */, 19 }, + /* 7453 */ { MAD_F(0x04715c52) /* 0.277675936 */, 19 }, + /* 7454 */ { MAD_F(0x04719069) /* 0.277725613 */, 19 }, + /* 7455 */ { MAD_F(0x0471c481) /* 0.277775292 */, 19 }, + + /* 7456 */ { MAD_F(0x0471f899) /* 0.277824973 */, 19 }, + /* 7457 */ { MAD_F(0x04722cb2) /* 0.277874657 */, 19 }, + /* 7458 */ { MAD_F(0x047260cc) /* 0.277924343 */, 19 }, + /* 7459 */ { MAD_F(0x047294e6) /* 0.277974031 */, 19 }, + /* 7460 */ { MAD_F(0x0472c900) /* 0.278023722 */, 19 }, + /* 7461 */ { MAD_F(0x0472fd1b) /* 0.278073414 */, 19 }, + /* 7462 */ { MAD_F(0x04733137) /* 0.278123109 */, 19 }, + /* 7463 */ { MAD_F(0x04736554) /* 0.278172806 */, 19 }, + /* 7464 */ { MAD_F(0x04739971) /* 0.278222505 */, 19 }, + /* 7465 */ { MAD_F(0x0473cd8e) /* 0.278272207 */, 19 }, + /* 7466 */ { MAD_F(0x047401ad) /* 0.278321910 */, 19 }, + /* 7467 */ { MAD_F(0x047435cb) /* 0.278371616 */, 19 }, + /* 7468 */ { MAD_F(0x047469eb) /* 0.278421324 */, 19 }, + /* 7469 */ { MAD_F(0x04749e0b) /* 0.278471035 */, 19 }, + /* 7470 */ { MAD_F(0x0474d22c) /* 0.278520747 */, 19 }, + /* 7471 */ { MAD_F(0x0475064d) /* 0.278570462 */, 19 }, + + /* 7472 */ { MAD_F(0x04753a6f) /* 0.278620179 */, 19 }, + /* 7473 */ { MAD_F(0x04756e91) /* 0.278669898 */, 19 }, + /* 7474 */ { MAD_F(0x0475a2b4) /* 0.278719619 */, 19 }, + /* 7475 */ { MAD_F(0x0475d6d7) /* 0.278769343 */, 19 }, + /* 7476 */ { MAD_F(0x04760afc) /* 0.278819069 */, 19 }, + /* 7477 */ { MAD_F(0x04763f20) /* 0.278868797 */, 19 }, + /* 7478 */ { MAD_F(0x04767346) /* 0.278918527 */, 19 }, + /* 7479 */ { MAD_F(0x0476a76c) /* 0.278968260 */, 19 }, + /* 7480 */ { MAD_F(0x0476db92) /* 0.279017995 */, 19 }, + /* 7481 */ { MAD_F(0x04770fba) /* 0.279067731 */, 19 }, + /* 7482 */ { MAD_F(0x047743e1) /* 0.279117471 */, 19 }, + /* 7483 */ { MAD_F(0x0477780a) /* 0.279167212 */, 19 }, + /* 7484 */ { MAD_F(0x0477ac33) /* 0.279216956 */, 19 }, + /* 7485 */ { MAD_F(0x0477e05c) /* 0.279266701 */, 19 }, + /* 7486 */ { MAD_F(0x04781486) /* 0.279316449 */, 19 }, + /* 7487 */ { MAD_F(0x047848b1) /* 0.279366200 */, 19 }, + + /* 7488 */ { MAD_F(0x04787cdc) /* 0.279415952 */, 19 }, + /* 7489 */ { MAD_F(0x0478b108) /* 0.279465707 */, 19 }, + /* 7490 */ { MAD_F(0x0478e535) /* 0.279515464 */, 19 }, + /* 7491 */ { MAD_F(0x04791962) /* 0.279565223 */, 19 }, + /* 7492 */ { MAD_F(0x04794d8f) /* 0.279614984 */, 19 }, + /* 7493 */ { MAD_F(0x047981be) /* 0.279664748 */, 19 }, + /* 7494 */ { MAD_F(0x0479b5ed) /* 0.279714513 */, 19 }, + /* 7495 */ { MAD_F(0x0479ea1c) /* 0.279764281 */, 19 }, + /* 7496 */ { MAD_F(0x047a1e4c) /* 0.279814051 */, 19 }, + /* 7497 */ { MAD_F(0x047a527d) /* 0.279863824 */, 19 }, + /* 7498 */ { MAD_F(0x047a86ae) /* 0.279913598 */, 19 }, + /* 7499 */ { MAD_F(0x047abae0) /* 0.279963375 */, 19 }, + /* 7500 */ { MAD_F(0x047aef12) /* 0.280013154 */, 19 }, + /* 7501 */ { MAD_F(0x047b2346) /* 0.280062935 */, 19 }, + /* 7502 */ { MAD_F(0x047b5779) /* 0.280112719 */, 19 }, + /* 7503 */ { MAD_F(0x047b8bad) /* 0.280162504 */, 19 }, + + /* 7504 */ { MAD_F(0x047bbfe2) /* 0.280212292 */, 19 }, + /* 7505 */ { MAD_F(0x047bf418) /* 0.280262082 */, 19 }, + /* 7506 */ { MAD_F(0x047c284e) /* 0.280311875 */, 19 }, + /* 7507 */ { MAD_F(0x047c5c84) /* 0.280361669 */, 19 }, + /* 7508 */ { MAD_F(0x047c90bb) /* 0.280411466 */, 19 }, + /* 7509 */ { MAD_F(0x047cc4f3) /* 0.280461265 */, 19 }, + /* 7510 */ { MAD_F(0x047cf92c) /* 0.280511066 */, 19 }, + /* 7511 */ { MAD_F(0x047d2d65) /* 0.280560869 */, 19 }, + /* 7512 */ { MAD_F(0x047d619e) /* 0.280610675 */, 19 }, + /* 7513 */ { MAD_F(0x047d95d8) /* 0.280660483 */, 19 }, + /* 7514 */ { MAD_F(0x047dca13) /* 0.280710292 */, 19 }, + /* 7515 */ { MAD_F(0x047dfe4e) /* 0.280760105 */, 19 }, + /* 7516 */ { MAD_F(0x047e328a) /* 0.280809919 */, 19 }, + /* 7517 */ { MAD_F(0x047e66c7) /* 0.280859736 */, 19 }, + /* 7518 */ { MAD_F(0x047e9b04) /* 0.280909554 */, 19 }, + /* 7519 */ { MAD_F(0x047ecf42) /* 0.280959375 */, 19 }, + + /* 7520 */ { MAD_F(0x047f0380) /* 0.281009199 */, 19 }, + /* 7521 */ { MAD_F(0x047f37bf) /* 0.281059024 */, 19 }, + /* 7522 */ { MAD_F(0x047f6bff) /* 0.281108852 */, 19 }, + /* 7523 */ { MAD_F(0x047fa03f) /* 0.281158682 */, 19 }, + /* 7524 */ { MAD_F(0x047fd47f) /* 0.281208514 */, 19 }, + /* 7525 */ { MAD_F(0x048008c1) /* 0.281258348 */, 19 }, + /* 7526 */ { MAD_F(0x04803d02) /* 0.281308184 */, 19 }, + /* 7527 */ { MAD_F(0x04807145) /* 0.281358023 */, 19 }, + /* 7528 */ { MAD_F(0x0480a588) /* 0.281407864 */, 19 }, + /* 7529 */ { MAD_F(0x0480d9cc) /* 0.281457707 */, 19 }, + /* 7530 */ { MAD_F(0x04810e10) /* 0.281507552 */, 19 }, + /* 7531 */ { MAD_F(0x04814255) /* 0.281557400 */, 19 }, + /* 7532 */ { MAD_F(0x0481769a) /* 0.281607250 */, 19 }, + /* 7533 */ { MAD_F(0x0481aae0) /* 0.281657101 */, 19 }, + /* 7534 */ { MAD_F(0x0481df27) /* 0.281706956 */, 19 }, + /* 7535 */ { MAD_F(0x0482136e) /* 0.281756812 */, 19 }, + + /* 7536 */ { MAD_F(0x048247b6) /* 0.281806670 */, 19 }, + /* 7537 */ { MAD_F(0x04827bfe) /* 0.281856531 */, 19 }, + /* 7538 */ { MAD_F(0x0482b047) /* 0.281906394 */, 19 }, + /* 7539 */ { MAD_F(0x0482e491) /* 0.281956259 */, 19 }, + /* 7540 */ { MAD_F(0x048318db) /* 0.282006127 */, 19 }, + /* 7541 */ { MAD_F(0x04834d26) /* 0.282055996 */, 19 }, + /* 7542 */ { MAD_F(0x04838171) /* 0.282105868 */, 19 }, + /* 7543 */ { MAD_F(0x0483b5bd) /* 0.282155742 */, 19 }, + /* 7544 */ { MAD_F(0x0483ea0a) /* 0.282205618 */, 19 }, + /* 7545 */ { MAD_F(0x04841e57) /* 0.282255496 */, 19 }, + /* 7546 */ { MAD_F(0x048452a4) /* 0.282305377 */, 19 }, + /* 7547 */ { MAD_F(0x048486f3) /* 0.282355260 */, 19 }, + /* 7548 */ { MAD_F(0x0484bb42) /* 0.282405145 */, 19 }, + /* 7549 */ { MAD_F(0x0484ef91) /* 0.282455032 */, 19 }, + /* 7550 */ { MAD_F(0x048523e1) /* 0.282504921 */, 19 }, + /* 7551 */ { MAD_F(0x04855832) /* 0.282554813 */, 19 }, + + /* 7552 */ { MAD_F(0x04858c83) /* 0.282604707 */, 19 }, + /* 7553 */ { MAD_F(0x0485c0d5) /* 0.282654603 */, 19 }, + /* 7554 */ { MAD_F(0x0485f527) /* 0.282704501 */, 19 }, + /* 7555 */ { MAD_F(0x0486297a) /* 0.282754401 */, 19 }, + /* 7556 */ { MAD_F(0x04865dce) /* 0.282804304 */, 19 }, + /* 7557 */ { MAD_F(0x04869222) /* 0.282854209 */, 19 }, + /* 7558 */ { MAD_F(0x0486c677) /* 0.282904116 */, 19 }, + /* 7559 */ { MAD_F(0x0486facc) /* 0.282954025 */, 19 }, + /* 7560 */ { MAD_F(0x04872f22) /* 0.283003936 */, 19 }, + /* 7561 */ { MAD_F(0x04876379) /* 0.283053850 */, 19 }, + /* 7562 */ { MAD_F(0x048797d0) /* 0.283103766 */, 19 }, + /* 7563 */ { MAD_F(0x0487cc28) /* 0.283153684 */, 19 }, + /* 7564 */ { MAD_F(0x04880080) /* 0.283203604 */, 19 }, + /* 7565 */ { MAD_F(0x048834d9) /* 0.283253527 */, 19 }, + /* 7566 */ { MAD_F(0x04886933) /* 0.283303451 */, 19 }, + /* 7567 */ { MAD_F(0x04889d8d) /* 0.283353378 */, 19 }, + + /* 7568 */ { MAD_F(0x0488d1e8) /* 0.283403307 */, 19 }, + /* 7569 */ { MAD_F(0x04890643) /* 0.283453238 */, 19 }, + /* 7570 */ { MAD_F(0x04893a9f) /* 0.283503172 */, 19 }, + /* 7571 */ { MAD_F(0x04896efb) /* 0.283553107 */, 19 }, + /* 7572 */ { MAD_F(0x0489a358) /* 0.283603045 */, 19 }, + /* 7573 */ { MAD_F(0x0489d7b6) /* 0.283652985 */, 19 }, + /* 7574 */ { MAD_F(0x048a0c14) /* 0.283702927 */, 19 }, + /* 7575 */ { MAD_F(0x048a4073) /* 0.283752872 */, 19 }, + /* 7576 */ { MAD_F(0x048a74d3) /* 0.283802818 */, 19 }, + /* 7577 */ { MAD_F(0x048aa933) /* 0.283852767 */, 19 }, + /* 7578 */ { MAD_F(0x048add93) /* 0.283902718 */, 19 }, + /* 7579 */ { MAD_F(0x048b11f5) /* 0.283952671 */, 19 }, + /* 7580 */ { MAD_F(0x048b4656) /* 0.284002627 */, 19 }, + /* 7581 */ { MAD_F(0x048b7ab9) /* 0.284052584 */, 19 }, + /* 7582 */ { MAD_F(0x048baf1c) /* 0.284102544 */, 19 }, + /* 7583 */ { MAD_F(0x048be37f) /* 0.284152506 */, 19 }, + + /* 7584 */ { MAD_F(0x048c17e3) /* 0.284202470 */, 19 }, + /* 7585 */ { MAD_F(0x048c4c48) /* 0.284252436 */, 19 }, + /* 7586 */ { MAD_F(0x048c80ad) /* 0.284302405 */, 19 }, + /* 7587 */ { MAD_F(0x048cb513) /* 0.284352376 */, 19 }, + /* 7588 */ { MAD_F(0x048ce97a) /* 0.284402349 */, 19 }, + /* 7589 */ { MAD_F(0x048d1de1) /* 0.284452324 */, 19 }, + /* 7590 */ { MAD_F(0x048d5249) /* 0.284502301 */, 19 }, + /* 7591 */ { MAD_F(0x048d86b1) /* 0.284552281 */, 19 }, + /* 7592 */ { MAD_F(0x048dbb1a) /* 0.284602263 */, 19 }, + /* 7593 */ { MAD_F(0x048def83) /* 0.284652246 */, 19 }, + /* 7594 */ { MAD_F(0x048e23ed) /* 0.284702233 */, 19 }, + /* 7595 */ { MAD_F(0x048e5858) /* 0.284752221 */, 19 }, + /* 7596 */ { MAD_F(0x048e8cc3) /* 0.284802211 */, 19 }, + /* 7597 */ { MAD_F(0x048ec12f) /* 0.284852204 */, 19 }, + /* 7598 */ { MAD_F(0x048ef59b) /* 0.284902199 */, 19 }, + /* 7599 */ { MAD_F(0x048f2a08) /* 0.284952196 */, 19 }, + + /* 7600 */ { MAD_F(0x048f5e76) /* 0.285002195 */, 19 }, + /* 7601 */ { MAD_F(0x048f92e4) /* 0.285052197 */, 19 }, + /* 7602 */ { MAD_F(0x048fc753) /* 0.285102201 */, 19 }, + /* 7603 */ { MAD_F(0x048ffbc2) /* 0.285152206 */, 19 }, + /* 7604 */ { MAD_F(0x04903032) /* 0.285202214 */, 19 }, + /* 7605 */ { MAD_F(0x049064a3) /* 0.285252225 */, 19 }, + /* 7606 */ { MAD_F(0x04909914) /* 0.285302237 */, 19 }, + /* 7607 */ { MAD_F(0x0490cd86) /* 0.285352252 */, 19 }, + /* 7608 */ { MAD_F(0x049101f8) /* 0.285402269 */, 19 }, + /* 7609 */ { MAD_F(0x0491366b) /* 0.285452288 */, 19 }, + /* 7610 */ { MAD_F(0x04916ade) /* 0.285502309 */, 19 }, + /* 7611 */ { MAD_F(0x04919f52) /* 0.285552332 */, 19 }, + /* 7612 */ { MAD_F(0x0491d3c7) /* 0.285602358 */, 19 }, + /* 7613 */ { MAD_F(0x0492083c) /* 0.285652386 */, 19 }, + /* 7614 */ { MAD_F(0x04923cb2) /* 0.285702416 */, 19 }, + /* 7615 */ { MAD_F(0x04927128) /* 0.285752448 */, 19 }, + + /* 7616 */ { MAD_F(0x0492a59f) /* 0.285802482 */, 19 }, + /* 7617 */ { MAD_F(0x0492da17) /* 0.285852519 */, 19 }, + /* 7618 */ { MAD_F(0x04930e8f) /* 0.285902557 */, 19 }, + /* 7619 */ { MAD_F(0x04934308) /* 0.285952598 */, 19 }, + /* 7620 */ { MAD_F(0x04937781) /* 0.286002641 */, 19 }, + /* 7621 */ { MAD_F(0x0493abfb) /* 0.286052687 */, 19 }, + /* 7622 */ { MAD_F(0x0493e076) /* 0.286102734 */, 19 }, + /* 7623 */ { MAD_F(0x049414f1) /* 0.286152784 */, 19 }, + /* 7624 */ { MAD_F(0x0494496c) /* 0.286202836 */, 19 }, + /* 7625 */ { MAD_F(0x04947de9) /* 0.286252890 */, 19 }, + /* 7626 */ { MAD_F(0x0494b266) /* 0.286302946 */, 19 }, + /* 7627 */ { MAD_F(0x0494e6e3) /* 0.286353005 */, 19 }, + /* 7628 */ { MAD_F(0x04951b61) /* 0.286403065 */, 19 }, + /* 7629 */ { MAD_F(0x04954fe0) /* 0.286453128 */, 19 }, + /* 7630 */ { MAD_F(0x0495845f) /* 0.286503193 */, 19 }, + /* 7631 */ { MAD_F(0x0495b8df) /* 0.286553260 */, 19 }, + + /* 7632 */ { MAD_F(0x0495ed5f) /* 0.286603329 */, 19 }, + /* 7633 */ { MAD_F(0x049621e0) /* 0.286653401 */, 19 }, + /* 7634 */ { MAD_F(0x04965662) /* 0.286703475 */, 19 }, + /* 7635 */ { MAD_F(0x04968ae4) /* 0.286753551 */, 19 }, + /* 7636 */ { MAD_F(0x0496bf67) /* 0.286803629 */, 19 }, + /* 7637 */ { MAD_F(0x0496f3ea) /* 0.286853709 */, 19 }, + /* 7638 */ { MAD_F(0x0497286e) /* 0.286903792 */, 19 }, + /* 7639 */ { MAD_F(0x04975cf2) /* 0.286953876 */, 19 }, + /* 7640 */ { MAD_F(0x04979177) /* 0.287003963 */, 19 }, + /* 7641 */ { MAD_F(0x0497c5fd) /* 0.287054052 */, 19 }, + /* 7642 */ { MAD_F(0x0497fa83) /* 0.287104143 */, 19 }, + /* 7643 */ { MAD_F(0x04982f0a) /* 0.287154237 */, 19 }, + /* 7644 */ { MAD_F(0x04986392) /* 0.287204332 */, 19 }, + /* 7645 */ { MAD_F(0x0498981a) /* 0.287254430 */, 19 }, + /* 7646 */ { MAD_F(0x0498cca2) /* 0.287304530 */, 19 }, + /* 7647 */ { MAD_F(0x0499012c) /* 0.287354632 */, 19 }, + + /* 7648 */ { MAD_F(0x049935b5) /* 0.287404737 */, 19 }, + /* 7649 */ { MAD_F(0x04996a40) /* 0.287454843 */, 19 }, + /* 7650 */ { MAD_F(0x04999ecb) /* 0.287504952 */, 19 }, + /* 7651 */ { MAD_F(0x0499d356) /* 0.287555063 */, 19 }, + /* 7652 */ { MAD_F(0x049a07e2) /* 0.287605176 */, 19 }, + /* 7653 */ { MAD_F(0x049a3c6f) /* 0.287655291 */, 19 }, + /* 7654 */ { MAD_F(0x049a70fc) /* 0.287705409 */, 19 }, + /* 7655 */ { MAD_F(0x049aa58a) /* 0.287755528 */, 19 }, + /* 7656 */ { MAD_F(0x049ada19) /* 0.287805650 */, 19 }, + /* 7657 */ { MAD_F(0x049b0ea8) /* 0.287855774 */, 19 }, + /* 7658 */ { MAD_F(0x049b4337) /* 0.287905900 */, 19 }, + /* 7659 */ { MAD_F(0x049b77c8) /* 0.287956028 */, 19 }, + /* 7660 */ { MAD_F(0x049bac58) /* 0.288006159 */, 19 }, + /* 7661 */ { MAD_F(0x049be0ea) /* 0.288056292 */, 19 }, + /* 7662 */ { MAD_F(0x049c157c) /* 0.288106427 */, 19 }, + /* 7663 */ { MAD_F(0x049c4a0e) /* 0.288156564 */, 19 }, + + /* 7664 */ { MAD_F(0x049c7ea1) /* 0.288206703 */, 19 }, + /* 7665 */ { MAD_F(0x049cb335) /* 0.288256844 */, 19 }, + /* 7666 */ { MAD_F(0x049ce7ca) /* 0.288306988 */, 19 }, + /* 7667 */ { MAD_F(0x049d1c5e) /* 0.288357134 */, 19 }, + /* 7668 */ { MAD_F(0x049d50f4) /* 0.288407282 */, 19 }, + /* 7669 */ { MAD_F(0x049d858a) /* 0.288457432 */, 19 }, + /* 7670 */ { MAD_F(0x049dba21) /* 0.288507584 */, 19 }, + /* 7671 */ { MAD_F(0x049deeb8) /* 0.288557739 */, 19 }, + /* 7672 */ { MAD_F(0x049e2350) /* 0.288607895 */, 19 }, + /* 7673 */ { MAD_F(0x049e57e8) /* 0.288658054 */, 19 }, + /* 7674 */ { MAD_F(0x049e8c81) /* 0.288708215 */, 19 }, + /* 7675 */ { MAD_F(0x049ec11b) /* 0.288758379 */, 19 }, + /* 7676 */ { MAD_F(0x049ef5b5) /* 0.288808544 */, 19 }, + /* 7677 */ { MAD_F(0x049f2a50) /* 0.288858712 */, 19 }, + /* 7678 */ { MAD_F(0x049f5eeb) /* 0.288908881 */, 19 }, + /* 7679 */ { MAD_F(0x049f9387) /* 0.288959053 */, 19 }, + + /* 7680 */ { MAD_F(0x049fc824) /* 0.289009227 */, 19 }, + /* 7681 */ { MAD_F(0x049ffcc1) /* 0.289059404 */, 19 }, + /* 7682 */ { MAD_F(0x04a0315e) /* 0.289109582 */, 19 }, + /* 7683 */ { MAD_F(0x04a065fd) /* 0.289159763 */, 19 }, + /* 7684 */ { MAD_F(0x04a09a9b) /* 0.289209946 */, 19 }, + /* 7685 */ { MAD_F(0x04a0cf3b) /* 0.289260131 */, 19 }, + /* 7686 */ { MAD_F(0x04a103db) /* 0.289310318 */, 19 }, + /* 7687 */ { MAD_F(0x04a1387b) /* 0.289360507 */, 19 }, + /* 7688 */ { MAD_F(0x04a16d1d) /* 0.289410699 */, 19 }, + /* 7689 */ { MAD_F(0x04a1a1be) /* 0.289460893 */, 19 }, + /* 7690 */ { MAD_F(0x04a1d661) /* 0.289511088 */, 19 }, + /* 7691 */ { MAD_F(0x04a20b04) /* 0.289561287 */, 19 }, + /* 7692 */ { MAD_F(0x04a23fa7) /* 0.289611487 */, 19 }, + /* 7693 */ { MAD_F(0x04a2744b) /* 0.289661689 */, 19 }, + /* 7694 */ { MAD_F(0x04a2a8f0) /* 0.289711894 */, 19 }, + /* 7695 */ { MAD_F(0x04a2dd95) /* 0.289762101 */, 19 }, + + /* 7696 */ { MAD_F(0x04a3123b) /* 0.289812309 */, 19 }, + /* 7697 */ { MAD_F(0x04a346e2) /* 0.289862521 */, 19 }, + /* 7698 */ { MAD_F(0x04a37b89) /* 0.289912734 */, 19 }, + /* 7699 */ { MAD_F(0x04a3b030) /* 0.289962949 */, 19 }, + /* 7700 */ { MAD_F(0x04a3e4d8) /* 0.290013167 */, 19 }, + /* 7701 */ { MAD_F(0x04a41981) /* 0.290063387 */, 19 }, + /* 7702 */ { MAD_F(0x04a44e2b) /* 0.290113609 */, 19 }, + /* 7703 */ { MAD_F(0x04a482d5) /* 0.290163833 */, 19 }, + /* 7704 */ { MAD_F(0x04a4b77f) /* 0.290214059 */, 19 }, + /* 7705 */ { MAD_F(0x04a4ec2a) /* 0.290264288 */, 19 }, + /* 7706 */ { MAD_F(0x04a520d6) /* 0.290314519 */, 19 }, + /* 7707 */ { MAD_F(0x04a55582) /* 0.290364751 */, 19 }, + /* 7708 */ { MAD_F(0x04a58a2f) /* 0.290414986 */, 19 }, + /* 7709 */ { MAD_F(0x04a5bedd) /* 0.290465224 */, 19 }, + /* 7710 */ { MAD_F(0x04a5f38b) /* 0.290515463 */, 19 }, + /* 7711 */ { MAD_F(0x04a62839) /* 0.290565705 */, 19 }, + + /* 7712 */ { MAD_F(0x04a65ce8) /* 0.290615948 */, 19 }, + /* 7713 */ { MAD_F(0x04a69198) /* 0.290666194 */, 19 }, + /* 7714 */ { MAD_F(0x04a6c648) /* 0.290716442 */, 19 }, + /* 7715 */ { MAD_F(0x04a6faf9) /* 0.290766692 */, 19 }, + /* 7716 */ { MAD_F(0x04a72fab) /* 0.290816945 */, 19 }, + /* 7717 */ { MAD_F(0x04a7645d) /* 0.290867199 */, 19 }, + /* 7718 */ { MAD_F(0x04a79910) /* 0.290917456 */, 19 }, + /* 7719 */ { MAD_F(0x04a7cdc3) /* 0.290967715 */, 19 }, + /* 7720 */ { MAD_F(0x04a80277) /* 0.291017976 */, 19 }, + /* 7721 */ { MAD_F(0x04a8372b) /* 0.291068239 */, 19 }, + /* 7722 */ { MAD_F(0x04a86be0) /* 0.291118505 */, 19 }, + /* 7723 */ { MAD_F(0x04a8a096) /* 0.291168772 */, 19 }, + /* 7724 */ { MAD_F(0x04a8d54c) /* 0.291219042 */, 19 }, + /* 7725 */ { MAD_F(0x04a90a03) /* 0.291269314 */, 19 }, + /* 7726 */ { MAD_F(0x04a93eba) /* 0.291319588 */, 19 }, + /* 7727 */ { MAD_F(0x04a97372) /* 0.291369865 */, 19 }, + + /* 7728 */ { MAD_F(0x04a9a82b) /* 0.291420143 */, 19 }, + /* 7729 */ { MAD_F(0x04a9dce4) /* 0.291470424 */, 19 }, + /* 7730 */ { MAD_F(0x04aa119d) /* 0.291520706 */, 19 }, + /* 7731 */ { MAD_F(0x04aa4658) /* 0.291570991 */, 19 }, + /* 7732 */ { MAD_F(0x04aa7b13) /* 0.291621278 */, 19 }, + /* 7733 */ { MAD_F(0x04aaafce) /* 0.291671568 */, 19 }, + /* 7734 */ { MAD_F(0x04aae48a) /* 0.291721859 */, 19 }, + /* 7735 */ { MAD_F(0x04ab1947) /* 0.291772153 */, 19 }, + /* 7736 */ { MAD_F(0x04ab4e04) /* 0.291822449 */, 19 }, + /* 7737 */ { MAD_F(0x04ab82c2) /* 0.291872747 */, 19 }, + /* 7738 */ { MAD_F(0x04abb780) /* 0.291923047 */, 19 }, + /* 7739 */ { MAD_F(0x04abec3f) /* 0.291973349 */, 19 }, + /* 7740 */ { MAD_F(0x04ac20fe) /* 0.292023653 */, 19 }, + /* 7741 */ { MAD_F(0x04ac55be) /* 0.292073960 */, 19 }, + /* 7742 */ { MAD_F(0x04ac8a7f) /* 0.292124269 */, 19 }, + /* 7743 */ { MAD_F(0x04acbf40) /* 0.292174580 */, 19 }, + + /* 7744 */ { MAD_F(0x04acf402) /* 0.292224893 */, 19 }, + /* 7745 */ { MAD_F(0x04ad28c5) /* 0.292275208 */, 19 }, + /* 7746 */ { MAD_F(0x04ad5d88) /* 0.292325526 */, 19 }, + /* 7747 */ { MAD_F(0x04ad924b) /* 0.292375845 */, 19 }, + /* 7748 */ { MAD_F(0x04adc70f) /* 0.292426167 */, 19 }, + /* 7749 */ { MAD_F(0x04adfbd4) /* 0.292476491 */, 19 }, + /* 7750 */ { MAD_F(0x04ae3099) /* 0.292526817 */, 19 }, + /* 7751 */ { MAD_F(0x04ae655f) /* 0.292577145 */, 19 }, + /* 7752 */ { MAD_F(0x04ae9a26) /* 0.292627476 */, 19 }, + /* 7753 */ { MAD_F(0x04aeceed) /* 0.292677808 */, 19 }, + /* 7754 */ { MAD_F(0x04af03b4) /* 0.292728143 */, 19 }, + /* 7755 */ { MAD_F(0x04af387d) /* 0.292778480 */, 19 }, + /* 7756 */ { MAD_F(0x04af6d45) /* 0.292828819 */, 19 }, + /* 7757 */ { MAD_F(0x04afa20f) /* 0.292879160 */, 19 }, + /* 7758 */ { MAD_F(0x04afd6d9) /* 0.292929504 */, 19 }, + /* 7759 */ { MAD_F(0x04b00ba3) /* 0.292979849 */, 19 }, + + /* 7760 */ { MAD_F(0x04b0406e) /* 0.293030197 */, 19 }, + /* 7761 */ { MAD_F(0x04b0753a) /* 0.293080547 */, 19 }, + /* 7762 */ { MAD_F(0x04b0aa06) /* 0.293130899 */, 19 }, + /* 7763 */ { MAD_F(0x04b0ded3) /* 0.293181253 */, 19 }, + /* 7764 */ { MAD_F(0x04b113a1) /* 0.293231610 */, 19 }, + /* 7765 */ { MAD_F(0x04b1486f) /* 0.293281968 */, 19 }, + /* 7766 */ { MAD_F(0x04b17d3d) /* 0.293332329 */, 19 }, + /* 7767 */ { MAD_F(0x04b1b20c) /* 0.293382692 */, 19 }, + /* 7768 */ { MAD_F(0x04b1e6dc) /* 0.293433057 */, 19 }, + /* 7769 */ { MAD_F(0x04b21bad) /* 0.293483424 */, 19 }, + /* 7770 */ { MAD_F(0x04b2507d) /* 0.293533794 */, 19 }, + /* 7771 */ { MAD_F(0x04b2854f) /* 0.293584165 */, 19 }, + /* 7772 */ { MAD_F(0x04b2ba21) /* 0.293634539 */, 19 }, + /* 7773 */ { MAD_F(0x04b2eef4) /* 0.293684915 */, 19 }, + /* 7774 */ { MAD_F(0x04b323c7) /* 0.293735293 */, 19 }, + /* 7775 */ { MAD_F(0x04b3589b) /* 0.293785673 */, 19 }, + + /* 7776 */ { MAD_F(0x04b38d6f) /* 0.293836055 */, 19 }, + /* 7777 */ { MAD_F(0x04b3c244) /* 0.293886440 */, 19 }, + /* 7778 */ { MAD_F(0x04b3f71a) /* 0.293936826 */, 19 }, + /* 7779 */ { MAD_F(0x04b42bf0) /* 0.293987215 */, 19 }, + /* 7780 */ { MAD_F(0x04b460c7) /* 0.294037606 */, 19 }, + /* 7781 */ { MAD_F(0x04b4959e) /* 0.294087999 */, 19 }, + /* 7782 */ { MAD_F(0x04b4ca76) /* 0.294138395 */, 19 }, + /* 7783 */ { MAD_F(0x04b4ff4e) /* 0.294188792 */, 19 }, + /* 7784 */ { MAD_F(0x04b53427) /* 0.294239192 */, 19 }, + /* 7785 */ { MAD_F(0x04b56901) /* 0.294289593 */, 19 }, + /* 7786 */ { MAD_F(0x04b59ddb) /* 0.294339997 */, 19 }, + /* 7787 */ { MAD_F(0x04b5d2b6) /* 0.294390403 */, 19 }, + /* 7788 */ { MAD_F(0x04b60791) /* 0.294440812 */, 19 }, + /* 7789 */ { MAD_F(0x04b63c6d) /* 0.294491222 */, 19 }, + /* 7790 */ { MAD_F(0x04b6714a) /* 0.294541635 */, 19 }, + /* 7791 */ { MAD_F(0x04b6a627) /* 0.294592049 */, 19 }, + + /* 7792 */ { MAD_F(0x04b6db05) /* 0.294642466 */, 19 }, + /* 7793 */ { MAD_F(0x04b70fe3) /* 0.294692885 */, 19 }, + /* 7794 */ { MAD_F(0x04b744c2) /* 0.294743306 */, 19 }, + /* 7795 */ { MAD_F(0x04b779a1) /* 0.294793730 */, 19 }, + /* 7796 */ { MAD_F(0x04b7ae81) /* 0.294844155 */, 19 }, + /* 7797 */ { MAD_F(0x04b7e362) /* 0.294894583 */, 19 }, + /* 7798 */ { MAD_F(0x04b81843) /* 0.294945013 */, 19 }, + /* 7799 */ { MAD_F(0x04b84d24) /* 0.294995445 */, 19 }, + /* 7800 */ { MAD_F(0x04b88207) /* 0.295045879 */, 19 }, + /* 7801 */ { MAD_F(0x04b8b6ea) /* 0.295096315 */, 19 }, + /* 7802 */ { MAD_F(0x04b8ebcd) /* 0.295146753 */, 19 }, + /* 7803 */ { MAD_F(0x04b920b1) /* 0.295197194 */, 19 }, + /* 7804 */ { MAD_F(0x04b95596) /* 0.295247637 */, 19 }, + /* 7805 */ { MAD_F(0x04b98a7b) /* 0.295298082 */, 19 }, + /* 7806 */ { MAD_F(0x04b9bf61) /* 0.295348529 */, 19 }, + /* 7807 */ { MAD_F(0x04b9f447) /* 0.295398978 */, 19 }, + + /* 7808 */ { MAD_F(0x04ba292e) /* 0.295449429 */, 19 }, + /* 7809 */ { MAD_F(0x04ba5e16) /* 0.295499883 */, 19 }, + /* 7810 */ { MAD_F(0x04ba92fe) /* 0.295550338 */, 19 }, + /* 7811 */ { MAD_F(0x04bac7e6) /* 0.295600796 */, 19 }, + /* 7812 */ { MAD_F(0x04bafcd0) /* 0.295651256 */, 19 }, + /* 7813 */ { MAD_F(0x04bb31b9) /* 0.295701718 */, 19 }, + /* 7814 */ { MAD_F(0x04bb66a4) /* 0.295752183 */, 19 }, + /* 7815 */ { MAD_F(0x04bb9b8f) /* 0.295802649 */, 19 }, + /* 7816 */ { MAD_F(0x04bbd07a) /* 0.295853118 */, 19 }, + /* 7817 */ { MAD_F(0x04bc0566) /* 0.295903588 */, 19 }, + /* 7818 */ { MAD_F(0x04bc3a53) /* 0.295954061 */, 19 }, + /* 7819 */ { MAD_F(0x04bc6f40) /* 0.296004536 */, 19 }, + /* 7820 */ { MAD_F(0x04bca42e) /* 0.296055013 */, 19 }, + /* 7821 */ { MAD_F(0x04bcd91d) /* 0.296105493 */, 19 }, + /* 7822 */ { MAD_F(0x04bd0e0c) /* 0.296155974 */, 19 }, + /* 7823 */ { MAD_F(0x04bd42fb) /* 0.296206458 */, 19 }, + + /* 7824 */ { MAD_F(0x04bd77ec) /* 0.296256944 */, 19 }, + /* 7825 */ { MAD_F(0x04bdacdc) /* 0.296307432 */, 19 }, + /* 7826 */ { MAD_F(0x04bde1ce) /* 0.296357922 */, 19 }, + /* 7827 */ { MAD_F(0x04be16c0) /* 0.296408414 */, 19 }, + /* 7828 */ { MAD_F(0x04be4bb2) /* 0.296458908 */, 19 }, + /* 7829 */ { MAD_F(0x04be80a5) /* 0.296509405 */, 19 }, + /* 7830 */ { MAD_F(0x04beb599) /* 0.296559904 */, 19 }, + /* 7831 */ { MAD_F(0x04beea8d) /* 0.296610404 */, 19 }, + /* 7832 */ { MAD_F(0x04bf1f82) /* 0.296660907 */, 19 }, + /* 7833 */ { MAD_F(0x04bf5477) /* 0.296711413 */, 19 }, + /* 7834 */ { MAD_F(0x04bf896d) /* 0.296761920 */, 19 }, + /* 7835 */ { MAD_F(0x04bfbe64) /* 0.296812429 */, 19 }, + /* 7836 */ { MAD_F(0x04bff35b) /* 0.296862941 */, 19 }, + /* 7837 */ { MAD_F(0x04c02852) /* 0.296913455 */, 19 }, + /* 7838 */ { MAD_F(0x04c05d4b) /* 0.296963971 */, 19 }, + /* 7839 */ { MAD_F(0x04c09243) /* 0.297014489 */, 19 }, + + /* 7840 */ { MAD_F(0x04c0c73d) /* 0.297065009 */, 19 }, + /* 7841 */ { MAD_F(0x04c0fc37) /* 0.297115531 */, 19 }, + /* 7842 */ { MAD_F(0x04c13131) /* 0.297166056 */, 19 }, + /* 7843 */ { MAD_F(0x04c1662d) /* 0.297216582 */, 19 }, + /* 7844 */ { MAD_F(0x04c19b28) /* 0.297267111 */, 19 }, + /* 7845 */ { MAD_F(0x04c1d025) /* 0.297317642 */, 19 }, + /* 7846 */ { MAD_F(0x04c20521) /* 0.297368175 */, 19 }, + /* 7847 */ { MAD_F(0x04c23a1f) /* 0.297418710 */, 19 }, + /* 7848 */ { MAD_F(0x04c26f1d) /* 0.297469248 */, 19 }, + /* 7849 */ { MAD_F(0x04c2a41b) /* 0.297519787 */, 19 }, + /* 7850 */ { MAD_F(0x04c2d91b) /* 0.297570329 */, 19 }, + /* 7851 */ { MAD_F(0x04c30e1a) /* 0.297620873 */, 19 }, + /* 7852 */ { MAD_F(0x04c3431b) /* 0.297671418 */, 19 }, + /* 7853 */ { MAD_F(0x04c3781c) /* 0.297721967 */, 19 }, + /* 7854 */ { MAD_F(0x04c3ad1d) /* 0.297772517 */, 19 }, + /* 7855 */ { MAD_F(0x04c3e21f) /* 0.297823069 */, 19 }, + + /* 7856 */ { MAD_F(0x04c41722) /* 0.297873624 */, 19 }, + /* 7857 */ { MAD_F(0x04c44c25) /* 0.297924180 */, 19 }, + /* 7858 */ { MAD_F(0x04c48129) /* 0.297974739 */, 19 }, + /* 7859 */ { MAD_F(0x04c4b62d) /* 0.298025300 */, 19 }, + /* 7860 */ { MAD_F(0x04c4eb32) /* 0.298075863 */, 19 }, + /* 7861 */ { MAD_F(0x04c52038) /* 0.298126429 */, 19 }, + /* 7862 */ { MAD_F(0x04c5553e) /* 0.298176996 */, 19 }, + /* 7863 */ { MAD_F(0x04c58a44) /* 0.298227565 */, 19 }, + /* 7864 */ { MAD_F(0x04c5bf4c) /* 0.298278137 */, 19 }, + /* 7865 */ { MAD_F(0x04c5f453) /* 0.298328711 */, 19 }, + /* 7866 */ { MAD_F(0x04c6295c) /* 0.298379287 */, 19 }, + /* 7867 */ { MAD_F(0x04c65e65) /* 0.298429865 */, 19 }, + /* 7868 */ { MAD_F(0x04c6936e) /* 0.298480445 */, 19 }, + /* 7869 */ { MAD_F(0x04c6c878) /* 0.298531028 */, 19 }, + /* 7870 */ { MAD_F(0x04c6fd83) /* 0.298581612 */, 19 }, + /* 7871 */ { MAD_F(0x04c7328e) /* 0.298632199 */, 19 }, + + /* 7872 */ { MAD_F(0x04c7679a) /* 0.298682788 */, 19 }, + /* 7873 */ { MAD_F(0x04c79ca7) /* 0.298733379 */, 19 }, + /* 7874 */ { MAD_F(0x04c7d1b4) /* 0.298783972 */, 19 }, + /* 7875 */ { MAD_F(0x04c806c1) /* 0.298834567 */, 19 }, + /* 7876 */ { MAD_F(0x04c83bcf) /* 0.298885165 */, 19 }, + /* 7877 */ { MAD_F(0x04c870de) /* 0.298935764 */, 19 }, + /* 7878 */ { MAD_F(0x04c8a5ed) /* 0.298986366 */, 19 }, + /* 7879 */ { MAD_F(0x04c8dafd) /* 0.299036970 */, 19 }, + /* 7880 */ { MAD_F(0x04c9100d) /* 0.299087576 */, 19 }, + /* 7881 */ { MAD_F(0x04c9451e) /* 0.299138184 */, 19 }, + /* 7882 */ { MAD_F(0x04c97a30) /* 0.299188794 */, 19 }, + /* 7883 */ { MAD_F(0x04c9af42) /* 0.299239406 */, 19 }, + /* 7884 */ { MAD_F(0x04c9e455) /* 0.299290021 */, 19 }, + /* 7885 */ { MAD_F(0x04ca1968) /* 0.299340638 */, 19 }, + /* 7886 */ { MAD_F(0x04ca4e7c) /* 0.299391256 */, 19 }, + /* 7887 */ { MAD_F(0x04ca8391) /* 0.299441877 */, 19 }, + + /* 7888 */ { MAD_F(0x04cab8a6) /* 0.299492500 */, 19 }, + /* 7889 */ { MAD_F(0x04caedbb) /* 0.299543126 */, 19 }, + /* 7890 */ { MAD_F(0x04cb22d1) /* 0.299593753 */, 19 }, + /* 7891 */ { MAD_F(0x04cb57e8) /* 0.299644382 */, 19 }, + /* 7892 */ { MAD_F(0x04cb8d00) /* 0.299695014 */, 19 }, + /* 7893 */ { MAD_F(0x04cbc217) /* 0.299745648 */, 19 }, + /* 7894 */ { MAD_F(0x04cbf730) /* 0.299796284 */, 19 }, + /* 7895 */ { MAD_F(0x04cc2c49) /* 0.299846922 */, 19 }, + /* 7896 */ { MAD_F(0x04cc6163) /* 0.299897562 */, 19 }, + /* 7897 */ { MAD_F(0x04cc967d) /* 0.299948204 */, 19 }, + /* 7898 */ { MAD_F(0x04cccb98) /* 0.299998849 */, 19 }, + /* 7899 */ { MAD_F(0x04cd00b3) /* 0.300049495 */, 19 }, + /* 7900 */ { MAD_F(0x04cd35cf) /* 0.300100144 */, 19 }, + /* 7901 */ { MAD_F(0x04cd6aeb) /* 0.300150795 */, 19 }, + /* 7902 */ { MAD_F(0x04cda008) /* 0.300201448 */, 19 }, + /* 7903 */ { MAD_F(0x04cdd526) /* 0.300252103 */, 19 }, + + /* 7904 */ { MAD_F(0x04ce0a44) /* 0.300302761 */, 19 }, + /* 7905 */ { MAD_F(0x04ce3f63) /* 0.300353420 */, 19 }, + /* 7906 */ { MAD_F(0x04ce7482) /* 0.300404082 */, 19 }, + /* 7907 */ { MAD_F(0x04cea9a2) /* 0.300454745 */, 19 }, + /* 7908 */ { MAD_F(0x04cedec3) /* 0.300505411 */, 19 }, + /* 7909 */ { MAD_F(0x04cf13e4) /* 0.300556079 */, 19 }, + /* 7910 */ { MAD_F(0x04cf4906) /* 0.300606749 */, 19 }, + /* 7911 */ { MAD_F(0x04cf7e28) /* 0.300657421 */, 19 }, + /* 7912 */ { MAD_F(0x04cfb34b) /* 0.300708096 */, 19 }, + /* 7913 */ { MAD_F(0x04cfe86e) /* 0.300758772 */, 19 }, + /* 7914 */ { MAD_F(0x04d01d92) /* 0.300809451 */, 19 }, + /* 7915 */ { MAD_F(0x04d052b6) /* 0.300860132 */, 19 }, + /* 7916 */ { MAD_F(0x04d087db) /* 0.300910815 */, 19 }, + /* 7917 */ { MAD_F(0x04d0bd01) /* 0.300961500 */, 19 }, + /* 7918 */ { MAD_F(0x04d0f227) /* 0.301012187 */, 19 }, + /* 7919 */ { MAD_F(0x04d1274e) /* 0.301062876 */, 19 }, + + /* 7920 */ { MAD_F(0x04d15c76) /* 0.301113568 */, 19 }, + /* 7921 */ { MAD_F(0x04d1919e) /* 0.301164261 */, 19 }, + /* 7922 */ { MAD_F(0x04d1c6c6) /* 0.301214957 */, 19 }, + /* 7923 */ { MAD_F(0x04d1fbef) /* 0.301265655 */, 19 }, + /* 7924 */ { MAD_F(0x04d23119) /* 0.301316355 */, 19 }, + /* 7925 */ { MAD_F(0x04d26643) /* 0.301367057 */, 19 }, + /* 7926 */ { MAD_F(0x04d29b6e) /* 0.301417761 */, 19 }, + /* 7927 */ { MAD_F(0x04d2d099) /* 0.301468468 */, 19 }, + /* 7928 */ { MAD_F(0x04d305c5) /* 0.301519176 */, 19 }, + /* 7929 */ { MAD_F(0x04d33af2) /* 0.301569887 */, 19 }, + /* 7930 */ { MAD_F(0x04d3701f) /* 0.301620599 */, 19 }, + /* 7931 */ { MAD_F(0x04d3a54d) /* 0.301671314 */, 19 }, + /* 7932 */ { MAD_F(0x04d3da7b) /* 0.301722031 */, 19 }, + /* 7933 */ { MAD_F(0x04d40faa) /* 0.301772751 */, 19 }, + /* 7934 */ { MAD_F(0x04d444d9) /* 0.301823472 */, 19 }, + /* 7935 */ { MAD_F(0x04d47a09) /* 0.301874195 */, 19 }, + + /* 7936 */ { MAD_F(0x04d4af3a) /* 0.301924921 */, 19 }, + /* 7937 */ { MAD_F(0x04d4e46b) /* 0.301975649 */, 19 }, + /* 7938 */ { MAD_F(0x04d5199c) /* 0.302026378 */, 19 }, + /* 7939 */ { MAD_F(0x04d54ecf) /* 0.302077110 */, 19 }, + /* 7940 */ { MAD_F(0x04d58401) /* 0.302127845 */, 19 }, + /* 7941 */ { MAD_F(0x04d5b935) /* 0.302178581 */, 19 }, + /* 7942 */ { MAD_F(0x04d5ee69) /* 0.302229319 */, 19 }, + /* 7943 */ { MAD_F(0x04d6239d) /* 0.302280060 */, 19 }, + /* 7944 */ { MAD_F(0x04d658d2) /* 0.302330802 */, 19 }, + /* 7945 */ { MAD_F(0x04d68e08) /* 0.302381547 */, 19 }, + /* 7946 */ { MAD_F(0x04d6c33e) /* 0.302432294 */, 19 }, + /* 7947 */ { MAD_F(0x04d6f875) /* 0.302483043 */, 19 }, + /* 7948 */ { MAD_F(0x04d72dad) /* 0.302533794 */, 19 }, + /* 7949 */ { MAD_F(0x04d762e5) /* 0.302584547 */, 19 }, + /* 7950 */ { MAD_F(0x04d7981d) /* 0.302635303 */, 19 }, + /* 7951 */ { MAD_F(0x04d7cd56) /* 0.302686060 */, 19 }, + + /* 7952 */ { MAD_F(0x04d80290) /* 0.302736820 */, 19 }, + /* 7953 */ { MAD_F(0x04d837ca) /* 0.302787581 */, 19 }, + /* 7954 */ { MAD_F(0x04d86d05) /* 0.302838345 */, 19 }, + /* 7955 */ { MAD_F(0x04d8a240) /* 0.302889111 */, 19 }, + /* 7956 */ { MAD_F(0x04d8d77c) /* 0.302939879 */, 19 }, + /* 7957 */ { MAD_F(0x04d90cb9) /* 0.302990650 */, 19 }, + /* 7958 */ { MAD_F(0x04d941f6) /* 0.303041422 */, 19 }, + /* 7959 */ { MAD_F(0x04d97734) /* 0.303092197 */, 19 }, + /* 7960 */ { MAD_F(0x04d9ac72) /* 0.303142973 */, 19 }, + /* 7961 */ { MAD_F(0x04d9e1b1) /* 0.303193752 */, 19 }, + /* 7962 */ { MAD_F(0x04da16f0) /* 0.303244533 */, 19 }, + /* 7963 */ { MAD_F(0x04da4c30) /* 0.303295316 */, 19 }, + /* 7964 */ { MAD_F(0x04da8171) /* 0.303346101 */, 19 }, + /* 7965 */ { MAD_F(0x04dab6b2) /* 0.303396889 */, 19 }, + /* 7966 */ { MAD_F(0x04daebf4) /* 0.303447678 */, 19 }, + /* 7967 */ { MAD_F(0x04db2136) /* 0.303498469 */, 19 }, + + /* 7968 */ { MAD_F(0x04db5679) /* 0.303549263 */, 19 }, + /* 7969 */ { MAD_F(0x04db8bbc) /* 0.303600059 */, 19 }, + /* 7970 */ { MAD_F(0x04dbc100) /* 0.303650857 */, 19 }, + /* 7971 */ { MAD_F(0x04dbf644) /* 0.303701657 */, 19 }, + /* 7972 */ { MAD_F(0x04dc2b8a) /* 0.303752459 */, 19 }, + /* 7973 */ { MAD_F(0x04dc60cf) /* 0.303803263 */, 19 }, + /* 7974 */ { MAD_F(0x04dc9616) /* 0.303854070 */, 19 }, + /* 7975 */ { MAD_F(0x04dccb5c) /* 0.303904878 */, 19 }, + /* 7976 */ { MAD_F(0x04dd00a4) /* 0.303955689 */, 19 }, + /* 7977 */ { MAD_F(0x04dd35ec) /* 0.304006502 */, 19 }, + /* 7978 */ { MAD_F(0x04dd6b34) /* 0.304057317 */, 19 }, + /* 7979 */ { MAD_F(0x04dda07d) /* 0.304108134 */, 19 }, + /* 7980 */ { MAD_F(0x04ddd5c7) /* 0.304158953 */, 19 }, + /* 7981 */ { MAD_F(0x04de0b11) /* 0.304209774 */, 19 }, + /* 7982 */ { MAD_F(0x04de405c) /* 0.304260597 */, 19 }, + /* 7983 */ { MAD_F(0x04de75a7) /* 0.304311423 */, 19 }, + + /* 7984 */ { MAD_F(0x04deaaf3) /* 0.304362251 */, 19 }, + /* 7985 */ { MAD_F(0x04dee040) /* 0.304413080 */, 19 }, + /* 7986 */ { MAD_F(0x04df158d) /* 0.304463912 */, 19 }, + /* 7987 */ { MAD_F(0x04df4adb) /* 0.304514746 */, 19 }, + /* 7988 */ { MAD_F(0x04df8029) /* 0.304565582 */, 19 }, + /* 7989 */ { MAD_F(0x04dfb578) /* 0.304616421 */, 19 }, + /* 7990 */ { MAD_F(0x04dfeac7) /* 0.304667261 */, 19 }, + /* 7991 */ { MAD_F(0x04e02017) /* 0.304718103 */, 19 }, + /* 7992 */ { MAD_F(0x04e05567) /* 0.304768948 */, 19 }, + /* 7993 */ { MAD_F(0x04e08ab8) /* 0.304819795 */, 19 }, + /* 7994 */ { MAD_F(0x04e0c00a) /* 0.304870644 */, 19 }, + /* 7995 */ { MAD_F(0x04e0f55c) /* 0.304921495 */, 19 }, + /* 7996 */ { MAD_F(0x04e12aaf) /* 0.304972348 */, 19 }, + /* 7997 */ { MAD_F(0x04e16002) /* 0.305023203 */, 19 }, + /* 7998 */ { MAD_F(0x04e19556) /* 0.305074060 */, 19 }, + /* 7999 */ { MAD_F(0x04e1caab) /* 0.305124920 */, 19 }, + + /* 8000 */ { MAD_F(0x04e20000) /* 0.305175781 */, 19 }, + /* 8001 */ { MAD_F(0x04e23555) /* 0.305226645 */, 19 }, + /* 8002 */ { MAD_F(0x04e26aac) /* 0.305277511 */, 19 }, + /* 8003 */ { MAD_F(0x04e2a002) /* 0.305328379 */, 19 }, + /* 8004 */ { MAD_F(0x04e2d55a) /* 0.305379249 */, 19 }, + /* 8005 */ { MAD_F(0x04e30ab2) /* 0.305430121 */, 19 }, + /* 8006 */ { MAD_F(0x04e3400a) /* 0.305480995 */, 19 }, + /* 8007 */ { MAD_F(0x04e37563) /* 0.305531872 */, 19 }, + /* 8008 */ { MAD_F(0x04e3aabd) /* 0.305582750 */, 19 }, + /* 8009 */ { MAD_F(0x04e3e017) /* 0.305633631 */, 19 }, + /* 8010 */ { MAD_F(0x04e41572) /* 0.305684513 */, 19 }, + /* 8011 */ { MAD_F(0x04e44acd) /* 0.305735398 */, 19 }, + /* 8012 */ { MAD_F(0x04e48029) /* 0.305786285 */, 19 }, + /* 8013 */ { MAD_F(0x04e4b585) /* 0.305837174 */, 19 }, + /* 8014 */ { MAD_F(0x04e4eae2) /* 0.305888066 */, 19 }, + /* 8015 */ { MAD_F(0x04e52040) /* 0.305938959 */, 19 }, + + /* 8016 */ { MAD_F(0x04e5559e) /* 0.305989854 */, 19 }, + /* 8017 */ { MAD_F(0x04e58afd) /* 0.306040752 */, 19 }, + /* 8018 */ { MAD_F(0x04e5c05c) /* 0.306091652 */, 19 }, + /* 8019 */ { MAD_F(0x04e5f5bc) /* 0.306142554 */, 19 }, + /* 8020 */ { MAD_F(0x04e62b1c) /* 0.306193457 */, 19 }, + /* 8021 */ { MAD_F(0x04e6607d) /* 0.306244364 */, 19 }, + /* 8022 */ { MAD_F(0x04e695df) /* 0.306295272 */, 19 }, + /* 8023 */ { MAD_F(0x04e6cb41) /* 0.306346182 */, 19 }, + /* 8024 */ { MAD_F(0x04e700a3) /* 0.306397094 */, 19 }, + /* 8025 */ { MAD_F(0x04e73607) /* 0.306448009 */, 19 }, + /* 8026 */ { MAD_F(0x04e76b6b) /* 0.306498925 */, 19 }, + /* 8027 */ { MAD_F(0x04e7a0cf) /* 0.306549844 */, 19 }, + /* 8028 */ { MAD_F(0x04e7d634) /* 0.306600765 */, 19 }, + /* 8029 */ { MAD_F(0x04e80b99) /* 0.306651688 */, 19 }, + /* 8030 */ { MAD_F(0x04e84100) /* 0.306702613 */, 19 }, + /* 8031 */ { MAD_F(0x04e87666) /* 0.306753540 */, 19 }, + + /* 8032 */ { MAD_F(0x04e8abcd) /* 0.306804470 */, 19 }, + /* 8033 */ { MAD_F(0x04e8e135) /* 0.306855401 */, 19 }, + /* 8034 */ { MAD_F(0x04e9169e) /* 0.306906334 */, 19 }, + /* 8035 */ { MAD_F(0x04e94c07) /* 0.306957270 */, 19 }, + /* 8036 */ { MAD_F(0x04e98170) /* 0.307008208 */, 19 }, + /* 8037 */ { MAD_F(0x04e9b6da) /* 0.307059148 */, 19 }, + /* 8038 */ { MAD_F(0x04e9ec45) /* 0.307110090 */, 19 }, + /* 8039 */ { MAD_F(0x04ea21b0) /* 0.307161034 */, 19 }, + /* 8040 */ { MAD_F(0x04ea571c) /* 0.307211980 */, 19 }, + /* 8041 */ { MAD_F(0x04ea8c88) /* 0.307262928 */, 19 }, + /* 8042 */ { MAD_F(0x04eac1f5) /* 0.307313879 */, 19 }, + /* 8043 */ { MAD_F(0x04eaf762) /* 0.307364831 */, 19 }, + /* 8044 */ { MAD_F(0x04eb2cd0) /* 0.307415786 */, 19 }, + /* 8045 */ { MAD_F(0x04eb623f) /* 0.307466743 */, 19 }, + /* 8046 */ { MAD_F(0x04eb97ae) /* 0.307517702 */, 19 }, + /* 8047 */ { MAD_F(0x04ebcd1e) /* 0.307568663 */, 19 }, + + /* 8048 */ { MAD_F(0x04ec028e) /* 0.307619626 */, 19 }, + /* 8049 */ { MAD_F(0x04ec37ff) /* 0.307670591 */, 19 }, + /* 8050 */ { MAD_F(0x04ec6d71) /* 0.307721558 */, 19 }, + /* 8051 */ { MAD_F(0x04eca2e3) /* 0.307772528 */, 19 }, + /* 8052 */ { MAD_F(0x04ecd855) /* 0.307823499 */, 19 }, + /* 8053 */ { MAD_F(0x04ed0dc8) /* 0.307874473 */, 19 }, + /* 8054 */ { MAD_F(0x04ed433c) /* 0.307925449 */, 19 }, + /* 8055 */ { MAD_F(0x04ed78b0) /* 0.307976426 */, 19 }, + /* 8056 */ { MAD_F(0x04edae25) /* 0.308027406 */, 19 }, + /* 8057 */ { MAD_F(0x04ede39a) /* 0.308078389 */, 19 }, + /* 8058 */ { MAD_F(0x04ee1910) /* 0.308129373 */, 19 }, + /* 8059 */ { MAD_F(0x04ee4e87) /* 0.308180359 */, 19 }, + /* 8060 */ { MAD_F(0x04ee83fe) /* 0.308231347 */, 19 }, + /* 8061 */ { MAD_F(0x04eeb976) /* 0.308282338 */, 19 }, + /* 8062 */ { MAD_F(0x04eeeeee) /* 0.308333331 */, 19 }, + /* 8063 */ { MAD_F(0x04ef2467) /* 0.308384325 */, 19 }, + + /* 8064 */ { MAD_F(0x04ef59e0) /* 0.308435322 */, 19 }, + /* 8065 */ { MAD_F(0x04ef8f5a) /* 0.308486321 */, 19 }, + /* 8066 */ { MAD_F(0x04efc4d5) /* 0.308537322 */, 19 }, + /* 8067 */ { MAD_F(0x04effa50) /* 0.308588325 */, 19 }, + /* 8068 */ { MAD_F(0x04f02fcb) /* 0.308639331 */, 19 }, + /* 8069 */ { MAD_F(0x04f06547) /* 0.308690338 */, 19 }, + /* 8070 */ { MAD_F(0x04f09ac4) /* 0.308741348 */, 19 }, + /* 8071 */ { MAD_F(0x04f0d041) /* 0.308792359 */, 19 }, + /* 8072 */ { MAD_F(0x04f105bf) /* 0.308843373 */, 19 }, + /* 8073 */ { MAD_F(0x04f13b3e) /* 0.308894389 */, 19 }, + /* 8074 */ { MAD_F(0x04f170bd) /* 0.308945407 */, 19 }, + /* 8075 */ { MAD_F(0x04f1a63c) /* 0.308996427 */, 19 }, + /* 8076 */ { MAD_F(0x04f1dbbd) /* 0.309047449 */, 19 }, + /* 8077 */ { MAD_F(0x04f2113d) /* 0.309098473 */, 19 }, + /* 8078 */ { MAD_F(0x04f246bf) /* 0.309149499 */, 19 }, + /* 8079 */ { MAD_F(0x04f27c40) /* 0.309200528 */, 19 }, + + /* 8080 */ { MAD_F(0x04f2b1c3) /* 0.309251558 */, 19 }, + /* 8081 */ { MAD_F(0x04f2e746) /* 0.309302591 */, 19 }, + /* 8082 */ { MAD_F(0x04f31cc9) /* 0.309353626 */, 19 }, + /* 8083 */ { MAD_F(0x04f3524d) /* 0.309404663 */, 19 }, + /* 8084 */ { MAD_F(0x04f387d2) /* 0.309455702 */, 19 }, + /* 8085 */ { MAD_F(0x04f3bd57) /* 0.309506743 */, 19 }, + /* 8086 */ { MAD_F(0x04f3f2dd) /* 0.309557786 */, 19 }, + /* 8087 */ { MAD_F(0x04f42864) /* 0.309608831 */, 19 }, + /* 8088 */ { MAD_F(0x04f45dea) /* 0.309659879 */, 19 }, + /* 8089 */ { MAD_F(0x04f49372) /* 0.309710928 */, 19 }, + /* 8090 */ { MAD_F(0x04f4c8fa) /* 0.309761980 */, 19 }, + /* 8091 */ { MAD_F(0x04f4fe83) /* 0.309813033 */, 19 }, + /* 8092 */ { MAD_F(0x04f5340c) /* 0.309864089 */, 19 }, + /* 8093 */ { MAD_F(0x04f56996) /* 0.309915147 */, 19 }, + /* 8094 */ { MAD_F(0x04f59f20) /* 0.309966207 */, 19 }, + /* 8095 */ { MAD_F(0x04f5d4ab) /* 0.310017269 */, 19 }, + + /* 8096 */ { MAD_F(0x04f60a36) /* 0.310068333 */, 19 }, + /* 8097 */ { MAD_F(0x04f63fc2) /* 0.310119400 */, 19 }, + /* 8098 */ { MAD_F(0x04f6754f) /* 0.310170468 */, 19 }, + /* 8099 */ { MAD_F(0x04f6aadc) /* 0.310221539 */, 19 }, + /* 8100 */ { MAD_F(0x04f6e06a) /* 0.310272611 */, 19 }, + /* 8101 */ { MAD_F(0x04f715f8) /* 0.310323686 */, 19 }, + /* 8102 */ { MAD_F(0x04f74b87) /* 0.310374763 */, 19 }, + /* 8103 */ { MAD_F(0x04f78116) /* 0.310425842 */, 19 }, + /* 8104 */ { MAD_F(0x04f7b6a6) /* 0.310476923 */, 19 }, + /* 8105 */ { MAD_F(0x04f7ec37) /* 0.310528006 */, 19 }, + /* 8106 */ { MAD_F(0x04f821c8) /* 0.310579091 */, 19 }, + /* 8107 */ { MAD_F(0x04f85759) /* 0.310630179 */, 19 }, + /* 8108 */ { MAD_F(0x04f88cec) /* 0.310681268 */, 19 }, + /* 8109 */ { MAD_F(0x04f8c27e) /* 0.310732360 */, 19 }, + /* 8110 */ { MAD_F(0x04f8f812) /* 0.310783453 */, 19 }, + /* 8111 */ { MAD_F(0x04f92da6) /* 0.310834549 */, 19 }, + + /* 8112 */ { MAD_F(0x04f9633a) /* 0.310885647 */, 19 }, + /* 8113 */ { MAD_F(0x04f998cf) /* 0.310936747 */, 19 }, + /* 8114 */ { MAD_F(0x04f9ce65) /* 0.310987849 */, 19 }, + /* 8115 */ { MAD_F(0x04fa03fb) /* 0.311038953 */, 19 }, + /* 8116 */ { MAD_F(0x04fa3992) /* 0.311090059 */, 19 }, + /* 8117 */ { MAD_F(0x04fa6f29) /* 0.311141168 */, 19 }, + /* 8118 */ { MAD_F(0x04faa4c1) /* 0.311192278 */, 19 }, + /* 8119 */ { MAD_F(0x04fada59) /* 0.311243390 */, 19 }, + /* 8120 */ { MAD_F(0x04fb0ff2) /* 0.311294505 */, 19 }, + /* 8121 */ { MAD_F(0x04fb458c) /* 0.311345622 */, 19 }, + /* 8122 */ { MAD_F(0x04fb7b26) /* 0.311396741 */, 19 }, + /* 8123 */ { MAD_F(0x04fbb0c1) /* 0.311447862 */, 19 }, + /* 8124 */ { MAD_F(0x04fbe65c) /* 0.311498985 */, 19 }, + /* 8125 */ { MAD_F(0x04fc1bf8) /* 0.311550110 */, 19 }, + /* 8126 */ { MAD_F(0x04fc5194) /* 0.311601237 */, 19 }, + /* 8127 */ { MAD_F(0x04fc8731) /* 0.311652366 */, 19 }, + + /* 8128 */ { MAD_F(0x04fcbcce) /* 0.311703498 */, 19 }, + /* 8129 */ { MAD_F(0x04fcf26c) /* 0.311754631 */, 19 }, + /* 8130 */ { MAD_F(0x04fd280b) /* 0.311805767 */, 19 }, + /* 8131 */ { MAD_F(0x04fd5daa) /* 0.311856905 */, 19 }, + /* 8132 */ { MAD_F(0x04fd934a) /* 0.311908044 */, 19 }, + /* 8133 */ { MAD_F(0x04fdc8ea) /* 0.311959186 */, 19 }, + /* 8134 */ { MAD_F(0x04fdfe8b) /* 0.312010330 */, 19 }, + /* 8135 */ { MAD_F(0x04fe342c) /* 0.312061476 */, 19 }, + /* 8136 */ { MAD_F(0x04fe69ce) /* 0.312112625 */, 19 }, + /* 8137 */ { MAD_F(0x04fe9f71) /* 0.312163775 */, 19 }, + /* 8138 */ { MAD_F(0x04fed514) /* 0.312214927 */, 19 }, + /* 8139 */ { MAD_F(0x04ff0ab8) /* 0.312266082 */, 19 }, + /* 8140 */ { MAD_F(0x04ff405c) /* 0.312317238 */, 19 }, + /* 8141 */ { MAD_F(0x04ff7601) /* 0.312368397 */, 19 }, + /* 8142 */ { MAD_F(0x04ffaba6) /* 0.312419558 */, 19 }, + /* 8143 */ { MAD_F(0x04ffe14c) /* 0.312470720 */, 19 }, + + /* 8144 */ { MAD_F(0x050016f3) /* 0.312521885 */, 19 }, + /* 8145 */ { MAD_F(0x05004c9a) /* 0.312573052 */, 19 }, + /* 8146 */ { MAD_F(0x05008241) /* 0.312624222 */, 19 }, + /* 8147 */ { MAD_F(0x0500b7e9) /* 0.312675393 */, 19 }, + /* 8148 */ { MAD_F(0x0500ed92) /* 0.312726566 */, 19 }, + /* 8149 */ { MAD_F(0x0501233b) /* 0.312777742 */, 19 }, + /* 8150 */ { MAD_F(0x050158e5) /* 0.312828919 */, 19 }, + /* 8151 */ { MAD_F(0x05018e90) /* 0.312880099 */, 19 }, + /* 8152 */ { MAD_F(0x0501c43b) /* 0.312931280 */, 19 }, + /* 8153 */ { MAD_F(0x0501f9e6) /* 0.312982464 */, 19 }, + /* 8154 */ { MAD_F(0x05022f92) /* 0.313033650 */, 19 }, + /* 8155 */ { MAD_F(0x0502653f) /* 0.313084838 */, 19 }, + /* 8156 */ { MAD_F(0x05029aec) /* 0.313136028 */, 19 }, + /* 8157 */ { MAD_F(0x0502d09a) /* 0.313187220 */, 19 }, + /* 8158 */ { MAD_F(0x05030648) /* 0.313238414 */, 19 }, + /* 8159 */ { MAD_F(0x05033bf7) /* 0.313289611 */, 19 }, + + /* 8160 */ { MAD_F(0x050371a7) /* 0.313340809 */, 19 }, + /* 8161 */ { MAD_F(0x0503a757) /* 0.313392010 */, 19 }, + /* 8162 */ { MAD_F(0x0503dd07) /* 0.313443212 */, 19 }, + /* 8163 */ { MAD_F(0x050412b9) /* 0.313494417 */, 19 }, + /* 8164 */ { MAD_F(0x0504486a) /* 0.313545624 */, 19 }, + /* 8165 */ { MAD_F(0x05047e1d) /* 0.313596833 */, 19 }, + /* 8166 */ { MAD_F(0x0504b3cf) /* 0.313648044 */, 19 }, + /* 8167 */ { MAD_F(0x0504e983) /* 0.313699257 */, 19 }, + /* 8168 */ { MAD_F(0x05051f37) /* 0.313750472 */, 19 }, + /* 8169 */ { MAD_F(0x050554eb) /* 0.313801689 */, 19 }, + /* 8170 */ { MAD_F(0x05058aa0) /* 0.313852909 */, 19 }, + /* 8171 */ { MAD_F(0x0505c056) /* 0.313904130 */, 19 }, + /* 8172 */ { MAD_F(0x0505f60c) /* 0.313955354 */, 19 }, + /* 8173 */ { MAD_F(0x05062bc3) /* 0.314006579 */, 19 }, + /* 8174 */ { MAD_F(0x0506617a) /* 0.314057807 */, 19 }, + /* 8175 */ { MAD_F(0x05069732) /* 0.314109037 */, 19 }, + + /* 8176 */ { MAD_F(0x0506cceb) /* 0.314160269 */, 19 }, + /* 8177 */ { MAD_F(0x050702a4) /* 0.314211502 */, 19 }, + /* 8178 */ { MAD_F(0x0507385d) /* 0.314262739 */, 19 }, + /* 8179 */ { MAD_F(0x05076e17) /* 0.314313977 */, 19 }, + /* 8180 */ { MAD_F(0x0507a3d2) /* 0.314365217 */, 19 }, + /* 8181 */ { MAD_F(0x0507d98d) /* 0.314416459 */, 19 }, + /* 8182 */ { MAD_F(0x05080f49) /* 0.314467704 */, 19 }, + /* 8183 */ { MAD_F(0x05084506) /* 0.314518950 */, 19 }, + /* 8184 */ { MAD_F(0x05087ac2) /* 0.314570199 */, 19 }, + /* 8185 */ { MAD_F(0x0508b080) /* 0.314621449 */, 19 }, + /* 8186 */ { MAD_F(0x0508e63e) /* 0.314672702 */, 19 }, + /* 8187 */ { MAD_F(0x05091bfd) /* 0.314723957 */, 19 }, + /* 8188 */ { MAD_F(0x050951bc) /* 0.314775214 */, 19 }, + /* 8189 */ { MAD_F(0x0509877c) /* 0.314826473 */, 19 }, + /* 8190 */ { MAD_F(0x0509bd3c) /* 0.314877734 */, 19 }, + /* 8191 */ { MAD_F(0x0509f2fd) /* 0.314928997 */, 19 }, + + /* 8192 */ { MAD_F(0x050a28be) /* 0.314980262 */, 19 }, + /* 8193 */ { MAD_F(0x050a5e80) /* 0.315031530 */, 19 }, + /* 8194 */ { MAD_F(0x050a9443) /* 0.315082799 */, 19 }, + /* 8195 */ { MAD_F(0x050aca06) /* 0.315134071 */, 19 }, + /* 8196 */ { MAD_F(0x050affc9) /* 0.315185344 */, 19 }, + /* 8197 */ { MAD_F(0x050b358e) /* 0.315236620 */, 19 }, + /* 8198 */ { MAD_F(0x050b6b52) /* 0.315287898 */, 19 }, + /* 8199 */ { MAD_F(0x050ba118) /* 0.315339178 */, 19 }, + /* 8200 */ { MAD_F(0x050bd6de) /* 0.315390460 */, 19 }, + /* 8201 */ { MAD_F(0x050c0ca4) /* 0.315441744 */, 19 }, + /* 8202 */ { MAD_F(0x050c426b) /* 0.315493030 */, 19 }, + /* 8203 */ { MAD_F(0x050c7833) /* 0.315544318 */, 19 }, + /* 8204 */ { MAD_F(0x050cadfb) /* 0.315595608 */, 19 }, + /* 8205 */ { MAD_F(0x050ce3c4) /* 0.315646901 */, 19 }, + /* 8206 */ { MAD_F(0x050d198d) /* 0.315698195 */, 19 } diff --git a/code/libmad/sf_table.dat b/code/libmad/sf_table.dat new file mode 100644 index 00000000..db1484a0 --- /dev/null +++ b/code/libmad/sf_table.dat @@ -0,0 +1,106 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: sf_table.dat,v 1.7 2004/01/23 09:41:33 rob Exp $ + */ + +/* + * These are the scalefactor values for Layer I and Layer II. + * The values are from Table B.1 of ISO/IEC 11172-3. + * + * There is some error introduced by the 32-bit fixed-point representation; + * the amount of error is shown. For 16-bit PCM output, this shouldn't be + * too much of a problem. + * + * Strictly speaking, Table B.1 has only 63 entries (0-62), thus a strict + * interpretation of ISO/IEC 11172-3 would suggest that a scalefactor index of + * 63 is invalid. However, for better compatibility with current practices, we + * add a 64th entry. + */ + + MAD_F(0x20000000), /* 2.000000000000 => 2.000000000000, e 0.000000000000 */ + MAD_F(0x1965fea5), /* 1.587401051968 => 1.587401051074, e 0.000000000894 */ + MAD_F(0x1428a2fa), /* 1.259921049895 => 1.259921051562, e -0.000000001667 */ + MAD_F(0x10000000), /* 1.000000000000 => 1.000000000000, e 0.000000000000 */ + MAD_F(0x0cb2ff53), /* 0.793700525984 => 0.793700527400, e -0.000000001416 */ + MAD_F(0x0a14517d), /* 0.629960524947 => 0.629960525781, e -0.000000000833 */ + MAD_F(0x08000000), /* 0.500000000000 => 0.500000000000, e 0.000000000000 */ + MAD_F(0x06597fa9), /* 0.396850262992 => 0.396850261837, e 0.000000001155 */ + + MAD_F(0x050a28be), /* 0.314980262474 => 0.314980261028, e 0.000000001446 */ + MAD_F(0x04000000), /* 0.250000000000 => 0.250000000000, e 0.000000000000 */ + MAD_F(0x032cbfd5), /* 0.198425131496 => 0.198425132781, e -0.000000001285 */ + MAD_F(0x0285145f), /* 0.157490131237 => 0.157490130514, e 0.000000000723 */ + MAD_F(0x02000000), /* 0.125000000000 => 0.125000000000, e 0.000000000000 */ + MAD_F(0x01965fea), /* 0.099212565748 => 0.099212564528, e 0.000000001220 */ + MAD_F(0x01428a30), /* 0.078745065618 => 0.078745067120, e -0.000000001501 */ + MAD_F(0x01000000), /* 0.062500000000 => 0.062500000000, e 0.000000000000 */ + + MAD_F(0x00cb2ff5), /* 0.049606282874 => 0.049606282264, e 0.000000000610 */ + MAD_F(0x00a14518), /* 0.039372532809 => 0.039372533560, e -0.000000000751 */ + MAD_F(0x00800000), /* 0.031250000000 => 0.031250000000, e 0.000000000000 */ + MAD_F(0x006597fb), /* 0.024803141437 => 0.024803142995, e -0.000000001558 */ + MAD_F(0x0050a28c), /* 0.019686266405 => 0.019686266780, e -0.000000000375 */ + MAD_F(0x00400000), /* 0.015625000000 => 0.015625000000, e 0.000000000000 */ + MAD_F(0x0032cbfd), /* 0.012401570719 => 0.012401569635, e 0.000000001084 */ + MAD_F(0x00285146), /* 0.009843133202 => 0.009843133390, e -0.000000000188 */ + + MAD_F(0x00200000), /* 0.007812500000 => 0.007812500000, e 0.000000000000 */ + MAD_F(0x001965ff), /* 0.006200785359 => 0.006200786680, e -0.000000001321 */ + MAD_F(0x001428a3), /* 0.004921566601 => 0.004921566695, e -0.000000000094 */ + MAD_F(0x00100000), /* 0.003906250000 => 0.003906250000, e 0.000000000000 */ + MAD_F(0x000cb2ff), /* 0.003100392680 => 0.003100391477, e 0.000000001202 */ + MAD_F(0x000a1451), /* 0.002460783301 => 0.002460781485, e 0.000000001816 */ + MAD_F(0x00080000), /* 0.001953125000 => 0.001953125000, e 0.000000000000 */ + MAD_F(0x00065980), /* 0.001550196340 => 0.001550197601, e -0.000000001262 */ + + MAD_F(0x00050a29), /* 0.001230391650 => 0.001230392605, e -0.000000000955 */ + MAD_F(0x00040000), /* 0.000976562500 => 0.000976562500, e 0.000000000000 */ + MAD_F(0x00032cc0), /* 0.000775098170 => 0.000775098801, e -0.000000000631 */ + MAD_F(0x00028514), /* 0.000615195825 => 0.000615194440, e 0.000000001385 */ + MAD_F(0x00020000), /* 0.000488281250 => 0.000488281250, e 0.000000000000 */ + MAD_F(0x00019660), /* 0.000387549085 => 0.000387549400, e -0.000000000315 */ + MAD_F(0x0001428a), /* 0.000307597913 => 0.000307597220, e 0.000000000693 */ + MAD_F(0x00010000), /* 0.000244140625 => 0.000244140625, e 0.000000000000 */ + + MAD_F(0x0000cb30), /* 0.000193774542 => 0.000193774700, e -0.000000000158 */ + MAD_F(0x0000a145), /* 0.000153798956 => 0.000153798610, e 0.000000000346 */ + MAD_F(0x00008000), /* 0.000122070313 => 0.000122070313, e 0.000000000000 */ + MAD_F(0x00006598), /* 0.000096887271 => 0.000096887350, e -0.000000000079 */ + MAD_F(0x000050a3), /* 0.000076899478 => 0.000076901168, e -0.000000001689 */ + MAD_F(0x00004000), /* 0.000061035156 => 0.000061035156, e 0.000000000000 */ + MAD_F(0x000032cc), /* 0.000048443636 => 0.000048443675, e -0.000000000039 */ + MAD_F(0x00002851), /* 0.000038449739 => 0.000038448721, e 0.000000001018 */ + + MAD_F(0x00002000), /* 0.000030517578 => 0.000030517578, e 0.000000000000 */ + MAD_F(0x00001966), /* 0.000024221818 => 0.000024221838, e -0.000000000020 */ + MAD_F(0x00001429), /* 0.000019224870 => 0.000019226223, e -0.000000001354 */ + MAD_F(0x00001000), /* 0.000015258789 => 0.000015258789, e -0.000000000000 */ + MAD_F(0x00000cb3), /* 0.000012110909 => 0.000012110919, e -0.000000000010 */ + MAD_F(0x00000a14), /* 0.000009612435 => 0.000009611249, e 0.000000001186 */ + MAD_F(0x00000800), /* 0.000007629395 => 0.000007629395, e -0.000000000000 */ + MAD_F(0x00000659), /* 0.000006055454 => 0.000006053597, e 0.000000001858 */ + + MAD_F(0x0000050a), /* 0.000004806217 => 0.000004805624, e 0.000000000593 */ + MAD_F(0x00000400), /* 0.000003814697 => 0.000003814697, e 0.000000000000 */ + MAD_F(0x0000032d), /* 0.000003027727 => 0.000003028661, e -0.000000000934 */ + MAD_F(0x00000285), /* 0.000002403109 => 0.000002402812, e 0.000000000296 */ + MAD_F(0x00000200), /* 0.000001907349 => 0.000001907349, e -0.000000000000 */ + MAD_F(0x00000196), /* 0.000001513864 => 0.000001512468, e 0.000000001396 */ + MAD_F(0x00000143), /* 0.000001201554 => 0.000001203269, e -0.000000001714 */ + MAD_F(0x00000000) /* this compatibility entry is not part of Table B.1 */ diff --git a/code/libmad/stream.c b/code/libmad/stream.c new file mode 100644 index 00000000..18ce95ae --- /dev/null +++ b/code/libmad/stream.c @@ -0,0 +1,156 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: stream.c,v 1.12 2004/02/05 09:02:39 rob Exp $ + */ + +# include "global.h" + +# include + +# include "mad.h" + +/* + * NAME: stream->init() + * DESCRIPTION: initialize stream struct + */ +void mad_stream_init(struct mad_stream *stream) +{ + stream->buffer = 0; + stream->bufend = 0; + stream->skiplen = 0; + + stream->sync = 0; + stream->freerate = 0; + + stream->this_frame = 0; + stream->next_frame = 0; + mad_bit_init(&stream->ptr, 0); + + mad_bit_init(&stream->anc_ptr, 0); + stream->anc_bitlen = 0; + + stream->main_data = 0; + stream->md_len = 0; + + stream->options = 0; + stream->error = MAD_ERROR_NONE; +} + +/* + * NAME: stream->finish() + * DESCRIPTION: deallocate any dynamic memory associated with stream + */ +void mad_stream_finish(struct mad_stream *stream) +{ + if (stream->main_data) { + free(stream->main_data); + stream->main_data = 0; + } + + mad_bit_finish(&stream->anc_ptr); + mad_bit_finish(&stream->ptr); +} + +/* + * NAME: stream->buffer() + * DESCRIPTION: set stream buffer pointers + */ +void mad_stream_buffer(struct mad_stream *stream, + unsigned char const *buffer, unsigned long length) +{ + stream->buffer = buffer; + stream->bufend = buffer + length; + + stream->this_frame = buffer; + stream->next_frame = buffer; + + stream->sync = 1; + + mad_bit_init(&stream->ptr, buffer); +} + +/* + * NAME: stream->skip() + * DESCRIPTION: arrange to skip bytes before the next frame + */ +void mad_stream_skip(struct mad_stream *stream, unsigned long length) +{ + stream->skiplen += length; +} + +/* + * NAME: stream->sync() + * DESCRIPTION: locate the next stream sync word + */ +int mad_stream_sync(struct mad_stream *stream) +{ + register unsigned char const *ptr, *end; + + ptr = mad_bit_nextbyte(&stream->ptr); + end = stream->bufend; + + while (ptr < end - 1 && + !(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) + ++ptr; + + if (end - ptr < MAD_BUFFER_GUARD) + return -1; + + mad_bit_init(&stream->ptr, ptr); + + return 0; +} + +/* + * NAME: stream->errorstr() + * DESCRIPTION: return a string description of the current error condition + */ +char const *mad_stream_errorstr(struct mad_stream const *stream) +{ + switch (stream->error) { + case MAD_ERROR_NONE: return "no error"; + + case MAD_ERROR_BUFLEN: return "input buffer too small (or EOF)"; + case MAD_ERROR_BUFPTR: return "invalid (null) buffer pointer"; + + case MAD_ERROR_NOMEM: return "not enough memory"; + + case MAD_ERROR_LOSTSYNC: return "lost synchronization"; + case MAD_ERROR_BADLAYER: return "reserved header layer value"; + case MAD_ERROR_BADBITRATE: return "forbidden bitrate value"; + case MAD_ERROR_BADSAMPLERATE: return "reserved sample frequency value"; + case MAD_ERROR_BADEMPHASIS: return "reserved emphasis value"; + + case MAD_ERROR_BADCRC: return "CRC check failed"; + case MAD_ERROR_BADBITALLOC: return "forbidden bit allocation value"; + case MAD_ERROR_BADSCALEFACTOR: return "bad scalefactor index"; + case MAD_ERROR_BADMODE: return "bad bitrate/mode combination"; + case MAD_ERROR_BADFRAMELEN: return "bad frame length"; + case MAD_ERROR_BADBIGVALUES: return "bad big_values count"; + case MAD_ERROR_BADBLOCKTYPE: return "reserved block_type"; + case MAD_ERROR_BADSCFSI: return "bad scalefactor selection info"; + case MAD_ERROR_BADDATAPTR: return "bad main_data_begin pointer"; + case MAD_ERROR_BADPART3LEN: return "bad audio data length"; + case MAD_ERROR_BADHUFFTABLE: return "bad Huffman table select"; + case MAD_ERROR_BADHUFFDATA: return "Huffman data overrun"; + case MAD_ERROR_BADSTEREO: return "incompatible block_type for JS"; + } + + return 0; +} diff --git a/code/libmad/synth.c b/code/libmad/synth.c new file mode 100644 index 00000000..110c9b28 --- /dev/null +++ b/code/libmad/synth.c @@ -0,0 +1,851 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: synth.c,v 1.25 2004/01/23 09:41:33 rob Exp $ + */ + +# include "global.h" + +# include "mad.h" + +/* + * NAME: synth->init() + * DESCRIPTION: initialize synth struct + */ +void mad_synth_init(struct mad_synth *synth) +{ + mad_synth_mute(synth); + + synth->phase = 0; + + synth->pcm.samplerate = 0; + synth->pcm.channels = 0; + synth->pcm.length = 0; +} + +/* + * NAME: synth->mute() + * DESCRIPTION: zero all polyphase filterbank values, resetting synthesis + */ +void mad_synth_mute(struct mad_synth *synth) +{ + unsigned int ch, s, v; + + for (ch = 0; ch < 2; ++ch) { + for (s = 0; s < 16; ++s) { + for (v = 0; v < 8; ++v) { + synth->filter[ch][0][0][s][v] = synth->filter[ch][0][1][s][v] = + synth->filter[ch][1][0][s][v] = synth->filter[ch][1][1][s][v] = 0; + } + } + } +} + +/* + * An optional optimization called here the Subband Synthesis Optimization + * (SSO) improves the performance of subband synthesis at the expense of + * accuracy. + * + * The idea is to simplify 32x32->64-bit multiplication to 32x32->32 such + * that extra scaling and rounding are not necessary. This often allows the + * compiler to use faster 32-bit multiply-accumulate instructions instead of + * explicit 64-bit multiply, shift, and add instructions. + * + * SSO works like this: a full 32x32->64-bit multiply of two mad_fixed_t + * values requires the result to be right-shifted 28 bits to be properly + * scaled to the same fixed-point format. Right shifts can be applied at any + * time to either operand or to the result, so the optimization involves + * careful placement of these shifts to minimize the loss of accuracy. + * + * First, a 14-bit shift is applied with rounding at compile-time to the D[] + * table of coefficients for the subband synthesis window. This only loses 2 + * bits of accuracy because the lower 12 bits are always zero. A second + * 12-bit shift occurs after the DCT calculation. This loses 12 bits of + * accuracy. Finally, a third 2-bit shift occurs just before the sample is + * saved in the PCM buffer. 14 + 12 + 2 == 28 bits. + */ + +/* FPM_DEFAULT without OPT_SSO will actually lose accuracy and performance */ + +# if defined(FPM_DEFAULT) && !defined(OPT_SSO) +# define OPT_SSO +# endif + +/* second SSO shift, with rounding */ + +# if defined(OPT_SSO) +# define SHIFT(x) (((x) + (1L << 11)) >> 12) +# else +# define SHIFT(x) (x) +# endif + +/* possible DCT speed optimization */ + +# if defined(OPT_SPEED) && defined(MAD_F_MLX) +# define OPT_DCTO +# define MUL(x, y) \ + ({ mad_fixed64hi_t hi; \ + mad_fixed64lo_t lo; \ + MAD_F_MLX(hi, lo, (x), (y)); \ + hi << (32 - MAD_F_SCALEBITS - 3); \ + }) +# else +# undef OPT_DCTO +# define MUL(x, y) mad_f_mul((x), (y)) +# endif + +/* + * NAME: dct32() + * DESCRIPTION: perform fast in[32]->out[32] DCT + */ +static +void dct32(mad_fixed_t const in[32], unsigned int slot, + mad_fixed_t lo[16][8], mad_fixed_t hi[16][8]) +{ + mad_fixed_t t0, t1, t2, t3, t4, t5, t6, t7; + mad_fixed_t t8, t9, t10, t11, t12, t13, t14, t15; + mad_fixed_t t16, t17, t18, t19, t20, t21, t22, t23; + mad_fixed_t t24, t25, t26, t27, t28, t29, t30, t31; + mad_fixed_t t32, t33, t34, t35, t36, t37, t38, t39; + mad_fixed_t t40, t41, t42, t43, t44, t45, t46, t47; + mad_fixed_t t48, t49, t50, t51, t52, t53, t54, t55; + mad_fixed_t t56, t57, t58, t59, t60, t61, t62, t63; + mad_fixed_t t64, t65, t66, t67, t68, t69, t70, t71; + mad_fixed_t t72, t73, t74, t75, t76, t77, t78, t79; + mad_fixed_t t80, t81, t82, t83, t84, t85, t86, t87; + mad_fixed_t t88, t89, t90, t91, t92, t93, t94, t95; + mad_fixed_t t96, t97, t98, t99, t100, t101, t102, t103; + mad_fixed_t t104, t105, t106, t107, t108, t109, t110, t111; + mad_fixed_t t112, t113, t114, t115, t116, t117, t118, t119; + mad_fixed_t t120, t121, t122, t123, t124, t125, t126, t127; + mad_fixed_t t128, t129, t130, t131, t132, t133, t134, t135; + mad_fixed_t t136, t137, t138, t139, t140, t141, t142, t143; + mad_fixed_t t144, t145, t146, t147, t148, t149, t150, t151; + mad_fixed_t t152, t153, t154, t155, t156, t157, t158, t159; + mad_fixed_t t160, t161, t162, t163, t164, t165, t166, t167; + mad_fixed_t t168, t169, t170, t171, t172, t173, t174, t175; + mad_fixed_t t176; + + /* costab[i] = cos(PI / (2 * 32) * i) */ + +# if defined(OPT_DCTO) +# define costab1 MAD_F(0x7fd8878e) +# define costab2 MAD_F(0x7f62368f) +# define costab3 MAD_F(0x7e9d55fc) +# define costab4 MAD_F(0x7d8a5f40) +# define costab5 MAD_F(0x7c29fbee) +# define costab6 MAD_F(0x7a7d055b) +# define costab7 MAD_F(0x78848414) +# define costab8 MAD_F(0x7641af3d) +# define costab9 MAD_F(0x73b5ebd1) +# define costab10 MAD_F(0x70e2cbc6) +# define costab11 MAD_F(0x6dca0d14) +# define costab12 MAD_F(0x6a6d98a4) +# define costab13 MAD_F(0x66cf8120) +# define costab14 MAD_F(0x62f201ac) +# define costab15 MAD_F(0x5ed77c8a) +# define costab16 MAD_F(0x5a82799a) +# define costab17 MAD_F(0x55f5a4d2) +# define costab18 MAD_F(0x5133cc94) +# define costab19 MAD_F(0x4c3fdff4) +# define costab20 MAD_F(0x471cece7) +# define costab21 MAD_F(0x41ce1e65) +# define costab22 MAD_F(0x3c56ba70) +# define costab23 MAD_F(0x36ba2014) +# define costab24 MAD_F(0x30fbc54d) +# define costab25 MAD_F(0x2b1f34eb) +# define costab26 MAD_F(0x25280c5e) +# define costab27 MAD_F(0x1f19f97b) +# define costab28 MAD_F(0x18f8b83c) +# define costab29 MAD_F(0x12c8106f) +# define costab30 MAD_F(0x0c8bd35e) +# define costab31 MAD_F(0x0647d97c) +# else +# define costab1 MAD_F(0x0ffb10f2) /* 0.998795456 */ +# define costab2 MAD_F(0x0fec46d2) /* 0.995184727 */ +# define costab3 MAD_F(0x0fd3aac0) /* 0.989176510 */ +# define costab4 MAD_F(0x0fb14be8) /* 0.980785280 */ +# define costab5 MAD_F(0x0f853f7e) /* 0.970031253 */ +# define costab6 MAD_F(0x0f4fa0ab) /* 0.956940336 */ +# define costab7 MAD_F(0x0f109082) /* 0.941544065 */ +# define costab8 MAD_F(0x0ec835e8) /* 0.923879533 */ +# define costab9 MAD_F(0x0e76bd7a) /* 0.903989293 */ +# define costab10 MAD_F(0x0e1c5979) /* 0.881921264 */ +# define costab11 MAD_F(0x0db941a3) /* 0.857728610 */ +# define costab12 MAD_F(0x0d4db315) /* 0.831469612 */ +# define costab13 MAD_F(0x0cd9f024) /* 0.803207531 */ +# define costab14 MAD_F(0x0c5e4036) /* 0.773010453 */ +# define costab15 MAD_F(0x0bdaef91) /* 0.740951125 */ +# define costab16 MAD_F(0x0b504f33) /* 0.707106781 */ +# define costab17 MAD_F(0x0abeb49a) /* 0.671558955 */ +# define costab18 MAD_F(0x0a267993) /* 0.634393284 */ +# define costab19 MAD_F(0x0987fbfe) /* 0.595699304 */ +# define costab20 MAD_F(0x08e39d9d) /* 0.555570233 */ +# define costab21 MAD_F(0x0839c3cd) /* 0.514102744 */ +# define costab22 MAD_F(0x078ad74e) /* 0.471396737 */ +# define costab23 MAD_F(0x06d74402) /* 0.427555093 */ +# define costab24 MAD_F(0x061f78aa) /* 0.382683432 */ +# define costab25 MAD_F(0x0563e69d) /* 0.336889853 */ +# define costab26 MAD_F(0x04a5018c) /* 0.290284677 */ +# define costab27 MAD_F(0x03e33f2f) /* 0.242980180 */ +# define costab28 MAD_F(0x031f1708) /* 0.195090322 */ +# define costab29 MAD_F(0x0259020e) /* 0.146730474 */ +# define costab30 MAD_F(0x01917a6c) /* 0.098017140 */ +# define costab31 MAD_F(0x00c8fb30) /* 0.049067674 */ +# endif + + t0 = in[0] + in[31]; t16 = MUL(in[0] - in[31], costab1); + t1 = in[15] + in[16]; t17 = MUL(in[15] - in[16], costab31); + + t41 = t16 + t17; + t59 = MUL(t16 - t17, costab2); + t33 = t0 + t1; + t50 = MUL(t0 - t1, costab2); + + t2 = in[7] + in[24]; t18 = MUL(in[7] - in[24], costab15); + t3 = in[8] + in[23]; t19 = MUL(in[8] - in[23], costab17); + + t42 = t18 + t19; + t60 = MUL(t18 - t19, costab30); + t34 = t2 + t3; + t51 = MUL(t2 - t3, costab30); + + t4 = in[3] + in[28]; t20 = MUL(in[3] - in[28], costab7); + t5 = in[12] + in[19]; t21 = MUL(in[12] - in[19], costab25); + + t43 = t20 + t21; + t61 = MUL(t20 - t21, costab14); + t35 = t4 + t5; + t52 = MUL(t4 - t5, costab14); + + t6 = in[4] + in[27]; t22 = MUL(in[4] - in[27], costab9); + t7 = in[11] + in[20]; t23 = MUL(in[11] - in[20], costab23); + + t44 = t22 + t23; + t62 = MUL(t22 - t23, costab18); + t36 = t6 + t7; + t53 = MUL(t6 - t7, costab18); + + t8 = in[1] + in[30]; t24 = MUL(in[1] - in[30], costab3); + t9 = in[14] + in[17]; t25 = MUL(in[14] - in[17], costab29); + + t45 = t24 + t25; + t63 = MUL(t24 - t25, costab6); + t37 = t8 + t9; + t54 = MUL(t8 - t9, costab6); + + t10 = in[6] + in[25]; t26 = MUL(in[6] - in[25], costab13); + t11 = in[9] + in[22]; t27 = MUL(in[9] - in[22], costab19); + + t46 = t26 + t27; + t64 = MUL(t26 - t27, costab26); + t38 = t10 + t11; + t55 = MUL(t10 - t11, costab26); + + t12 = in[2] + in[29]; t28 = MUL(in[2] - in[29], costab5); + t13 = in[13] + in[18]; t29 = MUL(in[13] - in[18], costab27); + + t47 = t28 + t29; + t65 = MUL(t28 - t29, costab10); + t39 = t12 + t13; + t56 = MUL(t12 - t13, costab10); + + t14 = in[5] + in[26]; t30 = MUL(in[5] - in[26], costab11); + t15 = in[10] + in[21]; t31 = MUL(in[10] - in[21], costab21); + + t48 = t30 + t31; + t66 = MUL(t30 - t31, costab22); + t40 = t14 + t15; + t57 = MUL(t14 - t15, costab22); + + t69 = t33 + t34; t89 = MUL(t33 - t34, costab4); + t70 = t35 + t36; t90 = MUL(t35 - t36, costab28); + t71 = t37 + t38; t91 = MUL(t37 - t38, costab12); + t72 = t39 + t40; t92 = MUL(t39 - t40, costab20); + t73 = t41 + t42; t94 = MUL(t41 - t42, costab4); + t74 = t43 + t44; t95 = MUL(t43 - t44, costab28); + t75 = t45 + t46; t96 = MUL(t45 - t46, costab12); + t76 = t47 + t48; t97 = MUL(t47 - t48, costab20); + + t78 = t50 + t51; t100 = MUL(t50 - t51, costab4); + t79 = t52 + t53; t101 = MUL(t52 - t53, costab28); + t80 = t54 + t55; t102 = MUL(t54 - t55, costab12); + t81 = t56 + t57; t103 = MUL(t56 - t57, costab20); + + t83 = t59 + t60; t106 = MUL(t59 - t60, costab4); + t84 = t61 + t62; t107 = MUL(t61 - t62, costab28); + t85 = t63 + t64; t108 = MUL(t63 - t64, costab12); + t86 = t65 + t66; t109 = MUL(t65 - t66, costab20); + + t113 = t69 + t70; + t114 = t71 + t72; + + /* 0 */ hi[15][slot] = SHIFT(t113 + t114); + /* 16 */ lo[ 0][slot] = SHIFT(MUL(t113 - t114, costab16)); + + t115 = t73 + t74; + t116 = t75 + t76; + + t32 = t115 + t116; + + /* 1 */ hi[14][slot] = SHIFT(t32); + + t118 = t78 + t79; + t119 = t80 + t81; + + t58 = t118 + t119; + + /* 2 */ hi[13][slot] = SHIFT(t58); + + t121 = t83 + t84; + t122 = t85 + t86; + + t67 = t121 + t122; + + t49 = (t67 * 2) - t32; + + /* 3 */ hi[12][slot] = SHIFT(t49); + + t125 = t89 + t90; + t126 = t91 + t92; + + t93 = t125 + t126; + + /* 4 */ hi[11][slot] = SHIFT(t93); + + t128 = t94 + t95; + t129 = t96 + t97; + + t98 = t128 + t129; + + t68 = (t98 * 2) - t49; + + /* 5 */ hi[10][slot] = SHIFT(t68); + + t132 = t100 + t101; + t133 = t102 + t103; + + t104 = t132 + t133; + + t82 = (t104 * 2) - t58; + + /* 6 */ hi[ 9][slot] = SHIFT(t82); + + t136 = t106 + t107; + t137 = t108 + t109; + + t110 = t136 + t137; + + t87 = (t110 * 2) - t67; + + t77 = (t87 * 2) - t68; + + /* 7 */ hi[ 8][slot] = SHIFT(t77); + + t141 = MUL(t69 - t70, costab8); + t142 = MUL(t71 - t72, costab24); + t143 = t141 + t142; + + /* 8 */ hi[ 7][slot] = SHIFT(t143); + /* 24 */ lo[ 8][slot] = + SHIFT((MUL(t141 - t142, costab16) * 2) - t143); + + t144 = MUL(t73 - t74, costab8); + t145 = MUL(t75 - t76, costab24); + t146 = t144 + t145; + + t88 = (t146 * 2) - t77; + + /* 9 */ hi[ 6][slot] = SHIFT(t88); + + t148 = MUL(t78 - t79, costab8); + t149 = MUL(t80 - t81, costab24); + t150 = t148 + t149; + + t105 = (t150 * 2) - t82; + + /* 10 */ hi[ 5][slot] = SHIFT(t105); + + t152 = MUL(t83 - t84, costab8); + t153 = MUL(t85 - t86, costab24); + t154 = t152 + t153; + + t111 = (t154 * 2) - t87; + + t99 = (t111 * 2) - t88; + + /* 11 */ hi[ 4][slot] = SHIFT(t99); + + t157 = MUL(t89 - t90, costab8); + t158 = MUL(t91 - t92, costab24); + t159 = t157 + t158; + + t127 = (t159 * 2) - t93; + + /* 12 */ hi[ 3][slot] = SHIFT(t127); + + t160 = (MUL(t125 - t126, costab16) * 2) - t127; + + /* 20 */ lo[ 4][slot] = SHIFT(t160); + /* 28 */ lo[12][slot] = + SHIFT((((MUL(t157 - t158, costab16) * 2) - t159) * 2) - t160); + + t161 = MUL(t94 - t95, costab8); + t162 = MUL(t96 - t97, costab24); + t163 = t161 + t162; + + t130 = (t163 * 2) - t98; + + t112 = (t130 * 2) - t99; + + /* 13 */ hi[ 2][slot] = SHIFT(t112); + + t164 = (MUL(t128 - t129, costab16) * 2) - t130; + + t166 = MUL(t100 - t101, costab8); + t167 = MUL(t102 - t103, costab24); + t168 = t166 + t167; + + t134 = (t168 * 2) - t104; + + t120 = (t134 * 2) - t105; + + /* 14 */ hi[ 1][slot] = SHIFT(t120); + + t135 = (MUL(t118 - t119, costab16) * 2) - t120; + + /* 18 */ lo[ 2][slot] = SHIFT(t135); + + t169 = (MUL(t132 - t133, costab16) * 2) - t134; + + t151 = (t169 * 2) - t135; + + /* 22 */ lo[ 6][slot] = SHIFT(t151); + + t170 = (((MUL(t148 - t149, costab16) * 2) - t150) * 2) - t151; + + /* 26 */ lo[10][slot] = SHIFT(t170); + /* 30 */ lo[14][slot] = + SHIFT((((((MUL(t166 - t167, costab16) * 2) - + t168) * 2) - t169) * 2) - t170); + + t171 = MUL(t106 - t107, costab8); + t172 = MUL(t108 - t109, costab24); + t173 = t171 + t172; + + t138 = (t173 * 2) - t110; + + t123 = (t138 * 2) - t111; + + t139 = (MUL(t121 - t122, costab16) * 2) - t123; + + t117 = (t123 * 2) - t112; + + /* 15 */ hi[ 0][slot] = SHIFT(t117); + + t124 = (MUL(t115 - t116, costab16) * 2) - t117; + + /* 17 */ lo[ 1][slot] = SHIFT(t124); + + t131 = (t139 * 2) - t124; + + /* 19 */ lo[ 3][slot] = SHIFT(t131); + + t140 = (t164 * 2) - t131; + + /* 21 */ lo[ 5][slot] = SHIFT(t140); + + t174 = (MUL(t136 - t137, costab16) * 2) - t138; + + t155 = (t174 * 2) - t139; + + t147 = (t155 * 2) - t140; + + /* 23 */ lo[ 7][slot] = SHIFT(t147); + + t156 = (((MUL(t144 - t145, costab16) * 2) - t146) * 2) - t147; + + /* 25 */ lo[ 9][slot] = SHIFT(t156); + + t175 = (((MUL(t152 - t153, costab16) * 2) - t154) * 2) - t155; + + t165 = (t175 * 2) - t156; + + /* 27 */ lo[11][slot] = SHIFT(t165); + + t176 = (((((MUL(t161 - t162, costab16) * 2) - + t163) * 2) - t164) * 2) - t165; + + /* 29 */ lo[13][slot] = SHIFT(t176); + /* 31 */ lo[15][slot] = + SHIFT((((((((MUL(t171 - t172, costab16) * 2) - + t173) * 2) - t174) * 2) - t175) * 2) - t176); + + /* + * Totals: + * 80 multiplies + * 80 additions + * 119 subtractions + * 49 shifts (not counting SSO) + */ +} + +# undef MUL +# undef SHIFT + +/* third SSO shift and/or D[] optimization preshift */ + +# if defined(OPT_SSO) +# if MAD_F_FRACBITS != 28 +# error "MAD_F_FRACBITS must be 28 to use OPT_SSO" +# endif +# define ML0(hi, lo, x, y) ((lo) = (x) * (y)) +# define MLA(hi, lo, x, y) ((lo) += (x) * (y)) +# define MLN(hi, lo) ((lo) = -(lo)) +# define MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo)) +# define SHIFT(x) ((x) >> 2) +# define PRESHIFT(x) ((MAD_F(x) + (1L << 13)) >> 14) +# else +# define ML0(hi, lo, x, y) MAD_F_ML0((hi), (lo), (x), (y)) +# define MLA(hi, lo, x, y) MAD_F_MLA((hi), (lo), (x), (y)) +# define MLN(hi, lo) MAD_F_MLN((hi), (lo)) +# define MLZ(hi, lo) MAD_F_MLZ((hi), (lo)) +# define SHIFT(x) (x) +# if defined(MAD_F_SCALEBITS) +# undef MAD_F_SCALEBITS +# define MAD_F_SCALEBITS (MAD_F_FRACBITS - 12) +# define PRESHIFT(x) (MAD_F(x) >> 12) +# else +# define PRESHIFT(x) MAD_F(x) +# endif +# endif + +static +mad_fixed_t const D[17][32] = { +# include "D.dat" +}; + +# if defined(ASO_SYNTH) +void synth_full(struct mad_synth *, struct mad_frame const *, + unsigned int, unsigned int); +# else +/* + * NAME: synth->full() + * DESCRIPTION: perform full frequency PCM synthesis + */ +static +void synth_full(struct mad_synth *synth, struct mad_frame const *frame, + unsigned int nch, unsigned int ns) +{ + unsigned int phase, ch, s, sb, pe, po; + mad_fixed_t *pcm1, *pcm2, (*filter)[2][2][16][8]; + mad_fixed_t const (*sbsample)[36][32]; + register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8]; + register mad_fixed_t const (*Dptr)[32], *ptr; + register mad_fixed64hi_t hi; + register mad_fixed64lo_t lo; + + for (ch = 0; ch < nch; ++ch) { + sbsample = &frame->sbsample[ch]; + filter = &synth->filter[ch]; + phase = synth->phase; + pcm1 = synth->pcm.samples[ch]; + + for (s = 0; s < ns; ++s) { + dct32((*sbsample)[s], phase >> 1, + (*filter)[0][phase & 1], (*filter)[1][phase & 1]); + + pe = phase & ~1; + po = ((phase - 1) & 0xf) | 1; + + /* calculate 32 samples */ + + fe = &(*filter)[0][ phase & 1][0]; + fx = &(*filter)[0][~phase & 1][0]; + fo = &(*filter)[1][~phase & 1][0]; + + Dptr = &D[0]; + + ptr = *Dptr + po; + ML0(hi, lo, (*fx)[0], ptr[ 0]); + MLA(hi, lo, (*fx)[1], ptr[14]); + MLA(hi, lo, (*fx)[2], ptr[12]); + MLA(hi, lo, (*fx)[3], ptr[10]); + MLA(hi, lo, (*fx)[4], ptr[ 8]); + MLA(hi, lo, (*fx)[5], ptr[ 6]); + MLA(hi, lo, (*fx)[6], ptr[ 4]); + MLA(hi, lo, (*fx)[7], ptr[ 2]); + MLN(hi, lo); + + ptr = *Dptr + pe; + MLA(hi, lo, (*fe)[0], ptr[ 0]); + MLA(hi, lo, (*fe)[1], ptr[14]); + MLA(hi, lo, (*fe)[2], ptr[12]); + MLA(hi, lo, (*fe)[3], ptr[10]); + MLA(hi, lo, (*fe)[4], ptr[ 8]); + MLA(hi, lo, (*fe)[5], ptr[ 6]); + MLA(hi, lo, (*fe)[6], ptr[ 4]); + MLA(hi, lo, (*fe)[7], ptr[ 2]); + + *pcm1++ = SHIFT(MLZ(hi, lo)); + + pcm2 = pcm1 + 30; + + for (sb = 1; sb < 16; ++sb) { + ++fe; + ++Dptr; + + /* D[32 - sb][i] == -D[sb][31 - i] */ + + ptr = *Dptr + po; + ML0(hi, lo, (*fo)[0], ptr[ 0]); + MLA(hi, lo, (*fo)[1], ptr[14]); + MLA(hi, lo, (*fo)[2], ptr[12]); + MLA(hi, lo, (*fo)[3], ptr[10]); + MLA(hi, lo, (*fo)[4], ptr[ 8]); + MLA(hi, lo, (*fo)[5], ptr[ 6]); + MLA(hi, lo, (*fo)[6], ptr[ 4]); + MLA(hi, lo, (*fo)[7], ptr[ 2]); + MLN(hi, lo); + + ptr = *Dptr + pe; + MLA(hi, lo, (*fe)[7], ptr[ 2]); + MLA(hi, lo, (*fe)[6], ptr[ 4]); + MLA(hi, lo, (*fe)[5], ptr[ 6]); + MLA(hi, lo, (*fe)[4], ptr[ 8]); + MLA(hi, lo, (*fe)[3], ptr[10]); + MLA(hi, lo, (*fe)[2], ptr[12]); + MLA(hi, lo, (*fe)[1], ptr[14]); + MLA(hi, lo, (*fe)[0], ptr[ 0]); + + *pcm1++ = SHIFT(MLZ(hi, lo)); + + ptr = *Dptr - pe; + ML0(hi, lo, (*fe)[0], ptr[31 - 16]); + MLA(hi, lo, (*fe)[1], ptr[31 - 14]); + MLA(hi, lo, (*fe)[2], ptr[31 - 12]); + MLA(hi, lo, (*fe)[3], ptr[31 - 10]); + MLA(hi, lo, (*fe)[4], ptr[31 - 8]); + MLA(hi, lo, (*fe)[5], ptr[31 - 6]); + MLA(hi, lo, (*fe)[6], ptr[31 - 4]); + MLA(hi, lo, (*fe)[7], ptr[31 - 2]); + + ptr = *Dptr - po; + MLA(hi, lo, (*fo)[7], ptr[31 - 2]); + MLA(hi, lo, (*fo)[6], ptr[31 - 4]); + MLA(hi, lo, (*fo)[5], ptr[31 - 6]); + MLA(hi, lo, (*fo)[4], ptr[31 - 8]); + MLA(hi, lo, (*fo)[3], ptr[31 - 10]); + MLA(hi, lo, (*fo)[2], ptr[31 - 12]); + MLA(hi, lo, (*fo)[1], ptr[31 - 14]); + MLA(hi, lo, (*fo)[0], ptr[31 - 16]); + + *pcm2-- = SHIFT(MLZ(hi, lo)); + + ++fo; + } + + ++Dptr; + + ptr = *Dptr + po; + ML0(hi, lo, (*fo)[0], ptr[ 0]); + MLA(hi, lo, (*fo)[1], ptr[14]); + MLA(hi, lo, (*fo)[2], ptr[12]); + MLA(hi, lo, (*fo)[3], ptr[10]); + MLA(hi, lo, (*fo)[4], ptr[ 8]); + MLA(hi, lo, (*fo)[5], ptr[ 6]); + MLA(hi, lo, (*fo)[6], ptr[ 4]); + MLA(hi, lo, (*fo)[7], ptr[ 2]); + + *pcm1 = SHIFT(-MLZ(hi, lo)); + pcm1 += 16; + + phase = (phase + 1) % 16; + } + } +} +# endif + +/* + * NAME: synth->half() + * DESCRIPTION: perform half frequency PCM synthesis + */ +static +void synth_half(struct mad_synth *synth, struct mad_frame const *frame, + unsigned int nch, unsigned int ns) +{ + unsigned int phase, ch, s, sb, pe, po; + mad_fixed_t *pcm1, *pcm2, (*filter)[2][2][16][8]; + mad_fixed_t const (*sbsample)[36][32]; + register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8]; + register mad_fixed_t const (*Dptr)[32], *ptr; + register mad_fixed64hi_t hi; + register mad_fixed64lo_t lo; + + for (ch = 0; ch < nch; ++ch) { + sbsample = &frame->sbsample[ch]; + filter = &synth->filter[ch]; + phase = synth->phase; + pcm1 = synth->pcm.samples[ch]; + + for (s = 0; s < ns; ++s) { + dct32((*sbsample)[s], phase >> 1, + (*filter)[0][phase & 1], (*filter)[1][phase & 1]); + + pe = phase & ~1; + po = ((phase - 1) & 0xf) | 1; + + /* calculate 16 samples */ + + fe = &(*filter)[0][ phase & 1][0]; + fx = &(*filter)[0][~phase & 1][0]; + fo = &(*filter)[1][~phase & 1][0]; + + Dptr = &D[0]; + + ptr = *Dptr + po; + ML0(hi, lo, (*fx)[0], ptr[ 0]); + MLA(hi, lo, (*fx)[1], ptr[14]); + MLA(hi, lo, (*fx)[2], ptr[12]); + MLA(hi, lo, (*fx)[3], ptr[10]); + MLA(hi, lo, (*fx)[4], ptr[ 8]); + MLA(hi, lo, (*fx)[5], ptr[ 6]); + MLA(hi, lo, (*fx)[6], ptr[ 4]); + MLA(hi, lo, (*fx)[7], ptr[ 2]); + MLN(hi, lo); + + ptr = *Dptr + pe; + MLA(hi, lo, (*fe)[0], ptr[ 0]); + MLA(hi, lo, (*fe)[1], ptr[14]); + MLA(hi, lo, (*fe)[2], ptr[12]); + MLA(hi, lo, (*fe)[3], ptr[10]); + MLA(hi, lo, (*fe)[4], ptr[ 8]); + MLA(hi, lo, (*fe)[5], ptr[ 6]); + MLA(hi, lo, (*fe)[6], ptr[ 4]); + MLA(hi, lo, (*fe)[7], ptr[ 2]); + + *pcm1++ = SHIFT(MLZ(hi, lo)); + + pcm2 = pcm1 + 14; + + for (sb = 1; sb < 16; ++sb) { + ++fe; + ++Dptr; + + /* D[32 - sb][i] == -D[sb][31 - i] */ + + if (!(sb & 1)) { + ptr = *Dptr + po; + ML0(hi, lo, (*fo)[0], ptr[ 0]); + MLA(hi, lo, (*fo)[1], ptr[14]); + MLA(hi, lo, (*fo)[2], ptr[12]); + MLA(hi, lo, (*fo)[3], ptr[10]); + MLA(hi, lo, (*fo)[4], ptr[ 8]); + MLA(hi, lo, (*fo)[5], ptr[ 6]); + MLA(hi, lo, (*fo)[6], ptr[ 4]); + MLA(hi, lo, (*fo)[7], ptr[ 2]); + MLN(hi, lo); + + ptr = *Dptr + pe; + MLA(hi, lo, (*fe)[7], ptr[ 2]); + MLA(hi, lo, (*fe)[6], ptr[ 4]); + MLA(hi, lo, (*fe)[5], ptr[ 6]); + MLA(hi, lo, (*fe)[4], ptr[ 8]); + MLA(hi, lo, (*fe)[3], ptr[10]); + MLA(hi, lo, (*fe)[2], ptr[12]); + MLA(hi, lo, (*fe)[1], ptr[14]); + MLA(hi, lo, (*fe)[0], ptr[ 0]); + + *pcm1++ = SHIFT(MLZ(hi, lo)); + + ptr = *Dptr - po; + ML0(hi, lo, (*fo)[7], ptr[31 - 2]); + MLA(hi, lo, (*fo)[6], ptr[31 - 4]); + MLA(hi, lo, (*fo)[5], ptr[31 - 6]); + MLA(hi, lo, (*fo)[4], ptr[31 - 8]); + MLA(hi, lo, (*fo)[3], ptr[31 - 10]); + MLA(hi, lo, (*fo)[2], ptr[31 - 12]); + MLA(hi, lo, (*fo)[1], ptr[31 - 14]); + MLA(hi, lo, (*fo)[0], ptr[31 - 16]); + + ptr = *Dptr - pe; + MLA(hi, lo, (*fe)[0], ptr[31 - 16]); + MLA(hi, lo, (*fe)[1], ptr[31 - 14]); + MLA(hi, lo, (*fe)[2], ptr[31 - 12]); + MLA(hi, lo, (*fe)[3], ptr[31 - 10]); + MLA(hi, lo, (*fe)[4], ptr[31 - 8]); + MLA(hi, lo, (*fe)[5], ptr[31 - 6]); + MLA(hi, lo, (*fe)[6], ptr[31 - 4]); + MLA(hi, lo, (*fe)[7], ptr[31 - 2]); + + *pcm2-- = SHIFT(MLZ(hi, lo)); + } + + ++fo; + } + + ++Dptr; + + ptr = *Dptr + po; + ML0(hi, lo, (*fo)[0], ptr[ 0]); + MLA(hi, lo, (*fo)[1], ptr[14]); + MLA(hi, lo, (*fo)[2], ptr[12]); + MLA(hi, lo, (*fo)[3], ptr[10]); + MLA(hi, lo, (*fo)[4], ptr[ 8]); + MLA(hi, lo, (*fo)[5], ptr[ 6]); + MLA(hi, lo, (*fo)[6], ptr[ 4]); + MLA(hi, lo, (*fo)[7], ptr[ 2]); + + *pcm1 = SHIFT(-MLZ(hi, lo)); + pcm1 += 8; + + phase = (phase + 1) % 16; + } + } +} + +/* + * NAME: synth->frame() + * DESCRIPTION: perform PCM synthesis of frame subband samples + */ +void mad_synth_frame(struct mad_synth *synth, struct mad_frame const *frame) +{ + unsigned int nch, ns; + void (*synth_frame)(struct mad_synth *, struct mad_frame const *, + unsigned int, unsigned int); + + nch = MAD_NCHANNELS(&frame->header); + ns = MAD_NSBSAMPLES(&frame->header); + + synth->pcm.samplerate = frame->header.samplerate; + synth->pcm.channels = nch; + synth->pcm.length = 32 * ns; + + synth_frame = synth_full; + + if (frame->options & MAD_OPTION_HALFSAMPLERATE) { + synth->pcm.samplerate /= 2; + synth->pcm.length /= 2; + + synth_frame = synth_half; + } + + synth_frame(synth, frame, nch, ns); + + synth->phase = (synth->phase + ns) % 16; +} diff --git a/code/libmad/timer.c b/code/libmad/timer.c new file mode 100644 index 00000000..df11316c --- /dev/null +++ b/code/libmad/timer.c @@ -0,0 +1,481 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: timer.c,v 1.18 2004/01/23 09:41:33 rob Exp $ + */ + +# include "global.h" + +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "mad.h" + +mad_timer_t const mad_timer_zero = { 0, 0 }; + +/* + * NAME: timer->compare() + * DESCRIPTION: indicate relative order of two timers + */ +int mad_timer_compare(mad_timer_t timer1, mad_timer_t timer2) +{ + signed long diff; + + diff = timer1.seconds - timer2.seconds; + if (diff < 0) + return -1; + else if (diff > 0) + return +1; + + diff = timer1.fraction - timer2.fraction; + if (diff < 0) + return -1; + else if (diff > 0) + return +1; + + return 0; +} + +/* + * NAME: timer->negate() + * DESCRIPTION: invert the sign of a timer + */ +void mad_timer_negate(mad_timer_t *timer) +{ + timer->seconds = -timer->seconds; + + if (timer->fraction) { + timer->seconds -= 1; + timer->fraction = MAD_TIMER_RESOLUTION - timer->fraction; + } +} + +/* + * NAME: timer->abs() + * DESCRIPTION: return the absolute value of a timer + */ +mad_timer_t mad_timer_abs(mad_timer_t timer) +{ + if (timer.seconds < 0) + mad_timer_negate(&timer); + + return timer; +} + +/* + * NAME: reduce_timer() + * DESCRIPTION: carry timer fraction into seconds + */ +static +void reduce_timer(mad_timer_t *timer) +{ + timer->seconds += timer->fraction / MAD_TIMER_RESOLUTION; + timer->fraction %= MAD_TIMER_RESOLUTION; +} + +/* + * NAME: gcd() + * DESCRIPTION: compute greatest common denominator + */ +static +unsigned long gcd(unsigned long num1, unsigned long num2) +{ + unsigned long tmp; + + while (num2) { + tmp = num2; + num2 = num1 % num2; + num1 = tmp; + } + + return num1; +} + +/* + * NAME: reduce_rational() + * DESCRIPTION: convert rational expression to lowest terms + */ +static +void reduce_rational(unsigned long *numer, unsigned long *denom) +{ + unsigned long factor; + + factor = gcd(*numer, *denom); + + assert(factor != 0); + + *numer /= factor; + *denom /= factor; +} + +/* + * NAME: scale_rational() + * DESCRIPTION: solve numer/denom == ?/scale avoiding overflowing + */ +static +unsigned long scale_rational(unsigned long numer, unsigned long denom, + unsigned long scale) +{ + reduce_rational(&numer, &denom); + reduce_rational(&scale, &denom); + + assert(denom != 0); + + if (denom < scale) + return numer * (scale / denom) + numer * (scale % denom) / denom; + if (denom < numer) + return scale * (numer / denom) + scale * (numer % denom) / denom; + + return numer * scale / denom; +} + +/* + * NAME: timer->set() + * DESCRIPTION: set timer to specific (positive) value + */ +void mad_timer_set(mad_timer_t *timer, unsigned long seconds, + unsigned long numer, unsigned long denom) +{ + timer->seconds = seconds; + if (numer >= denom && denom > 0) { + timer->seconds += numer / denom; + numer %= denom; + } + + switch (denom) { + case 0: + case 1: + timer->fraction = 0; + break; + + case MAD_TIMER_RESOLUTION: + timer->fraction = numer; + break; + + case 1000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 1000); + break; + + case 8000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 8000); + break; + + case 11025: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 11025); + break; + + case 12000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 12000); + break; + + case 16000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 16000); + break; + + case 22050: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 22050); + break; + + case 24000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 24000); + break; + + case 32000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 32000); + break; + + case 44100: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 44100); + break; + + case 48000: + timer->fraction = numer * (MAD_TIMER_RESOLUTION / 48000); + break; + + default: + timer->fraction = scale_rational(numer, denom, MAD_TIMER_RESOLUTION); + break; + } + + if (timer->fraction >= MAD_TIMER_RESOLUTION) + reduce_timer(timer); +} + +/* + * NAME: timer->add() + * DESCRIPTION: add one timer to another + */ +void mad_timer_add(mad_timer_t *timer, mad_timer_t incr) +{ + timer->seconds += incr.seconds; + timer->fraction += incr.fraction; + + if (timer->fraction >= MAD_TIMER_RESOLUTION) + reduce_timer(timer); +} + +/* + * NAME: timer->multiply() + * DESCRIPTION: multiply a timer by a scalar value + */ +void mad_timer_multiply(mad_timer_t *timer, signed long scalar) +{ + mad_timer_t addend; + unsigned long factor; + + factor = scalar; + if (scalar < 0) { + factor = -scalar; + mad_timer_negate(timer); + } + + addend = *timer; + *timer = mad_timer_zero; + + while (factor) { + if (factor & 1) + mad_timer_add(timer, addend); + + mad_timer_add(&addend, addend); + factor >>= 1; + } +} + +/* + * NAME: timer->count() + * DESCRIPTION: return timer value in selected units + */ +signed long mad_timer_count(mad_timer_t timer, enum mad_units units) +{ + switch (units) { + case MAD_UNITS_HOURS: + return timer.seconds / 60 / 60; + + case MAD_UNITS_MINUTES: + return timer.seconds / 60; + + case MAD_UNITS_SECONDS: + return timer.seconds; + + case MAD_UNITS_DECISECONDS: + case MAD_UNITS_CENTISECONDS: + case MAD_UNITS_MILLISECONDS: + + case MAD_UNITS_8000_HZ: + case MAD_UNITS_11025_HZ: + case MAD_UNITS_12000_HZ: + case MAD_UNITS_16000_HZ: + case MAD_UNITS_22050_HZ: + case MAD_UNITS_24000_HZ: + case MAD_UNITS_32000_HZ: + case MAD_UNITS_44100_HZ: + case MAD_UNITS_48000_HZ: + + case MAD_UNITS_24_FPS: + case MAD_UNITS_25_FPS: + case MAD_UNITS_30_FPS: + case MAD_UNITS_48_FPS: + case MAD_UNITS_50_FPS: + case MAD_UNITS_60_FPS: + case MAD_UNITS_75_FPS: + return timer.seconds * (signed long) units + + (signed long) scale_rational(timer.fraction, MAD_TIMER_RESOLUTION, + units); + + case MAD_UNITS_23_976_FPS: + case MAD_UNITS_24_975_FPS: + case MAD_UNITS_29_97_FPS: + case MAD_UNITS_47_952_FPS: + case MAD_UNITS_49_95_FPS: + case MAD_UNITS_59_94_FPS: + return (mad_timer_count(timer, -units) + 1) * 1000 / 1001; + } + + /* unsupported units */ + return 0; +} + +/* + * NAME: timer->fraction() + * DESCRIPTION: return fractional part of timer in arbitrary terms + */ +unsigned long mad_timer_fraction(mad_timer_t timer, unsigned long denom) +{ + timer = mad_timer_abs(timer); + + switch (denom) { + case 0: + return timer.fraction ? + MAD_TIMER_RESOLUTION / timer.fraction : MAD_TIMER_RESOLUTION + 1; + + case MAD_TIMER_RESOLUTION: + return timer.fraction; + + default: + return scale_rational(timer.fraction, MAD_TIMER_RESOLUTION, denom); + } +} + +/* + * NAME: timer->string() + * DESCRIPTION: write a string representation of a timer using a template + */ +void mad_timer_string(mad_timer_t timer, + char *dest, char const *format, enum mad_units units, + enum mad_units fracunits, unsigned long subparts) +{ + unsigned long hours, minutes, seconds, sub; + unsigned int frac; + + timer = mad_timer_abs(timer); + + seconds = timer.seconds; + frac = sub = 0; + + switch (fracunits) { + case MAD_UNITS_HOURS: + case MAD_UNITS_MINUTES: + case MAD_UNITS_SECONDS: + break; + + case MAD_UNITS_DECISECONDS: + case MAD_UNITS_CENTISECONDS: + case MAD_UNITS_MILLISECONDS: + + case MAD_UNITS_8000_HZ: + case MAD_UNITS_11025_HZ: + case MAD_UNITS_12000_HZ: + case MAD_UNITS_16000_HZ: + case MAD_UNITS_22050_HZ: + case MAD_UNITS_24000_HZ: + case MAD_UNITS_32000_HZ: + case MAD_UNITS_44100_HZ: + case MAD_UNITS_48000_HZ: + + case MAD_UNITS_24_FPS: + case MAD_UNITS_25_FPS: + case MAD_UNITS_30_FPS: + case MAD_UNITS_48_FPS: + case MAD_UNITS_50_FPS: + case MAD_UNITS_60_FPS: + case MAD_UNITS_75_FPS: + { + unsigned long denom; + + denom = MAD_TIMER_RESOLUTION / fracunits; + + frac = timer.fraction / denom; + sub = scale_rational(timer.fraction % denom, denom, subparts); + } + break; + + case MAD_UNITS_23_976_FPS: + case MAD_UNITS_24_975_FPS: + case MAD_UNITS_29_97_FPS: + case MAD_UNITS_47_952_FPS: + case MAD_UNITS_49_95_FPS: + case MAD_UNITS_59_94_FPS: + /* drop-frame encoding */ + /* N.B. this is only well-defined for MAD_UNITS_29_97_FPS */ + { + unsigned long frame, cycle, d, m; + + frame = mad_timer_count(timer, fracunits); + + cycle = -fracunits * 60 * 10 - (10 - 1) * 2; + + d = frame / cycle; + m = frame % cycle; + frame += (10 - 1) * 2 * d; + if (m > 2) + frame += 2 * ((m - 2) / (cycle / 10)); + + frac = frame % -fracunits; + seconds = frame / -fracunits; + } + break; + } + + switch (units) { + case MAD_UNITS_HOURS: + minutes = seconds / 60; + hours = minutes / 60; + + sprintf(dest, format, + hours, + (unsigned int) (minutes % 60), + (unsigned int) (seconds % 60), + frac, sub); + break; + + case MAD_UNITS_MINUTES: + minutes = seconds / 60; + + sprintf(dest, format, + minutes, + (unsigned int) (seconds % 60), + frac, sub); + break; + + case MAD_UNITS_SECONDS: + sprintf(dest, format, + seconds, + frac, sub); + break; + + case MAD_UNITS_23_976_FPS: + case MAD_UNITS_24_975_FPS: + case MAD_UNITS_29_97_FPS: + case MAD_UNITS_47_952_FPS: + case MAD_UNITS_49_95_FPS: + case MAD_UNITS_59_94_FPS: + if (fracunits < 0) { + /* not yet implemented */ + sub = 0; + } + + /* fall through */ + + case MAD_UNITS_DECISECONDS: + case MAD_UNITS_CENTISECONDS: + case MAD_UNITS_MILLISECONDS: + + case MAD_UNITS_8000_HZ: + case MAD_UNITS_11025_HZ: + case MAD_UNITS_12000_HZ: + case MAD_UNITS_16000_HZ: + case MAD_UNITS_22050_HZ: + case MAD_UNITS_24000_HZ: + case MAD_UNITS_32000_HZ: + case MAD_UNITS_44100_HZ: + case MAD_UNITS_48000_HZ: + + case MAD_UNITS_24_FPS: + case MAD_UNITS_25_FPS: + case MAD_UNITS_30_FPS: + case MAD_UNITS_48_FPS: + case MAD_UNITS_50_FPS: + case MAD_UNITS_60_FPS: + case MAD_UNITS_75_FPS: + sprintf(dest, format, mad_timer_count(timer, units), sub); + break; + } +} diff --git a/code/libmad/version.c b/code/libmad/version.c new file mode 100644 index 00000000..f3747567 --- /dev/null +++ b/code/libmad/version.c @@ -0,0 +1,87 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: version.c,v 1.15 2004/01/23 09:41:33 rob Exp $ + */ + +# include "global.h" + +# include "mad.h" + +char const mad_version[] = "MPEG Audio Decoder " MAD_VERSION; +char const mad_copyright[] = "Copyright (C) " MAD_PUBLISHYEAR " " MAD_AUTHOR; +char const mad_author[] = MAD_AUTHOR " <" MAD_EMAIL ">"; + +char const mad_build[] = "" +# if defined(DEBUG) + "DEBUG " +# elif defined(NDEBUG) + "NDEBUG " +# endif + +# if defined(EXPERIMENTAL) + "EXPERIMENTAL " +# endif + +# if defined(FPM_64BIT) + "FPM_64BIT " +# elif defined(FPM_INTEL) + "FPM_INTEL " +# elif defined(FPM_ARM) + "FPM_ARM " +# elif defined(FPM_MIPS) + "FPM_MIPS " +# elif defined(FPM_SPARC) + "FPM_SPARC " +# elif defined(FPM_PPC) + "FPM_PPC " +# elif defined(FPM_DEFAULT) + "FPM_DEFAULT " +# endif + +# if defined(ASO_IMDCT) + "ASO_IMDCT " +# endif +# if defined(ASO_INTERLEAVE1) + "ASO_INTERLEAVE1 " +# endif +# if defined(ASO_INTERLEAVE2) + "ASO_INTERLEAVE2 " +# endif +# if defined(ASO_ZEROCHECK) + "ASO_ZEROCHECK " +# endif + +# if defined(OPT_SPEED) + "OPT_SPEED " +# elif defined(OPT_ACCURACY) + "OPT_ACCURACY " +# endif + +# if defined(OPT_SSO) + "OPT_SSO " +# endif + +# if defined(OPT_DCTO) /* never defined here */ + "OPT_DCTO " +# endif + +# if defined(OPT_STRICT) + "OPT_STRICT " +# endif +; From 81b86d61da22da1e4dcb7b694a70f3e657f3bcf0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:34:39 +0200 Subject: [PATCH 0541/2040] Fix read-only cvar being improperly archived This caused cvars like `paused` being wrongly restored. If the `paused` value is 1 or above, like when saving from the menu, the game would get stuck loading the level because it's paused, no frame could be executed. It also fixes cvars like `sv_fps`, `g_playermodel` not being archived when they should. Fixes #326 --- code/fgame/g_main.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index 6e971646..b472b990 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -1264,14 +1264,14 @@ qboolean G_ArchiveLevel(const char *filename, qboolean autosave, qboolean loadin num = 0; for (cvar = gi.NextCvar(NULL); cvar != NULL; cvar = gi.NextCvar(cvar)) { - if (cvar->flags & CVAR_ROM) { + if (cvar->flags & CVAR_SAVEGAME) { num++; } } arc.ArchiveInteger(&num); for (cvar = gi.NextCvar(NULL); cvar != NULL; cvar = gi.NextCvar(cvar)) { - if (cvar->flags & CVAR_ROM) { + if (cvar->flags & CVAR_SAVEGAME) { s = cvar->name; arc.ArchiveString(&s); @@ -1390,15 +1390,6 @@ qboolean G_ArchiveLevel(const char *filename, qboolean autosave, qboolean loadin PathSearch::ArchiveDynamic(arc); - if (arc.Loading()) { - arc.Close(); - LoadingSavegame = false; - gi.Printf(HUD_MESSAGE_YELLOW "%s\n", gi.LV_ConvertString("Game Loaded")); - } else { - arc.Close(); - gi.Printf(HUD_MESSAGE_YELLOW "%s\n", gi.LV_ConvertString("Game Saved")); - } - if (arc.Loading()) { // Make sure all code that needs to setup the player after they have been loaded is run @@ -1412,6 +1403,15 @@ qboolean G_ArchiveLevel(const char *filename, qboolean autosave, qboolean loadin } } + if (arc.Loading()) { + arc.Close(); + LoadingSavegame = false; + gi.Printf(HUD_MESSAGE_YELLOW "%s\n", gi.LV_ConvertString("Game Loaded")); + } else { + arc.Close(); + gi.Printf(HUD_MESSAGE_YELLOW "%s\n", gi.LV_ConvertString("Game Saved")); + } + return qtrue; } From 93cd47065976a50063d2a2bf897e2c7a30cdc610 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:43:37 +0200 Subject: [PATCH 0542/2040] Fix broken cgame state saving --- code/cgame/cg_archive.cpp | 4 ++-- code/cgame/memarchiver.cpp | 18 +++++++++--------- code/client/cl_cgame.cpp | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/code/cgame/cg_archive.cpp b/code/cgame/cg_archive.cpp index 29fa32c7..3d944fb9 100644 --- a/code/cgame/cg_archive.cpp +++ b/code/cgame/cg_archive.cpp @@ -163,7 +163,7 @@ void CG_ArchiveRefEntity(MemArchiver& archiver, refEntity_t* ref) archiver.ArchiveVec3(ref->axis[2]); archiver.ArchiveBoolean(&ref->nonNormalizedAxes); archiver.ArchiveVec3(ref->origin); - archiver.ArchiveRaw(ref->frameInfo, 192); + archiver.ArchiveRaw(ref->frameInfo, sizeof(ref->frameInfo)); archiver.ArchiveFloat(&ref->actionWeight); archiver.ArchiveShort(&ref->wasframe); archiver.ArchiveFloat(&ref->scale); @@ -171,7 +171,7 @@ void CG_ArchiveRefEntity(MemArchiver& archiver, refEntity_t* ref) archiver.ArchiveInteger(&ref->skinNum); CG_ArchiveShaderHandle(archiver, &ref->customShader); - archiver.ArchiveRaw(ref->shaderRGBA, 4); + archiver.ArchiveRaw(ref->shaderRGBA, sizeof(ref->shaderRGBA)); archiver.ArchiveFloat(ref->shaderTexCoord); archiver.ArchiveFloat(&ref->shaderTexCoord[1]); archiver.ArchiveFloat(&ref->shaderTime); diff --git a/code/cgame/memarchiver.cpp b/code/cgame/memarchiver.cpp index f934fe65..a07c4211 100644 --- a/code/cgame/memarchiver.cpp +++ b/code/cgame/memarchiver.cpp @@ -42,23 +42,23 @@ MemArchiver::~MemArchiver() void MemArchiver::SetupForWriting(size_t initialSize) { - state = MEMARC_WRITING; - buffer = (byte*)cgi.Malloc(initialSize); - allocatedSize = initialSize; - bufferSize = 0; + this->state = MEMARC_WRITING; + this->buffer = (byte*)cgi.Malloc(initialSize); + this->allocatedSize = initialSize; + this->bufferSize = 0; } void MemArchiver::SetupForReading(byte* buffer, size_t size) { - state = MEMARC_READING; - buffer = buffer; - allocatedSize = size; - bufferSize = 0; + this->state = MEMARC_READING; + this->buffer = buffer; + this->allocatedSize = size; + this->bufferSize = 0; } void MemArchiver::SetBaseTime(unsigned int time) { - svsTime = time; + this->svsTime = time; } size_t MemArchiver::BufferSize() const diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index da55bb05..13ee3756 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -582,7 +582,7 @@ CL_RestoreSavedCgameState */ void CL_RestoreSavedCgameState() { if (cls.savedCgameState) { - cge->CG_LoadStateToBuffer(&cls.savedCgameState, cls.savedCgameStateSize, cl.snap.serverTime); + cge->CG_LoadStateToBuffer(cls.savedCgameState, cls.savedCgameStateSize, cl.snap.serverTime); } } From 422bf647a713ab11a40daf024947d876cd96443f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:45:32 +0200 Subject: [PATCH 0543/2040] Save the client-game state into the archive file (feature from moh spearhead 2.0) This saves cgame data such as emitters and vss sources --- code/fgame/g_main.cpp | 20 +++++++++++++++----- code/fgame/g_public.h | 4 ++-- code/server/sv_ccmds.c | 15 ++++++++++++--- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index b472b990..46c1119b 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -1215,7 +1215,7 @@ G_ArchiveLevel ================= */ -qboolean G_ArchiveLevel(const char *filename, qboolean autosave, qboolean loading) +qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, int *savedCgameStateSize, qboolean autosave, qboolean loading) { try { int i; @@ -1259,6 +1259,16 @@ qboolean G_ArchiveLevel(const char *filename, qboolean autosave, qboolean loadin L_ArchiveEvents(arc); } + arc.ArchiveInteger(savedCgameStateSize); + if (!arc.Saving()) { + if (*savedCgameStateSize) { + *savedCgameState = (byte*)gi.Malloc(*savedCgameStateSize); + } else { + *savedCgameState = NULL; + } + } + arc.ArchiveRaw(*savedCgameState, *savedCgameStateSize); + if (arc.Saving()) { str s; @@ -1427,10 +1437,10 @@ G_WriteLevel ================= */ -void G_WriteLevel(const char *filename, qboolean autosave) +void G_WriteLevel(const char *filename, qboolean autosave, byte** savedCgameState, int* savedCgameStateSize) { game.autosaved = autosave; - G_ArchiveLevel(filename, autosave, qfalse); + G_ArchiveLevel(filename, savedCgameState, savedCgameStateSize, autosave, qfalse); game.autosaved = false; } @@ -1449,11 +1459,11 @@ calling ReadLevel. No clients are connected yet. ================= */ -qboolean G_ReadLevel(const char *filename) +qboolean G_ReadLevel(const char *filename, byte** savedCgameState, int* savedCgameStateSize) { qboolean status; - status = G_ArchiveLevel(filename, qfalse, qtrue); + status = G_ArchiveLevel(filename, savedCgameState, savedCgameStateSize, qfalse, qtrue); // if the level load failed make sure that these variables are not set if (!status) { LoadingSavegame = false; diff --git a/code/fgame/g_public.h b/code/fgame/g_public.h index bf8dc73b..b790b4bf 100644 --- a/code/fgame/g_public.h +++ b/code/fgame/g_public.h @@ -520,8 +520,8 @@ typedef struct gameExport_s { // ReadLevel is called after the default map information has been // loaded with SpawnEntities, so any stored client spawn spots will // be used when the clients reconnect. - void (*WriteLevel)(const char *filename, qboolean autosave); - qboolean (*ReadLevel)(const char *filename); + void (*WriteLevel)(const char *filename, qboolean autosave, byte** savedCgameState, int* savedCgameStateSize); + qboolean (*ReadLevel)(const char *filename, byte** savedCgameState, int* savedCgameStateSize); qboolean (*LevelArchiveValid)(const char *filename); void (*ArchiveInteger)(int *i); diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 1e601533..2bd89bac 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1878,7 +1878,7 @@ qboolean SV_ArchiveLevelFile(qboolean loading, qboolean autosave) name = Com_GetArchiveFileName(svs.gameName, "sav"); if (loading) { - if (!ge->ReadLevel(name)) { + if (!ge->ReadLevel(name, &cls.savedCgameState, &cls.savedCgameStateSize)) { return qfalse; } @@ -1901,7 +1901,7 @@ qboolean SV_ArchiveLevelFile(qboolean loading, qboolean autosave) else { cls.savedCgameStateSize = cge->CG_SaveStateToBuffer(&cls.savedCgameState, svs.time); - ge->WriteLevel(name, autosave); + ge->WriteLevel(name, autosave, &cls.savedCgameState, &cls.savedCgameStateSize); Z_Free(cls.savedCgameState); cls.savedCgameState = NULL; } @@ -2271,9 +2271,18 @@ void SV_SaveGame( const char *gamename, qboolean autosave ) } strcpy( svs.gameName, name ); - SV_ArchiveLevelFile( qfalse, autosave ); + + if (!SV_ArchiveLevelFile(qfalse, autosave)) { + if (cls.savedCgameState) { + Z_Free(cls.savedCgameState); + cls.savedCgameState = 0; + } + } + SV_ArchiveServerFile( qfalse, autosave ); + Com_Printf( "Done.\n" ); + strcpy( svs.gameName, "current" ); #endif } From 535da856a4a963c5d94c37e66956fa512817210b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:42:48 +0200 Subject: [PATCH 0544/2040] When returning a cvar value, use the latched string if present --- code/uilib/ui_init.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/code/uilib/ui_init.cpp b/code/uilib/ui_init.cpp index 3bf89cd5..02f4d1f9 100644 --- a/code/uilib/ui_init.cpp +++ b/code/uilib/ui_init.cpp @@ -61,11 +61,14 @@ int UI_GetCvarInt( const char *name, int def ) { cvar_t *cvar = uii.Cvar_Find( name ); - if( !cvar ) - { + if( !cvar ) { return def; } + if (cvar->latchedString) { + return atoi(cvar->latchedString); + } + return cvar->integer; } @@ -73,11 +76,14 @@ float UI_GetCvarFloat( const char *name, float def ) { cvar_t *cvar = uii.Cvar_Find( name ); - if( !cvar ) - { + if( !cvar ) { return def; } + if (cvar->latchedString) { + return atof(cvar->latchedString); + } + return cvar->value; } From eee0eaac4a674ff9932a8ddda4f5af917a6b5351 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:55:11 +0200 Subject: [PATCH 0545/2040] Process the "!" (not) syntax for `enabledcvar` This fixes #265 where the mine detector icon wouldn't appear because it wants SP mode --- code/uilib/uiwidget.cpp | 142 ++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 65 deletions(-) diff --git a/code/uilib/uiwidget.cpp b/code/uilib/uiwidget.cpp index 3f0dca85..49da7e95 100644 --- a/code/uilib/uiwidget.cpp +++ b/code/uilib/uiwidget.cpp @@ -1966,11 +1966,23 @@ bool UIWidget::isEnabled ) { - if( !strcmp( m_enabledCvar, "" ) || UI_GetCvarInt( m_enabledCvar, 0 ) ) - { + if (!strcmp(m_enabledCvar.c_str(), "")) { return m_enabled; } + if (m_enabledCvar[0] == '!') { + // + // Added in 2.30 + // True if the cvar is 0 + if (m_enabled) { + return !UI_GetCvarInt(m_enabledCvar.c_str() + 1, 0); + } + } else { + if (m_enabled) { + return UI_GetCvarInt(m_enabledCvar.c_str(), 0) != 0; + } + } + return false; } @@ -2414,84 +2426,84 @@ void UIWidget::Display { int i; int n; - vec4_t col; + vec4_t col = { 1, 1, 1, 1 }; - VectorSet( col, 1, 1, 1 ); + if ( !isEnabled() ) { + return; + } - if( !m_enabledCvar.length() || UI_GetCvarInt( m_enabledCvar, 0 ) ) + if( !m_enabledCvar.length() && !IsVisible() ) { + return; + } + + if (m_direction || m_fadetime || m_fadeSequenceState != fadesequence_t::SEQUENCE_NONE) { + Motion(); + } + + m_local_alpha = m_alpha * parent_alpha; + set2D(); + + col[ 3 ] = m_local_alpha; + uii.Rend_SetColor( col ); + + if( m_background_color.a != 0.0 ) { - if( !m_enabledCvar.length() && !IsVisible() ) - return; + DrawBox( 0, 0, m_frame.size.width, m_frame.size.height, m_background_color, m_background_color.a * m_local_alpha ); + } - if (m_direction || m_fadetime || m_fadeSequenceState != fadesequence_t::SEQUENCE_NONE) { - Motion(); - } + if( m_borderStyle == border_outline ) + { + DrawBoxWithSolidBorder( UIRect2D( 0, 0, m_frame.size.width, m_frame.size.height ), UWhite, m_border_color.original, 2, 2, m_local_alpha ); + } + else if( m_borderStyle ) + { + Draw3DBox( 0, 0, m_frame.size.width, m_frame.size.height, m_borderStyle == border_indent, m_border_color, m_local_alpha ); + } - m_local_alpha = m_alpha * parent_alpha; - set2D(); - - col[ 3 ] = m_local_alpha; + if( m_material ) + { + col[0] = m_foreground_color.r; + col[1] = m_foreground_color.g; + col[2] = m_foreground_color.b; + col[3] = m_foreground_color.a * m_local_alpha; uii.Rend_SetColor( col ); - if( m_background_color.a != 0.0 ) - { - DrawBox( 0, 0, m_frame.size.width, m_frame.size.height, m_background_color, m_background_color.a * m_local_alpha ); - } + m_material->ReregisterMaterial(); - if( m_borderStyle == border_outline ) + if( m_flags & WF_TILESHADER ) { - DrawBoxWithSolidBorder( UIRect2D( 0, 0, m_frame.size.width, m_frame.size.height ), UWhite, m_border_color.original, 2, 2, m_local_alpha ); - } - else if( m_borderStyle ) - { - Draw3DBox( 0, 0, m_frame.size.width, m_frame.size.height, m_borderStyle == border_indent, m_border_color, m_local_alpha ); - } - - if( m_material ) - { - col[0] = m_foreground_color.r; - col[1] = m_foreground_color.g; - col[2] = m_foreground_color.b; - col[3] = m_foreground_color.a * m_local_alpha; - uii.Rend_SetColor( col ); - - m_material->ReregisterMaterial(); - - if( m_flags & WF_TILESHADER ) - { - if (m_bVirtual) { - float fvWidth = m_frame.size.width / m_vVirtualScale[0] / uii.Rend_GetShaderWidth(m_material->GetMaterial()); - float fvHeight = m_frame.size.height / m_vVirtualScale[1] / uii.Rend_GetShaderHeight(m_material->GetMaterial()); - - uii.Rend_DrawPicStretched(0, 0, m_frame.size.width, m_frame.size.height, 0, 0, fvWidth, fvHeight, m_material->GetMaterial()); - } else { - uii.Rend_DrawPicTiled(0, 0, m_frame.size.width, m_frame.size.height, m_material->GetMaterial()); - } - } - else - { - uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_material->GetMaterial() ); + if (m_bVirtual) { + float fvWidth = m_frame.size.width / m_vVirtualScale[0] / uii.Rend_GetShaderWidth(m_material->GetMaterial()); + float fvHeight = m_frame.size.height / m_vVirtualScale[1] / uii.Rend_GetShaderHeight(m_material->GetMaterial()); + + uii.Rend_DrawPicStretched(0, 0, m_frame.size.width, m_frame.size.height, 0, 0, fvWidth, fvHeight, m_material->GetMaterial()); + } else { + uii.Rend_DrawPicTiled(0, 0, m_frame.size.width, m_frame.size.height, m_material->GetMaterial()); } } - - if( m_pressedmaterial_active && m_pressedmaterial != NULL ) + else { - m_pressedmaterial->ReregisterMaterial(); - uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_pressedmaterial->GetMaterial() ); - } - else if( m_hovermaterial_active && m_hovermaterial != NULL ) - { - m_hovermaterial->ReregisterMaterial(); - uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_hovermaterial->GetMaterial() ); + uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_material->GetMaterial() ); } + } - Draw(); + if( m_pressedmaterial_active && m_pressedmaterial != NULL ) + { + m_pressedmaterial->ReregisterMaterial(); + uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_pressedmaterial->GetMaterial() ); + } + else if( m_hovermaterial_active && m_hovermaterial != NULL ) + { + m_hovermaterial->ReregisterMaterial(); + uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_hovermaterial->GetMaterial() ); + } - n = m_children.NumObjects(); - for( i = 1; i <= m_children.NumObjects(); i++ ) - { - m_children.ObjectAt( i )->Display( m_frame, m_local_alpha ); - } + Draw(); + + n = m_children.NumObjects(); + for( i = 1; i <= m_children.NumObjects(); i++ ) + { + m_children.ObjectAt( i )->Display( m_frame, m_local_alpha ); } } From fc0a995c66cdb0d49a7157bd16246efc4196b71a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 20 Jul 2024 16:04:04 +0200 Subject: [PATCH 0546/2040] Added code to save image with custom resolution to a file --- code/renderer/tr_init.c | 98 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index 3ab56925..c90ed92d 100644 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -630,6 +630,66 @@ void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) { , a, b, c, d ); } +/* +==================== +R_ResampledScreenShot +==================== +*/ +void R_ResampledScreenShot(const char* filename, int destwidth, int destheight) { + char checkname[MAX_OSPATH]; + byte *buffer; + byte *source; + byte *src, *dst; + int x, y; + int r, g, b; + float xScale, yScale; + int xx, yy; + + source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); + + buffer = ri.Hunk_AllocateTempMemory(destheight * destwidth * 3 + 18); + Com_Memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = destwidth & 255; + buffer[13] = destwidth >> 8; + buffer[14] = destheight & 255; + buffer[15] = destheight >> 8; + buffer[16] = 24; // pixel size + + qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); + + // resample from source + xScale = glConfig.vidWidth / (float)(destwidth * 4); + yScale = glConfig.vidHeight / (float)(destheight * 3); + for ( y = 0 ; y < destheight ; y++ ) { + for ( x = 0 ; x < destwidth ; x++ ) { + r = g = b = 0; + for ( yy = 0 ; yy < 3 ; yy++ ) { + for ( xx = 0 ; xx < 4 ; xx++ ) { + src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) ); + r += src[0]; + g += src[1]; + b += src[2]; + } + } + dst = buffer + 18 + 3 * ( y * destwidth + x ); + dst[0] = b / 12; + dst[1] = g / 12; + dst[2] = r / 12; + } + } + + // gamma correct + if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + R_GammaCorrect( buffer + 18, destheight * destwidth * 3 ); + } + + ri.FS_WriteFile( filename, buffer, destheight * destwidth * 3 + 18 ); + + ri.Hunk_FreeTempMemory( buffer ); + ri.Hunk_FreeTempMemory( source ); +} + /* ==================== R_LevelShot @@ -709,7 +769,8 @@ Doesn't print the pacifier message if there is a second arg */ void R_ScreenShot_f(void) { char checkname[MAX_OSPATH]; - static int lastNumber = -1; + static int lastNumber = -1; + int width, height; qboolean silent; if (!strcmp(ri.Cmd_Argv(1), "levelshot")) { @@ -723,10 +784,23 @@ void R_ScreenShot_f(void) { silent = qfalse; } - if (ri.Cmd_Argc() == 2 && !silent) { + width = 0; + height = 0; + + if (ri.Cmd_Argc() >= 2 && !silent) { // explicit filename - Com_sprintf(checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv(1)); - } else { + const char* name = ri.Cmd_Argv(1); + if (strchr(name, '/')) { + Q_strncpyz(checkname, name, sizeof(checkname)); + } else { + Com_sprintf(checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv(1)); + } + + if (ri.Cmd_Argc(2) > 2) { + width = atoi(ri.Cmd_Argv(2)); + height = atoi(ri.Cmd_Argv(3)); + } + } else { // scan for a free filename // if we have saved a previous screenshot, don't scan @@ -753,14 +827,18 @@ void R_ScreenShot_f(void) { lastNumber++; } - R_TakeScreenshot(0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse); + if (!width || !height) { + R_TakeScreenshot(0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse); - if (!silent) { - char message[64]; + if (!silent) { + char message[64]; - Com_sprintf(message, sizeof(message), "centerprint \"%s %s\"\n", ri.LV_ConvertString("Wrote"), checkname); - ri.Cmd_ExecuteText(EXEC_NOW, message); - } + Com_sprintf(message, sizeof(message), "centerprint \"%s %s\"\n", ri.LV_ConvertString("Wrote"), checkname); + ri.Cmd_ExecuteText(EXEC_NOW, message); + } + } else { + R_ResampledScreenShot(checkname, width, height); + } } void R_ScreenShotJPEG_f (void) { From d1e94f39342dced73020decf01dd58ac3b416449 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 20 Jul 2024 16:07:02 +0200 Subject: [PATCH 0547/2040] Fix saveshot not executed when saving This fixes #273 where the loadsave menu wouldn't show the screenshot --- code/server/sv_ccmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 2bd89bac..c760c1cd 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -2002,7 +2002,7 @@ qboolean SV_ArchiveServerFile( qboolean loading, qboolean autosave ) name = Com_GetArchiveFileName( svs.gameName, "tga" ); Com_sprintf( cmdString, sizeof( cmdString ), "saveshot %s 256 256\n", name ); - Cbuf_ExecuteText( svs.autosave != qfalse, name ); + Cbuf_ExecuteText( svs.autosave ? EXEC_INSERT : EXEC_NOW, cmdString ); } else { From 89eae683182e1ab1aa3bf7eadc0cf8e5be497002 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 20 Jul 2024 22:09:03 +0200 Subject: [PATCH 0548/2040] Fixed parameter mistake (Why didn't you tell anything about that, MSVC?) --- code/renderer/tr_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index c90ed92d..ef34b507 100644 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -796,7 +796,7 @@ void R_ScreenShot_f(void) { Com_sprintf(checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv(1)); } - if (ri.Cmd_Argc(2) > 2) { + if (ri.Cmd_Argc() > 2) { width = atoi(ri.Cmd_Argv(2)); height = atoi(ri.Cmd_Argv(3)); } From 8bd377ce8547d58967a90252f8f479095c415b9f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:00:25 +0200 Subject: [PATCH 0549/2040] Fix the save system taking a screenshot of the whole UI menu instead of just the 3D view This fixes #328 where the save would have a screenshot of the save menu --- code/client/cl_ui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index e5c6f22d..9e7b103c 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -1777,6 +1777,8 @@ void UI_Update(void) hud_compass->GetContainerWidget()->Display(frame, 1.0); } } + + return; } if (fakk_console) { From 2198bdec210016699bca5aa8645b391014f79da0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:15:52 +0200 Subject: [PATCH 0550/2040] Added stub variables and functions for loading --- code/client/new/snd_local_new.h | 3 +++ code/client/new/snd_main_new.cpp | 40 ++++++++++++++++++++++++++++++++ code/client/new/snd_public_new.h | 1 + 3 files changed, 44 insertions(+) diff --git a/code/client/new/snd_local_new.h b/code/client/new/snd_local_new.h index 1f336208..69ae7dcf 100644 --- a/code/client/new/snd_local_new.h +++ b/code/client/new/snd_local_new.h @@ -59,6 +59,9 @@ typedef struct { void S_ChannelFree_Callback(channel_t* v); void S_LoadData(soundsystemsavegame_t* pSave); void S_SaveData(soundsystemsavegame_t* pSave); +void S_ReLoad(soundsystemsavegame_t* pSave); + +extern qboolean s_bSoundPaused; #ifdef __cplusplus } diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index 0007453a..e2417250 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +qboolean s_bSoundPaused = qfalse; + void S_Init2() { S_Init(); @@ -492,24 +494,62 @@ void S_TriggeredMusic_PlayIntroMusic() { S_StartBackgroundTrack("sound/music/mus_MainTheme.mp3", ""); } +/* +============== +S_TriggeredMusic_SetupHandle +============== +*/ +void S_TriggeredMusic_SetupHandle(const char* pszName, int iLoopCount, int iOffset, qboolean autostart) { + // FIXME: unimplemented +} + +/* +============== +callbackServer +============== +*/ void callbackServer(int entnum, int channel_number, const char* name) { if (com_sv_running->integer) { SV_SoundCallback(entnum, channel_number, name); } } +/* +============== +S_ChannelFree_Callback +============== +*/ void S_ChannelFree_Callback(channel_t* v) { if (v->entnum & S_FLAG_DO_CALLBACK) { callbackServer(v->entnum & ~S_FLAG_DO_CALLBACK, v - s_channels, v->thesfx->soundName); } } +/* +============== +S_LoadData +============== +*/ void S_LoadData(soundsystemsavegame_t* pSave) { // FIXME: unimplemented } +/* +============== +S_SaveData +============== +*/ void S_SaveData(soundsystemsavegame_t* pSave) { // FIXME: unimplemented } +/* +============== +S_ReLoad +============== +*/ +void S_ReLoad(soundsystemsavegame_t* pSave) { + // FIXME: unimplemented +} + #endif diff --git a/code/client/new/snd_public_new.h b/code/client/new/snd_public_new.h index 1e7d32a2..30fe316f 100644 --- a/code/client/new/snd_public_new.h +++ b/code/client/new/snd_public_new.h @@ -78,6 +78,7 @@ qboolean S_IsSoundPlaying(int channelNumber, const char* name); void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener); void S_FadeSound(float fTime); void S_TriggeredMusic_PlayIntroMusic(); +void S_TriggeredMusic_SetupHandle(const char* pszName, int iLoopCount, int iOffset, qboolean autostart); #ifdef __cplusplus } From 757b4849f86d0302fd615f55cc5dcfe8f83e90e8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jul 2024 20:07:32 +0200 Subject: [PATCH 0551/2040] Add a fix to load the music from save This commit implements code to get/set sample offset in an OpenAL channel and saves the music filename/offset into the file. This only works by using the experimental sound system, so it partially fixes #327 --- code/client/cl_ui.cpp | 14 +++---- code/client/new/snd_main_new.cpp | 30 ++++++++++++++ code/client/new/snd_public_new.h | 4 ++ code/client/snd_dma_new.cpp | 30 ++++++++++++++ code/client/snd_local_new.h | 3 ++ code/client/snd_openal_new.cpp | 67 +++++++++++++++++++++++++++----- code/client/snd_openal_new.h | 4 ++ code/client/snd_public.h | 4 ++ code/server/sv_ccmds.c | 12 ++++++ 9 files changed, 151 insertions(+), 17 deletions(-) diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 9e7b103c..cc84f72c 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -3976,13 +3976,13 @@ void S_ServerLoaded(void) Com_DPrintf("Loading Previous Sound State.\n"); S_StopAllSounds2(qfalse); - //S_TriggeredMusic_Stop(); - //s_bSoundPaused = qtrue; - //S_ReLoad( &svs.soundSystem ); - // - //if( svs.tm_filename[ 0 ] ) { - // S_TriggeredMusic_SetupHandle( svs.tm_filename, svs.tm_loopcount, svs.tm_offset, 0 ); - //} + S_TriggeredMusic_Stop(); + s_bSoundPaused = qtrue; + S_ReLoad( &svs.soundSystem ); + + if( svs.tm_filename[ 0 ] ) { + S_TriggeredMusic_SetupHandle( svs.tm_filename, svs.tm_loopcount, svs.tm_offset, 0 ); + } } /* diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index e2417250..9e3fbbbc 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -503,6 +503,36 @@ void S_TriggeredMusic_SetupHandle(const char* pszName, int iLoopCount, int iOffs // FIXME: unimplemented } +/* +============== +S_GetMusicFilename +============== +*/ +const char* S_GetMusicFilename() { + // FIXME: unimplemented + return ""; +} + +/* +============== +S_GetMusicLoopCount +============== +*/ +int S_GetMusicLoopCount() { + // FIXME: unimplemented + return 0; +} + +/* +============== +S_GetMusicOffset +============== +*/ +unsigned int S_GetMusicOffset() { + // FIXME: unimplemented + return 0; +} + /* ============== callbackServer diff --git a/code/client/new/snd_public_new.h b/code/client/new/snd_public_new.h index 30fe316f..c945052a 100644 --- a/code/client/new/snd_public_new.h +++ b/code/client/new/snd_public_new.h @@ -80,6 +80,10 @@ void S_FadeSound(float fTime); void S_TriggeredMusic_PlayIntroMusic(); void S_TriggeredMusic_SetupHandle(const char* pszName, int iLoopCount, int iOffset, qboolean autostart); +const char* S_GetMusicFilename(); +int S_GetMusicLoopCount(); +unsigned int S_GetMusicOffset(); + #ifdef __cplusplus } #endif diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index fbe46aed..efa4735d 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -787,4 +787,34 @@ void S_ClearSoundBuffer() // TODO: Remove once AL is fully implemented } +/* +============== +S_GetMusicFilename +============== +*/ +const char* S_GetMusicFilename() +{ + return S_Driver_GetMusicFilename(); +} + +/* +============== +S_GetMusicLoopCount +============== +*/ +int S_GetMusicLoopCount() +{ + return S_Driver_GetMusicLoopCount(); +} + +/* +============== +S_GetMusicOffset +============== +*/ +unsigned int S_GetMusicOffset() +{ + return S_Driver_GetMusicOffset(); +} + #endif diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 20358ddb..d6771244 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -215,6 +215,9 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo #define S_Driver_Respatialize S_Call_SndDriverX(SOUND_DRIVER, Respatialize) #define S_Driver_SetReverb S_Call_SndDriverX(SOUND_DRIVER, SetReverb) #define S_Driver_Update S_Call_SndDriverX(SOUND_DRIVER, Update) +#define S_Driver_GetMusicFilename S_Call_SndDriverX(SOUND_DRIVER, GetMusicFilename) +#define S_Driver_GetMusicLoopCount S_Call_SndDriverX(SOUND_DRIVER, GetMusicLoopCount) +#define S_Driver_GetMusicOffset S_Call_SndDriverX(SOUND_DRIVER, GetMusicOffset) void S_PrintInfo(); void S_DumpInfo(); diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index a8c65c5a..21dd868c 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -958,8 +958,6 @@ void S_UnpauseSound() return; } - s_bSoundPaused = true; - for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { openal_channel *pChannel = openal.channel[i]; if (!pChannel) { @@ -2477,6 +2475,36 @@ void S_OPENAL_Update() } } +/* +============== +S_OPENAL_GetMusicFilename +============== +*/ +const char* S_OPENAL_GetMusicFilename() +{ + return openal.tm_filename; +} + +/* +============== +S_OPENAL_GetMusicLoopCount +============== +*/ +int S_OPENAL_GetMusicLoopCount() +{ + return openal.tm_loopcount; +} + +/* +============== +S_OPENAL_GetMusicOffset +============== +*/ +unsigned int S_OPENAL_GetMusicOffset() +{ + return openal.chan_trig_music.sample_offset(); +} + /* ============== S_IsSoundPlaying @@ -3077,8 +3105,12 @@ openal_channel::sample_offset */ U32 openal_channel::sample_offset() { - STUB_DESC("sample_offset"); - return 127; + ALint offset = 0; + + qalGetSourcei(source, AL_SAMPLE_OFFSET, &offset); + alDieIfError(); + + return offset; } /* @@ -3088,8 +3120,12 @@ openal_channel::sample_ms_offset */ U32 openal_channel::sample_ms_offset() { - STUB_DESC("sample_ms_offset"); - return 127; + float offset = 0; + + qalGetSourcef(source, AL_SAMPLE_OFFSET, &offset); + alDieIfError(); + + return offset * 1000.f; } /* @@ -3122,7 +3158,8 @@ openal_channel::set_sample_offset */ void openal_channel::set_sample_offset(U32 offset) { - STUB_DESC("sample_offset"); + qalSourcei(source, AL_SAMPLE_OFFSET, offset); + alDieIfError(); } /* @@ -3132,7 +3169,8 @@ openal_channel::set_sample_ms_offset */ void openal_channel::set_sample_ms_offset(U32 offset) { - STUB_DESC("sample_ms_offset"); + qalSourcef(source, AL_SEC_OFFSET, offset / 1000.f); + alDieIfError(); } /* @@ -3932,9 +3970,18 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs openal.chan_trig_music.set_sample_loop_count(iLoopCount); openal.chan_trig_music.set_sample_offset(iOffset); - if (autostart) { - openal.chan_trig_music.play(); + // Fixed in OPM + // Play the sound then pause it immediately + // So it can be unpaused upon loading from save + openal.chan_trig_music.play(); + + if (!autostart) { + openal.chan_trig_music.pause(); } + + //if (autostart) { + // openal.chan_trig_music.play(); + //} } /* diff --git a/code/client/snd_openal_new.h b/code/client/snd_openal_new.h index 1fbec8ba..f786c465 100644 --- a/code/client/snd_openal_new.h +++ b/code/client/snd_openal_new.h @@ -197,6 +197,10 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi void S_OPENAL_SetReverb(int iType, float fLevel); void S_OPENAL_Update(); +const char* S_OPENAL_GetMusicFilename(); +int S_OPENAL_GetMusicLoopCount(); +unsigned int S_OPENAL_GetMusicOffset(); + #ifdef __cplusplus } #endif diff --git a/code/client/snd_public.h b/code/client/snd_public.h index ce3069bf..f348cdc9 100644 --- a/code/client/snd_public.h +++ b/code/client/snd_public.h @@ -157,6 +157,10 @@ void S_StopMovieAudio(); void S_SetupMovieAudio(const char* pszMovieName); int S_CurrentMoviePosition(); +const char* S_GetMusicFilename(); +int S_GetMusicLoopCount(); +unsigned int S_GetMusicOffset(); + #ifdef __cplusplus } #endif diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index c760c1cd..88dba1c2 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1955,6 +1955,7 @@ qboolean SV_ArchiveServerFile( qboolean loading, qboolean autosave ) time_t aclock; Com_DPrintf( "SV_ArchiveServerFile(%s)\n", autosave ? "true" : "false" ); + memset(&save, 0, sizeof(save)); name = Com_GetArchiveFileName( svs.gameName, "ssv" ); if( !loading ) @@ -1995,6 +1996,17 @@ qboolean SV_ArchiveServerFile( qboolean loading, qboolean autosave ) strncpy( save.saveName, svs.gameName, sizeof( save.saveName ) ); save.mapTime = svs.time - svs.startTime; + name = S_GetMusicFilename(); + if (name) { + Q_strncpyz(save.tm_filename, name, sizeof(save.tm_filename)); + save.tm_offset = S_GetMusicOffset(); + save.tm_loopcount = S_GetMusicLoopCount(); + } else { + save.tm_filename[0] = 0; + save.tm_offset = 0; + save.tm_loopcount = 0; + } + FS_Write( &save, sizeof( savegamestruct_t ), f ); S_Save( f ); CM_WritePortalState( f ); From c5ef60040a5f6199c65c44cf98d66a50b0db5964 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 22 Jul 2024 20:44:00 +0200 Subject: [PATCH 0552/2040] Fix sounds not being resumed properly after loading from save --- code/client/snd_openal_new.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 21dd868c..7214807d 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -964,11 +964,9 @@ void S_UnpauseSound() continue; } - if (!pChannel->is_paused()) { - continue; + if (pChannel->is_paused() || (pChannel->iFlags & CHANNEL_FLAG_PLAYABLE)) { + pChannel->play(); } - - pChannel->play(); } if (openal.chan_mp3.is_paused()) { @@ -2591,9 +2589,6 @@ S_StartSoundFromBase(channelbasesavegame_t *pBase, openal_channel *pChannel, sfx } pChannel->iBaseRate = pChannel->sample_playback_rate(); - pChannel->set_gain(pChannel->fVolume); - pChannel->set_sample_offset(pBase->iOffset); - pChannel->set_sample_playback_rate(pChannel->iBaseRate * pBase->fNewPitchMult); if (sfx_infos[pSfx->sfx_info_index].loop_start != -1) { pChannel->set_sample_loop_block( @@ -2612,6 +2607,10 @@ S_StartSoundFromBase(channelbasesavegame_t *pBase, openal_channel *pChannel, sfx pChannel->set_sample_loop_count(1); } + pChannel->set_gain(pChannel->fVolume); + pChannel->set_sample_offset(pBase->iOffset); + pChannel->set_sample_playback_rate(pChannel->iBaseRate * pBase->fNewPitchMult); + if (bStartUnpaused) { pChannel->resume_sample(); } else { @@ -2917,6 +2916,7 @@ openal_channel::force_free void openal_channel::force_free() { stop(); + iFlags = 0; } /* From e5fb85ad089f722b8fcc6d798e9b69288798422a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:06:48 +0200 Subject: [PATCH 0553/2040] Fix material not refreshing when it already has a shader. This fixes #329 where the material (matching quick.tga) would be loaded only once without being able to change --- code/uilib/uiwidget.cpp | 2 +- code/uilib/uiwinman.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/uilib/uiwidget.cpp b/code/uilib/uiwidget.cpp index 49da7e95..4297705b 100644 --- a/code/uilib/uiwidget.cpp +++ b/code/uilib/uiwidget.cpp @@ -653,7 +653,7 @@ void UIReggedMaterial::RefreshMaterial { if( isGot ) { - this->hMat = uii.Rend_RegisterMaterial( name.c_str() ); + this->hMat = uii.Rend_RefreshMaterial( name.c_str() ); } } diff --git a/code/uilib/uiwinman.cpp b/code/uilib/uiwinman.cpp index 9e986d97..116e1f4e 100644 --- a/code/uilib/uiwinman.cpp +++ b/code/uilib/uiwinman.cpp @@ -635,7 +635,7 @@ UIReggedMaterial *UIWindowManager::RefreshShader(const str& name) for (i = 1; i <= m_materiallist.NumObjects(); i++) { regged = m_materiallist.ObjectAt(i); if (regged->GetName() == name) { - regged->ReregisterMaterial(); + regged->RefreshMaterial(); return regged; } } From 81df55310bdf5877dba7ef068d3cd10273257a16 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:53:40 +0200 Subject: [PATCH 0554/2040] Fix medals always being awarded This fixes #316 --- code/fgame/player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 86b41dd3..98b681f4 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -4499,9 +4499,9 @@ void Player::ClientThink(void) || g_medalbt3->modificationCount > 1 || g_medalbt4->modificationCount > 1 || g_medalbt5->modificationCount > 1 || g_eogmedal0->modificationCount > 1 || g_eogmedal1->modificationCount > 1 || g_eogmedal2->modificationCount > 1) { - gi.cvar_set("g_gotmedal", "0"); - } else { gi.cvar_set("g_gotmedal", "1"); + } else { + gi.cvar_set("g_gotmedal", "0"); } client->ps.pm_flags |= PMF_FROZEN; From 11ec6270da4d9541417a58cff8c84b9859c28190 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 24 Jul 2024 19:57:22 +0200 Subject: [PATCH 0555/2040] Made OpenAL package required --- code/client/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index 77a5f515..efb871d9 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -20,7 +20,7 @@ target_compile_definitions(omohclient INTERFACE USE_CODEC_MP3) if (USE_SOUND_NEW) # Try to use OpenAL - find_package(OpenAL) + find_package(OpenAL REQUIRED) if (OPENAL_FOUND) target_compile_definitions(omohclient INTERFACE USE_OPENAL=1 USE_SOUND_NEW=1) if (MSVC) From c093122764f99f1a45cc10005b4864e224418d66 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 24 Jul 2024 20:07:22 +0200 Subject: [PATCH 0556/2040] Made code C++ compatible so UI_LoadResource() can be used --- code/client/{snd_mem_new.c => snd_mem_new.cpp} | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) rename code/client/{snd_mem_new.c => snd_mem_new.cpp} (98%) diff --git a/code/client/snd_mem_new.c b/code/client/snd_mem_new.cpp similarity index 98% rename from code/client/snd_mem_new.c rename to code/client/snd_mem_new.cpp index 2cd06435..c3f18744 100644 --- a/code/client/snd_mem_new.c +++ b/code/client/snd_mem_new.cpp @@ -22,7 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if USE_SOUND_NEW -# include "snd_local.h" +#include "snd_local.h" +#include "cl_ui.h" byte *data_p; byte *iff_end; @@ -355,7 +356,7 @@ qboolean DownSampleWav(wavinfo_t *info, byte *wav, int wavlength, int newkhz, by info->rate = (float)newkhz; newdatasize += info->dataofs; - *newdata = Z_TagMalloc(newdatasize, TAG_SOUND); + *newdata = (byte*)Z_TagMalloc(newdatasize, TAG_SOUND); memcpy(*newdata, wav, info->dataofs); iff_data = *newdata; @@ -450,7 +451,7 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo return qfalse; } - sfx->data = Z_TagMalloc(size, TAG_SOUND); + sfx->data = (byte*)Z_TagMalloc(size, TAG_SOUND); FS_Read(sfx->data, size, file_handle); FS_FCloseFile(file_handle); @@ -528,7 +529,7 @@ qboolean S_LoadMP3(const char *fileName, sfx_t *sfx) } memset(&sfx->info, 0, sizeof(sfx->info)); - sfx->data = Z_TagMalloc(length, TAG_SOUND); + sfx->data = (byte*)Z_TagMalloc(length, TAG_SOUND); sfx->length = length; sfx->width = 1; FS_Read(sfx->data, length, file_handle); From 016e062fefc5c60d9278874a3efd3e340b3783c5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:10:46 +0200 Subject: [PATCH 0557/2040] Fix UIReggedMaterial::ReregisterMaterial and UIReggedMaterial::GetMaterial ReregisterMaterial() must register the material if it was registered before, and GetMaterial() must register the material if it hasn't been registered and return it --- code/client/cl_ui.cpp | 2 +- code/client/cl_uistd.cpp | 32 -------------------------------- code/uilib/uibind.cpp | 3 --- code/uilib/uibindlist.cpp | 3 --- code/uilib/uicheckbox.cpp | 1 - code/uilib/uilabel.cpp | 1 - code/uilib/uilangamelist.cpp | 2 -- code/uilib/uilist.cpp | 4 ---- code/uilib/uipulldownmenu.cpp | 6 ------ code/uilib/uislider.cpp | 10 ---------- code/uilib/uiwidget.cpp | 14 ++++++-------- code/uilib/uiwinman.cpp | 4 +--- 12 files changed, 8 insertions(+), 74 deletions(-) diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index cc84f72c..fff374af 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -1891,7 +1891,7 @@ void UI_Update(void) UI_CloseConsole(); } } else if (ui_static_materials.loading) { - ui_static_materials.loading->ReregisterMaterial(); + ui_static_materials.loading->GetMaterial(); } } } diff --git a/code/client/cl_uistd.cpp b/code/client/cl_uistd.cpp index d3780aa8..fd7fe2c1 100644 --- a/code/client/cl_uistd.cpp +++ b/code/client/cl_uistd.cpp @@ -490,12 +490,10 @@ void UIFakkLabel::DrawStatbar(float frac) { float width = frac * m_frame.size.width; - m_statbar_material->ReregisterMaterial(); re.DrawTilePic(0.0, 0.0, width, m_frame.size.height, m_statbar_material->GetMaterial()); if (alpha != 0.0 && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTilePic(0.0, 0.0, width, m_frame.size.height, m_statbar_material_flash->GetMaterial()); } break; @@ -507,12 +505,10 @@ void UIFakkLabel::DrawStatbar(float frac) { float y = m_frame.size.height * (1.0 - frac); - m_statbar_material->ReregisterMaterial(); re.DrawTilePic(0.0, y, m_frame.size.width, m_frame.size.height, m_statbar_material->GetMaterial()); if (alpha != 0.0 && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTilePic( 0.0, y, m_frame.size.width, m_frame.size.height, m_statbar_material_flash->GetMaterial() ); @@ -528,14 +524,12 @@ void UIFakkLabel::DrawStatbar(float frac) { float width = frac * m_frame.size.width; - m_statbar_material->ReregisterMaterial(); re.DrawStretchPic( 0.0, 0.0, width, m_frame.size.height, 0.0, 0.0, 1.0, 1.0, m_statbar_material->GetMaterial() ); if (alpha != 0.0 && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawStretchPic( 0.0, 0.0, @@ -557,14 +551,12 @@ void UIFakkLabel::DrawStatbar(float frac) float y = m_frame.size.height * (1.0 - frac); float height = m_frame.size.height * frac; - m_statbar_material->ReregisterMaterial(); re.DrawStretchPic( 0.0, y, m_frame.size.width, height, 0.0, 1.0 - frac, 1.0, 1.0, m_statbar_material->GetMaterial() ); if (alpha != 0.0 && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawStretchPic( 0.0, y, @@ -583,14 +575,12 @@ void UIFakkLabel::DrawStatbar(float frac) { float height = m_frame.size.height * frac; - m_statbar_material->ReregisterMaterial(); re.DrawStretchPic( 0.0, 0.0, m_frame.size.width, height, 0.0, 0.0, 1.0, frac, m_statbar_material->GetMaterial() ); if (alpha != 0.0 && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawStretchPic( 0.0, 0.0, @@ -686,12 +676,10 @@ void UIFakkLabel::DrawStatCircle(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } } else { @@ -709,12 +697,10 @@ void UIFakkLabel::DrawStatCircle(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } @@ -739,12 +725,10 @@ void UIFakkLabel::DrawStatCircle(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } } else { @@ -766,12 +750,10 @@ void UIFakkLabel::DrawStatCircle(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } @@ -846,12 +828,10 @@ void UIFakkLabel::DrawStatNeedle(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha != 0.f && m_statbar_material_flash) { re.SetColor(col); - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } @@ -867,11 +847,9 @@ void UIFakkLabel::DrawStatNeedle(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha != 0.f && m_statbar_material_flash) { - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } } @@ -937,11 +915,9 @@ void UIFakkLabel::DrawStatRotator(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha != 0.f && m_statbar_material_flash) { - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } @@ -959,11 +935,9 @@ void UIFakkLabel::DrawStatRotator(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha != 0.f && m_statbar_material_flash) { - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } } @@ -1137,7 +1111,6 @@ void UIFakkLabel::DrawStatCompass(float frac) vVerts[1][1] = vCenter[1] + vCompassDir[1] * vCenter[1] + fSinVal * vCenter[0]; vVerts[2][1] = vCenter[1] - vCompassDir[1] * vCenter[1] - fSinVal * vCenter[0]; - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); vVerts[0][0] = vVerts[2][0]; @@ -1150,7 +1123,6 @@ void UIFakkLabel::DrawStatCompass(float frac) vVerts[2][0] = vCenter[0] + fCosVal * vCenter[1] - vCompassDir[0] * vCenter[0]; vVerts[2][1] = vCenter[1] * fSinVal + vCenter[0] - vCompassDir[1] * vCenter[1]; - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); } @@ -1227,11 +1199,9 @@ void UIFakkLabel::DrawStatSpinner(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha != 0.f && m_statbar_material_flash) { - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } @@ -1249,11 +1219,9 @@ void UIFakkLabel::DrawStatSpinner(float frac) re.SetColor(m_foreground_color); } - m_statbar_material->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial()); if (alpha != 0.f && m_statbar_material_flash) { - m_statbar_material_flash->ReregisterMaterial(); re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material_flash->GetMaterial()); } } diff --git a/code/uilib/uibind.cpp b/code/uilib/uibind.cpp index cc6d43c9..c617cc4e 100644 --- a/code/uilib/uibind.cpp +++ b/code/uilib/uibind.cpp @@ -172,7 +172,6 @@ void UIBindButton::DrawUnpressed(void) if (str::cmp(s, m_last_keyname)) { m_mat = uWinMan.RegisterShader("textures/bind/" + s); if (m_mat) { - m_mat->ReregisterMaterial(); if (m_mat->GetMaterial()) { m_material = m_mat; } else { @@ -186,8 +185,6 @@ void UIBindButton::DrawUnpressed(void) } if (m_mat) { - m_mat->ReregisterMaterial(); - if (m_mat->GetMaterial()) { return; } diff --git a/code/uilib/uibindlist.cpp b/code/uilib/uibindlist.cpp index c2d3d1b4..f094a799 100644 --- a/code/uilib/uibindlist.cpp +++ b/code/uilib/uibindlist.cpp @@ -592,10 +592,7 @@ void UIFakkBindList::DrawPressKey(UIRect2D frame) return; } - m_presskey_mat->ReregisterMaterial(); w = uii.Rend_GetShaderWidth(m_presskey_mat->GetMaterial()) * m_vVirtualScale[0]; - - m_presskey_mat->ReregisterMaterial(); h = uii.Rend_GetShaderHeight(m_presskey_mat->GetMaterial()) * m_vVirtualScale[1]; UIRect2D newFrame = uWinMan.getFrame(); diff --git a/code/uilib/uicheckbox.cpp b/code/uilib/uicheckbox.cpp index 9b536b62..77e1c76d 100644 --- a/code/uilib/uicheckbox.cpp +++ b/code/uilib/uicheckbox.cpp @@ -102,7 +102,6 @@ void UICheckBox::Draw() float y = (m_frame.size.height - height) * 0.5f; if (material) { - material->ReregisterMaterial(); uii.Rend_DrawPicStretched(x, y, width, height, 0.0f, 0.0f, 1.0f, 1.0f, material->GetMaterial()); } else diff --git a/code/uilib/uilabel.cpp b/code/uilib/uilabel.cpp index 5a6524fe..30085e49 100644 --- a/code/uilib/uilabel.cpp +++ b/code/uilib/uilabel.cpp @@ -270,7 +270,6 @@ void UILabel::Draw(void) m_sCurrentShaderName = string; setMaterial(uWinMan.RegisterShader(m_sCurrentShaderName)); - m_material->ReregisterMaterial(); if (!m_material->GetMaterial()) { setMaterial(NULL); diff --git a/code/uilib/uilangamelist.cpp b/code/uilib/uilangamelist.cpp index deb0ed93..0dd99184 100644 --- a/code/uilib/uilangamelist.cpp +++ b/code/uilib/uilangamelist.cpp @@ -287,9 +287,7 @@ void UILanGameList::DrawNoServers(UIRect2D frame) AddNoServer(); } - m_noservers_mat->ReregisterMaterial(); w = uii.Rend_GetShaderWidth(m_noservers_mat->GetMaterial() * m_vVirtualScale[0]); - m_noservers_mat->ReregisterMaterial(); h = uii.Rend_GetShaderHeight(m_noservers_mat->GetMaterial() * m_vVirtualScale[1]); UIRect2D newFrame = uWinMan.getFrame(); diff --git a/code/uilib/uilist.cpp b/code/uilib/uilist.cpp index 0b22cdba..fdc6f782 100644 --- a/code/uilib/uilist.cpp +++ b/code/uilib/uilist.cpp @@ -108,8 +108,6 @@ void UIList::Draw m_border_color, m_local_alpha); - m_prev_arrow->ReregisterMaterial(); - float height = m_frame.size.height - 4.0; float width = m_arrow_width - 4.0; uii.Rend_DrawPicStretched( @@ -135,8 +133,6 @@ void UIList::Draw m_border_color, m_local_alpha); - m_next_arrow->ReregisterMaterial(); - uii.Rend_DrawPicStretched( x + 2.0f, y + 2.0f, diff --git a/code/uilib/uipulldownmenu.cpp b/code/uilib/uipulldownmenu.cpp index 9236472e..780ad481 100644 --- a/code/uilib/uipulldownmenu.cpp +++ b/code/uilib/uipulldownmenu.cpp @@ -121,8 +121,6 @@ UIRect2D UIPulldownMenu::getAlignmentRect uipull_describe *uipd = m_desc.ObjectAt(i); if (uipd && uipd->material) { - uipd->material->ReregisterMaterial(); - int h = uii.Rend_GetShaderHeight(uipd->material->GetMaterial()); if (h > maxheight) { @@ -148,7 +146,6 @@ float UIPulldownMenu::getDescWidth UIReggedMaterial* mat = desc->material; if (mat) { - mat->ReregisterMaterial(); return uii.Rend_GetShaderWidth(mat->GetMaterial()); } @@ -164,7 +161,6 @@ float UIPulldownMenu::getDescHeight UIReggedMaterial* mat = desc->material; if (mat) { - mat->ReregisterMaterial(); return uii.Rend_GetShaderHeight(mat->GetMaterial()); } @@ -549,7 +545,6 @@ void UIPulldownMenu::Draw m_font->setColor(m_highlightFGColor); if (desc->selected_material) { - desc->selected_material->ReregisterMaterial(); uii.Rend_DrawPicStretched( atx, 0.0f, @@ -577,7 +572,6 @@ void UIPulldownMenu::Draw { if (m_submenu != i) { - desc->material->ReregisterMaterial(); uii.Rend_DrawPicStretched( atx, 0.0f, diff --git a/code/uilib/uislider.cpp b/code/uilib/uislider.cpp index cc7b7c13..b2403e78 100644 --- a/code/uilib/uislider.cpp +++ b/code/uilib/uislider.cpp @@ -454,7 +454,6 @@ void UISlider::LayoutSliderThumbShader m_thumbmaterial_pressed = uWinMan.RegisterShader(pressedShader); } - m_thumbmaterial->ReregisterMaterial(); m_sliderwidth = uii.Rend_GetShaderWidth(m_thumbmaterial->GetMaterial()); m_initialized = qfalse; } @@ -478,7 +477,6 @@ void UISlider::LayoutSliderLeftShader m_prev_arrow_material_pressed = uWinMan.RegisterShader(pressedShader); } - m_prev_arrow_material->ReregisterMaterial(); m_arrow_width = uii.Rend_GetShaderWidth(m_prev_arrow_material->GetMaterial()); m_initialized = qfalse; } @@ -502,7 +500,6 @@ void UISlider::LayoutSliderRightShader m_next_arrow_material_pressed = uWinMan.RegisterShader(pressedShader); } - m_next_arrow_material->ReregisterMaterial(); m_arrow_width = uii.Rend_GetShaderWidth(m_next_arrow_material->GetMaterial()); m_initialized = qfalse; } @@ -569,7 +566,6 @@ void UISlider::Draw if (m_thumbmaterial) { UIReggedMaterial* material = m_thumb_depressed ? m_thumbmaterial_pressed : m_thumbmaterial; - material->ReregisterMaterial(); uii.Rend_DrawPicStretched(x, 0.0f, scaledThumbWidth, m_frame.size.height, 0.0f, 0.0f, 1.0f, 1.0f, material->GetMaterial()); } else @@ -581,7 +577,6 @@ void UISlider::Draw { Draw3DBox(0.0f, 0.0f, scaledArrowWidth, m_frame.size.height, m_prev_arrow_depressed, m_border_color, m_local_alpha); - m_prev_arrow_material->ReregisterMaterial(); uii.Rend_DrawPicStretched( 2.0f, 2.0f, @@ -599,12 +594,10 @@ void UISlider::Draw uihandle_t material; if (m_prev_arrow_depressed) { - m_prev_arrow_material_pressed->ReregisterMaterial(); material = m_prev_arrow_material_pressed->GetMaterial(); } else { - m_prev_arrow_material->ReregisterMaterial(); material = m_prev_arrow_material->GetMaterial(); } @@ -615,7 +608,6 @@ void UISlider::Draw { Draw3DBox(m_frame.size.width - scaledArrowWidth, 0.0f, scaledArrowWidth, m_frame.size.height, m_next_arrow_depressed, m_border_color, m_local_alpha); - m_next_arrow_material->ReregisterMaterial(); uii.Rend_DrawPicStretched( m_frame.size.width - scaledArrowWidth + 2.0f, 2.0f, @@ -633,12 +625,10 @@ void UISlider::Draw uihandle_t material; if (m_next_arrow_depressed) { - m_next_arrow_material_pressed->ReregisterMaterial(); material = m_next_arrow_material_pressed->GetMaterial(); } else { - m_next_arrow_material->ReregisterMaterial(); material = m_next_arrow_material->GetMaterial(); } diff --git a/code/uilib/uiwidget.cpp b/code/uilib/uiwidget.cpp index 4297705b..4682c062 100644 --- a/code/uilib/uiwidget.cpp +++ b/code/uilib/uiwidget.cpp @@ -610,7 +610,11 @@ UIReggedMaterial::UIReggedMaterial() uihandle_t UIReggedMaterial::GetMaterial() { - ReregisterMaterial(); + if ( !isGot ) + { + isGot = true; + this->hMat = uii.Rend_RegisterMaterial(name.c_str()); + } return hMat; } @@ -620,9 +624,7 @@ void UIReggedMaterial::ReregisterMaterial ) { - if( !isGot ) - { - isGot = true; + if( isGot ) { this->hMat = uii.Rend_RegisterMaterial( name.c_str() ); } } @@ -2468,8 +2470,6 @@ void UIWidget::Display col[3] = m_foreground_color.a * m_local_alpha; uii.Rend_SetColor( col ); - m_material->ReregisterMaterial(); - if( m_flags & WF_TILESHADER ) { if (m_bVirtual) { @@ -2489,12 +2489,10 @@ void UIWidget::Display if( m_pressedmaterial_active && m_pressedmaterial != NULL ) { - m_pressedmaterial->ReregisterMaterial(); uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_pressedmaterial->GetMaterial() ); } else if( m_hovermaterial_active && m_hovermaterial != NULL ) { - m_hovermaterial->ReregisterMaterial(); uii.Rend_DrawPicStretched( 0, 0, m_frame.size.width, m_frame.size.height, 0, 0, 1, 1, m_hovermaterial->GetMaterial() ); } diff --git a/code/uilib/uiwinman.cpp b/code/uilib/uiwinman.cpp index 116e1f4e..6adf321c 100644 --- a/code/uilib/uiwinman.cpp +++ b/code/uilib/uiwinman.cpp @@ -256,8 +256,6 @@ void UIWindowManager::UpdateViews(void) set2D(); uii.Rend_SetColor(col); - m_cursor->ReregisterMaterial(); - uii.Rend_DrawPicStretched(uid.mouseX, uid.mouseY, 0, 0, 0, 0, 1, 1, m_cursor->GetMaterial()); m_font->setColor(UWhite); @@ -667,7 +665,7 @@ void UIWindowManager::RefreshShadersFromList(void) num = m_materiallist.NumObjects(); for (i = 1; i <= num; i++) { UIReggedMaterial *regged = m_materiallist.ObjectAt(i); - regged->RefreshMaterial(); + regged->ReregisterMaterial(); } } From 5af8e127f82c1571fe057d22c98b6efb89382172 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:04:08 +0200 Subject: [PATCH 0558/2040] Added NULL sound flag --- code/client/snd_local_new.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index d6771244..19ebcc60 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -150,6 +150,7 @@ enum sfx_flags_t { SFX_FLAG_MP3 = 2, SFX_FLAG_STREAMED = 4, SFX_FLAG_NO_OFFSET = 8, + SFX_FLAG_NULL = 16, }; enum loopsound_flags_t { From bf4780bbdbd5578fd831e5fc9dcde75a69ee76ac Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:49:11 +0200 Subject: [PATCH 0559/2040] From now, load streamed sound into memory as deferred loading is currently unsupported --- code/client/snd_mem_new.cpp | 51 +++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/code/client/snd_mem_new.cpp b/code/client/snd_mem_new.cpp index c3f18744..e6aea697 100644 --- a/code/client/snd_mem_new.cpp +++ b/code/client/snd_mem_new.cpp @@ -416,8 +416,11 @@ DownSampleWav_MILES */ int DownSampleWav_MILES(wavinfo_t *info, byte *wav, int wavlength, int newkhz, byte **newdata) { - STUB_DESC("sound stuff"); - return 0; + //STUB_DESC("sound stuff"); + //return 0; + // FIXME: unimplemented + // Fallback to software downsampling + return DownSampleWav(info, wav, wavlength, newkhz, newdata); } /* @@ -438,6 +441,25 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo return qfalse; } + // Removed because of OpenAL + /* + if (streamed) { + // + // Added in 2.0 + // Will be loaded next time + sfx->length = 5000; + sfx->width = 1; + sfx->iFlags |= SFX_FLAG_STREAMED; + sfx->time_length = 5000.0; + sfx->data = 0; + return qtrue; + } + */ + + if (clc.state != CA_LOADING && !force_load) { + Com_Printf("**************S_LoadSound: %s\n", fileName); + } + if (strstr(fileName, ".mp3")) { return S_LoadMP3(fileName, sfx); } @@ -457,7 +479,7 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo FS_FCloseFile(file_handle); sfx->info = GetWavinfo(fileName, sfx->data, size); - if (sfx->info.channels != 1) + if (sfx->info.channels != 1 && !streamed) { Com_Printf("%s is a stereo wav file\n", fileName); Z_Free(sfx->data); @@ -469,14 +491,17 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo sfx->iFlags |= SFX_FLAG_NO_OFFSET; } - realKhz = 11025; - - if (s_khz->integer != 11) - { + switch (s_khz->integer) { + case 11: + realKhz = 11025; + break; + case 22: + default: realKhz = 22050; - if (s_khz->integer == 44) { - realKhz = 44100; - } + break; + case 44: + realKhz = 44100; + break; } if (!(sfx->iFlags & SFX_FLAG_STREAMED) && realKhz < sfx->info.rate) { @@ -507,6 +532,12 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo sprintf(tempName, "k%s", fileName); UI_LoadResource(tempName); + + if (strstr(fileName, "sound/null.wav")) { + sfx->iFlags |= SFX_FLAG_NULL; + return qtrue; + } + return qtrue; } From 31d254cb9f6d93e35dd2ee26237723caa7fa1bd3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:43:19 +0200 Subject: [PATCH 0560/2040] Use ceil() and set the delta appropriately if time1 is after team2 --- code/skeletor/skeletor.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 0987e17a..11bbc144 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -102,8 +102,8 @@ SkelVec3 skelAnimDataGameHeader_s::GetDeltaOverTime(float time1, float time2) deltaWeight1 = time1 / frameTime; deltaWeight2 = time2 / frameTime; - frameNum1 = (int)(deltaWeight1 + 1.0); - frameNum2 = (int)(deltaWeight2 + 1.0); + frameNum1 = ceil(deltaWeight1); + frameNum2 = ceil(deltaWeight2); d = frameNum1 - deltaWeight1; s = 1.0 - (frameNum2 - deltaWeight2); @@ -115,14 +115,15 @@ SkelVec3 skelAnimDataGameHeader_s::GetDeltaOverTime(float time1, float time2) for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) { delta += m_frame[currFrame % numFrames].delta; } + + delta.x += m_frame[frameNum2 % numFrames].delta.x * s; + delta.y += m_frame[frameNum2 % numFrames].delta.y * s; + delta.z += m_frame[frameNum2 % numFrames].delta.z * s; } else { s = s - (1.0 - d); + delta = m_frame[frameNum2 % numFrames].delta; } - delta.x += m_frame[frameNum2 % numFrames].delta.x * s; - delta.y += m_frame[frameNum2 % numFrames].delta.y * s; - delta.z += m_frame[frameNum2 % numFrames].delta.z * s; - if (delta.x > -0.001f && delta.x < 0.001f) { delta.x = 0; } @@ -148,25 +149,26 @@ float skelAnimDataGameHeader_s::GetAngularDeltaOverTime(float time1, float time2 deltaWeight1 = time1 / frameTime; deltaWeight2 = time2 / frameTime; - frameNum1 = (int)(deltaWeight1 + 1.0); - frameNum2 = (int)(deltaWeight2 + 1.0); + frameNum1 = ceil(deltaWeight1); + frameNum2 = ceil(deltaWeight2); d = frameNum1 - deltaWeight1; s = 1.0 - (frameNum2 - deltaWeight2); delta = 0; - if (frameNum2 > frameNum1) { + if (frameNum1 < frameNum2) { delta = m_frame[frameNum1 % numFrames].angleDelta; for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) { delta += m_frame[currFrame % numFrames].angleDelta; } + + delta += m_frame[frameNum2 % numFrames].angleDelta * s; } else { s = s - (1.0 - d); + delta = m_frame[frameNum2 % numFrames].angleDelta; } - delta += m_frame[frameNum2 % numFrames].angleDelta * s; - if (delta > -0.001f && delta < 0.001f) { delta = 0; } From 1b35d3ce056a2679757d237fbddbd88538658b21 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:43:46 +0200 Subject: [PATCH 0561/2040] Fix angular delta being wrong This fixes animated characters being sometimes badly positioned, like actors in the plane in t1l1 --- code/skeletor/skeletor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 11bbc144..62aca4fe 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -157,7 +157,7 @@ float skelAnimDataGameHeader_s::GetAngularDeltaOverTime(float time1, float time2 delta = 0; if (frameNum1 < frameNum2) { - delta = m_frame[frameNum1 % numFrames].angleDelta; + delta = m_frame[frameNum1 % numFrames].angleDelta * d; for (currFrame = frameNum1 + 1; currFrame < frameNum2; currFrame++) { delta += m_frame[currFrame % numFrames].angleDelta; From dcb0369e10553cca5bf71778d52e1649b66a4bb5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 26 Jul 2024 21:55:17 +0200 Subject: [PATCH 0562/2040] Fix actions deprecation warnings --- .github/workflows/build-cmake.yml | 10 +++++----- .github/workflows/publish-release.yml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 2628b791..782bcb6c 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -59,7 +59,7 @@ jobs: -DCMAKE_C_FLAGS=--target=${{ matrix.architecture.triple }} -DCMAKE_CXX_FLAGS=--target=${{ matrix.architecture.triple }}" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: 'source' @@ -99,7 +99,7 @@ jobs: cmake --install ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} cp '${{steps.sdl.outputs.prefix}}/lib/libSDL2.so' '${{github.workspace}}/install' - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: out-linux-${{matrix.architecture.name}} if-no-files-found: error @@ -142,7 +142,7 @@ jobs: cmake --build winflexbison-build --config Release --parallel cmake --install winflexbison-build - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: 'source' @@ -181,7 +181,7 @@ jobs: cmake --install ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} Copy-Item '${{steps.sdl.outputs.prefix}}/bin/*.dll' -Destination '${{github.workspace}}/install' - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: out-windows-${{matrix.architecture.name}} if-no-files-found: error @@ -189,7 +189,7 @@ jobs: ${{github.workspace}}/install !${{github.workspace}}/install/**/*.pdb - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: out-windows-${{matrix.architecture.name}}-pdb if-no-files-found: error diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 81b35639..af685159 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -46,7 +46,7 @@ jobs: RELEASE_NAME: ${{ github.event.repository.name }}-${{github.ref_name}}-${{matrix.target_os}} steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: 'out-${{matrix.target_os}}' path: ${{github.workspace}}/${{matrix.target_os}} @@ -56,7 +56,7 @@ jobs: run: zip -r ../${{ env.RELEASE_NAME }}.zip ./ - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: name: '${{github.ref_name}}-${{env.RELEASE_TYPE}}' prerelease: ${{env.RELEASE_IS_PRERELEASE}} From 769d06b0f0b683bdf6461af0deece8c8a622c62f Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Wed, 15 May 2024 15:14:52 -0700 Subject: [PATCH 0563/2040] Use nanosleep(2) instead of usleep(3) usleep(3) was declared obsolete in POSIX.1-2001 and removed in POSIX.1-2008 and nanosleep(2) was recommended to be used instead. --- code/autoupdater/autoupdater.c | 5 ++++- code/sys/sys_unix.c | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/code/autoupdater/autoupdater.c b/code/autoupdater/autoupdater.c index 4a052027..e013a1f4 100644 --- a/code/autoupdater/autoupdater.c +++ b/code/autoupdater/autoupdater.c @@ -933,10 +933,13 @@ static void waitToApplyUpdates(void) OS forcibly closes the pipe), we will unblock. Then we can loop on kill() until the process is truly gone. */ int x = 0; + struct timespec req; + req.tv_sec = 0; + req.tv_nsec = 100000000; read(3, &x, sizeof (x)); info("Pipe has closed, waiting for process to fully go away now."); while (kill(options.waitforprocess, 0) == 0) { - usleep(100000); + nanosleep(&req, NULL); } #endif } diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c index 42b5f1b5..cbbc0f6d 100644 --- a/code/sys/sys_unix.c +++ b/code/sys/sys_unix.c @@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include qboolean stdinIsATTY; @@ -550,11 +551,15 @@ void Sys_Sleep( int msec ) } else { + struct timespec req; + // With nothing to select() on, we can't wait indefinitely if( msec < 0 ) msec = 10; - usleep( msec * 1000 ); + req.tv_sec = msec/1000; + req.tv_nsec = (msec%1000)*1000000; + nanosleep(&req, NULL); } } From 2d15696a5eab8d3cb263659eb61173dd6e91c9d9 Mon Sep 17 00:00:00 2001 From: James Darpinian Date: Fri, 7 Jun 2024 08:27:37 -0700 Subject: [PATCH 0564/2040] Add .vscode and baseq3 to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f5adba0c..642e22a5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ Makefile.local *.swp *tags *~ +/.vscode/ +/baseq3 # OS X #################### From ee514710c5446154c0440a2b8a2bce7a4c7798d3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 26 Jul 2024 23:57:35 +0200 Subject: [PATCH 0565/2040] Add Emscripten implementation from ioquake3 upstream --- code/qcommon/q_platform.h | 16 ++++ code/sdl/sdl_glimp.c | 141 ++++++++++++++++++++++++++---------- code/web/client-config.json | 47 ++++++++++++ code/web/client.html | 116 +++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 40 deletions(-) create mode 100644 code/web/client-config.json create mode 100644 code/web/client.html diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index bc4960c5..a47f6739 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -355,6 +355,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif +//================================================================== EMSCRIPTEN === + +#ifdef __EMSCRIPTEN__ + +#define OS_STRING "emscripten" +#define ID_INLINE inline +#define PATH_SEP '/' + +#define ARCH_STRING "wasm32" + +#define Q3_LITTLE_ENDIAN + +#define DLL_EXT ".wasm" + +#endif + //================================================================== Q3VM === #ifdef Q3_VM diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index 528f3a06..af653d70 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -52,6 +52,7 @@ cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obta cvar_t *r_allowResize; // make window resizable cvar_t *r_centerWindow; cvar_t *r_sdlDriver; +cvar_t *r_useOpenGLES; int qglMajorVersion, qglMinorVersion; int qglesMajorVersion, qglesMinorVersion; @@ -230,6 +231,27 @@ static void GLimp_DetectAvailableModes(void) SDL_free( modes ); } +/* +=============== +OpenGL ES compatibility +=============== +*/ +static void APIENTRY GLimp_GLES_ClearDepth( GLclampd depth ) { + qglClearDepthf( depth ); +} + +static void APIENTRY GLimp_GLES_DepthRange( GLclampd near_val, GLclampd far_val ) { + qglDepthRangef( near_val, far_val ); +} + +static void APIENTRY GLimp_GLES_DrawBuffer( GLenum mode ) { + // unsupported +} + +static void APIENTRY GLimp_GLES_PolygonMode( GLenum face, GLenum mode ) { + // unsupported +} + /* =============== GLimp_GetProcAddresses @@ -293,6 +315,7 @@ static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) { } else { Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 1.1 is required", version ); } + // Add compression-related GL functions for the renderer if ( QGL_VERSION_ATLEAST( 1, 3 ) ) { QGL_1_3_PROCS; } @@ -309,8 +332,11 @@ static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) { QGL_1_3_PROCS; QGL_1_5_PROCS; QGL_2_0_PROCS; - // error so this doesn't segfault due to NULL desktop GL functions being used - Com_Error( ERR_FATAL, "Unsupported OpenGL Version: %s", version ); + + qglClearDepth = GLimp_GLES_ClearDepth; + qglDepthRange = GLimp_GLES_DepthRange; + qglDrawBuffer = GLimp_GLES_DrawBuffer; + qglPolygonMode = GLimp_GLES_PolygonMode; } else { Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 2.0 is required", version ); } @@ -636,57 +662,91 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool if (!fixedFunction) { - int profileMask, majorVersion, minorVersion; - SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profileMask); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion); + int profileMask; - ri.Printf(PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n"); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - if ((SDL_glContext = SDL_GL_CreateContext(SDL_window)) == NULL) + SDL_GL_GetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, &profileMask ); + + if ( r_useOpenGLES->integer == 1 || ( r_useOpenGLES->integer == -1 && profileMask == SDL_GL_CONTEXT_PROFILE_ES ) ) { - ri.Printf(PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); - ri.Printf(PRINT_ALL, "Reverting to default context\n"); + ri.Printf( PRINT_ALL, "Trying to get an OpenGL ES 2.0 context\n" ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 ); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion); - } - else - { - const char *renderer; - - ri.Printf(PRINT_ALL, "SDL_GL_CreateContext succeeded.\n"); - - if ( GLimp_GetProcAddresses( fixedFunction ) ) + SDL_glContext = SDL_GL_CreateContext( SDL_window ); + if ( !SDL_glContext ) { - renderer = (const char *)qglGetString(GL_RENDERER); + ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() ); } else { - ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL 3.2 core context\n" ); - renderer = NULL; - } + ri.Printf( PRINT_ALL, "SDL_GL_CreateContext succeeded.\n" ); - if (!renderer || (strstr(renderer, "Software Renderer") || strstr(renderer, "Software Rasterizer"))) + if ( !GLimp_GetProcAddresses( fixedFunction ) ) + { + ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL ES 2.0 context\n" ); + GLimp_ClearProcAddresses(); + SDL_GL_DeleteContext( SDL_glContext ); + SDL_glContext = NULL; + } + } + } + + if ( !SDL_glContext ) + { + ri.Printf( PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n" ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); + + SDL_glContext = SDL_GL_CreateContext( SDL_window ); + if ( !SDL_glContext ) { - if ( renderer ) - ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer); - - GLimp_ClearProcAddresses(); - SDL_GL_DeleteContext(SDL_glContext); - SDL_glContext = NULL; - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion); + ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() ); } + else + { + const char *renderer; + + ri.Printf( PRINT_ALL, "SDL_GL_CreateContext succeeded.\n" ); + + if ( GLimp_GetProcAddresses( fixedFunction ) ) + { + renderer = (const char *)qglGetString( GL_RENDERER ); + } + else + { + ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL 3.2 core context\n" ); + renderer = NULL; + } + + if ( !renderer || strstr( renderer, "Software Renderer" ) || strstr( renderer, "Software Rasterizer" ) ) + { + if ( renderer ) + ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer); + + GLimp_ClearProcAddresses(); + SDL_GL_DeleteContext( SDL_glContext ); + SDL_glContext = NULL; + } + } + } + + if ( !SDL_glContext ) + { + ri.Printf( PRINT_ALL, "Trying to get an OpenGL 2.0 context\n" ); + + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, 0 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 ); } } else { + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, 0 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 1 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 ); + SDL_glContext = NULL; } @@ -818,7 +878,7 @@ static void GLimp_InitExtensions( qboolean fixedFunction ) glConfig.textureCompression = TC_NONE; // GL_EXT_texture_compression_s3tc - if ( SDL_GL_ExtensionSupported( "GL_ARB_texture_compression" ) && + if ( ( QGLES_VERSION_ATLEAST( 2, 0 ) || SDL_GL_ExtensionSupported( "GL_ARB_texture_compression" ) ) && SDL_GL_ExtensionSupported( "GL_EXT_texture_compression_s3tc" ) ) { if ( r_ext_compressed_textures->value ) @@ -999,6 +1059,7 @@ void GLimp_Init( qboolean fixedFunction ) r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_useOpenGLES = ri.Cvar_Get( "r_useOpenGLES", "-1", CVAR_ARCHIVE | CVAR_LATCH ); if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) ) { diff --git a/code/web/client-config.json b/code/web/client-config.json new file mode 100644 index 00000000..eddf35db --- /dev/null +++ b/code/web/client-config.json @@ -0,0 +1,47 @@ +{ + "baseq3": { + "files": [ + {"src": "baseq3/pak0.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak1.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak2.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak3.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak4.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak5.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak6.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak7.pk3", "dst": "/baseq3"}, + {"src": "baseq3/pak8.pk3", "dst": "/baseq3"}, + {"src": "baseq3/vm/cgame.qvm", "dst": "/baseq3/vm"}, + {"src": "baseq3/vm/qagame.qvm", "dst": "/baseq3/vm"}, + {"src": "baseq3/vm/ui.qvm", "dst": "/baseq3/vm"} + ] + }, + "missionpack": { + "files": [ + {"src": "missionpack/pak0.pk3", "dst": "/missionpack"}, + {"src": "missionpack/pak1.pk3", "dst": "/missionpack"}, + {"src": "missionpack/pak2.pk3", "dst": "/missionpack"}, + {"src": "missionpack/pak3.pk3", "dst": "/missionpack"}, + {"src": "missionpack/vm/cgame.qvm", "dst": "/missionpack/vm"}, + {"src": "missionpack/vm/qagame.qvm", "dst": "/missionpack/vm"}, + {"src": "missionpack/vm/ui.qvm", "dst": "/missionpack/vm"} + ] + }, + "demoq3": { + "_comment": "Copy baseq3/vm/*.qvm to demoq3/vm/ as the Quake 3 demo QVMs are not compatible. However the botfiles are not fully compatible with newer QVMs.", + "files": [ + {"src": "demoq3/pak0.pk3", "dst": "/demoq3"}, + {"src": "demoq3/vm/cgame.qvm", "dst": "/demoq3/vm"}, + {"src": "demoq3/vm/qagame.qvm", "dst": "/demoq3/vm"}, + {"src": "demoq3/vm/ui.qvm", "dst": "/demoq3/vm"} + ] + }, + "tademo": { + "_comment": "Copy missionpack/vm/*.qvm to tademo/vm/ as the Team Arena demo QVMs are not compatible.", + "files": [ + {"src": "tademo/pak0.pk3", "dst": "/tademo"}, + {"src": "tademo/vm/cgame.qvm", "dst": "/tademo/vm"}, + {"src": "tademo/vm/qagame.qvm", "dst": "/tademo/vm"}, + {"src": "tademo/vm/ui.qvm", "dst": "/tademo/vm"} + ] + } +} diff --git a/code/web/client.html b/code/web/client.html new file mode 100644 index 00000000..3a23ab92 --- /dev/null +++ b/code/web/client.html @@ -0,0 +1,116 @@ + +__CLIENTBIN__ Emscripten demo + + + + + From 682dc8906770d632378793c5095e05101f04c0ce Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 17:54:48 +0200 Subject: [PATCH 0566/2040] Add ignorevelocity argument for `followpath` --- code/fgame/scriptslave.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 71b0f33b..924910eb 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1392,16 +1392,19 @@ void ScriptSlave::FollowPath(Event *ev) qboolean clamp; float starttime; - ent = ev->GetEntity(1); - argnum = 2; - starttime = -2; - clamp = true; - ignoreangles = false; - splineangles = true; + ent = ev->GetEntity(1); + argnum = 2; + starttime = -2; + clamp = true; + ignoreangles = false; + ignorevelocity = false; + splineangles = true; for (i = argnum; i <= ev->NumArgs(); i++) { token = ev->GetString(i); if (!Q_stricmp(token, "ignoreangles")) { ignoreangles = true; + } else if (!Q_stricmp(token, "ignorevelocity")) { + ignorevelocity = true; } else if (!Q_stricmp(token, "normalangles")) { splineangles = false; } else if (!Q_stricmp(token, "loop")) { @@ -1425,7 +1428,9 @@ void ScriptSlave::FollowPath(Event *ev) if (!ignoreangles) { avelocity = vec_zero; } - velocity = vec_zero; + if (!ignorevelocity) { + velocity = vec_zero; + } } } From 73c8ff11b3eb5ef22a94704be0bc732864ca7aa9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:03:41 +0200 Subject: [PATCH 0567/2040] Call CurrentScriptThread() to get the current script, so it can throw an exception if the current thread is NULL --- code/fgame/scriptslave.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 924910eb..6409b1a5 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -819,7 +819,7 @@ void ScriptSlave::DoMove(Event *ev) void ScriptSlave::WaitMove(Event *ev) { NewMove(); - Register(0, Director.CurrentThread()); + Register(0, Director.CurrentScriptThread()); } void ScriptSlave::MoveEnd(Event *ev) From 7b238e9d344d6b097d8f454878f21ac2fa983dc4 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:13:31 +0200 Subject: [PATCH 0568/2040] Set new orders appropriately --- code/fgame/scriptslave.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 6409b1a5..8cd45d16 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -772,10 +772,7 @@ void ScriptSlave::NewMove(void) BroadcastEvent(0, ev); } - if (m_pCurPath) { - PostEvent(EV_ScriptSlave_FollowingPath, 0); - } else if (splinePath) { - moving = true; + if (m_pCurPath || splinePath) { PostEvent(EV_ScriptSlave_FollowingPath, 0); } else { float t = traveltime; @@ -783,7 +780,6 @@ void ScriptSlave::NewMove(void) dist = Vector(NewPos - localorigin).length(); t = dist / speed; } - moving = true; LinearInterpolate(NewPos, NewAngles, t, EV_ScriptSlave_MoveDone); } } @@ -829,7 +825,7 @@ void ScriptSlave::MoveEnd(Event *ev) void ScriptSlave::SetAnglesEvent(Event *ev) { - commandswaiting = true; + CheckNewOrders(); SetAngles(ev); NewAngles = localangles; } @@ -904,7 +900,7 @@ void ScriptSlave::TriggerEvent(Event *ev) void ScriptSlave::GotoNextWaypoint(Event *ev) { - commandswaiting = true; + CheckNewOrders(); if (!waypoint) { ScriptError("%s is currently not at a waypoint", TargetName().c_str()); @@ -961,7 +957,7 @@ void ScriptSlave::JumpTo(Event *ev) void ScriptSlave::MoveToEvent(Event *ev) { - commandswaiting = true; + CheckNewOrders(); // // see if it is a vector @@ -1416,8 +1412,7 @@ void ScriptSlave::FollowPath(Event *ev) } } if (ent && ent->IsSubclassOfSplinePath()) { - commandswaiting = true; - path = (SplinePath *)ent; + path = (SplinePath *)ent; if (clamp) { CreatePath(path, SPLINE_CLAMP); } else { From fecb601fc4bb10485b66ad0ff261d28c1451622c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:17:10 +0200 Subject: [PATCH 0569/2040] Clear velocity only if it's not ignored --- code/fgame/scriptslave.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 8cd45d16..50f1297e 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -1442,7 +1442,9 @@ void ScriptSlave::EndPath(Event *ev) delete splinePath; splinePath = NULL; - velocity = vec_zero; + if (!ignorevelocity) { + velocity = vec_zero; + } if (!ignoreangles) { avelocity = vec_zero; } @@ -1639,7 +1641,9 @@ void ScriptSlave::FollowingPath(Event *ev) if ((splinePath->GetType() == SPLINE_CLAMP) && (splineTime > (splinePath->EndPoint() - 2))) { delete splinePath; splinePath = NULL; - velocity = vec_zero; + if (!ignorevelocity) { + velocity = vec_zero; + } if (!ignoreangles) { avelocity = vec_zero; } From 572e6652ccc8a8bfbbef7a1d07200c77b09cdb53 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:05:05 +0200 Subject: [PATCH 0570/2040] Fix `followpath` not working under special circumstances This fixes an issue where some planes (like the final bomber plane in t3l2) would not fly and look stuck --- code/fgame/scriptslave.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/code/fgame/scriptslave.cpp b/code/fgame/scriptslave.cpp index 50f1297e..847017e8 100644 --- a/code/fgame/scriptslave.cpp +++ b/code/fgame/scriptslave.cpp @@ -463,7 +463,7 @@ Event EV_ScriptSlave_FollowPath "eSSSSSS", "path arg1 arg2 arg3 arg4 arg5 arg6", "Makes the script slave follow the specified path. The allowable arguments are ignoreangles,\n" - "normalangles, loop, and a number specifying the start time.", + "ignorevelocity, normalangles, loop, and a number specifying the start time.", EV_NORMAL ); Event EV_ScriptSlave_FollowPath_RelativeYaw @@ -1407,6 +1407,17 @@ void ScriptSlave::FollowPath(Event *ev) clamp = false; } else if (IsNumeric(token)) { starttime = atof(token); + // Fixed in OPM + // HACKHACK + // + // There is a bug in mohaa where the token's raw pointer is directly used + // but then the token can be freed before comparison, which cause + // starttime to be always 0. + // OPM is correct here but for compatibility purpose the bug have to be reproduced. + // Otherwise, for example the final bomber plane in t3l2 will not fly. + if (!ev->IsStringAt(i)) { + starttime = 0; + } } else { ScriptError("Unknown followpath command %s.", token.c_str()); } From 0f48c39bc1620b04c836fe31091e1086cd81ac1f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:05:45 +0200 Subject: [PATCH 0571/2040] Add more resilience against null entity in `G_FixEntityPosition` --- code/fgame/g_phys.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/code/fgame/g_phys.cpp b/code/fgame/g_phys.cpp index 7e4314fb..80c4fe96 100644 --- a/code/fgame/g_phys.cpp +++ b/code/fgame/g_phys.cpp @@ -97,9 +97,14 @@ Entity *G_FixEntityPosition if( trace.startsolid ) { - //return g_entities->entity; - assert( trace.ent ); - assert( trace.ent->entity ); + if (!trace.ent) { + // Fixed in OPM + // I don't understand why they just prefer the game crashing + // rather than ignoring the entity + return NULL; + } + //assert( trace.ent ); + //assert( trace.ent->entity ); return trace.ent->entity; } From 44c17409a7b552bf197b6044de9c745b86cd5107 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:33:39 +0200 Subject: [PATCH 0572/2040] Allow pain if the player dies --- code/fgame/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index 98b681f4..b6806302 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -3357,7 +3357,7 @@ void Player::Pain(Event *ev) pain_location = iLocation; // Only set the regular pain level if enough time since last pain has passed - if ((level.time > nextpaintime) && take_pain) { + if (((level.time > nextpaintime) && take_pain) || IsDead()) { pain = damage; } From af432e6d3f51300534a37e785b7bd963fcac7988 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:37:05 +0200 Subject: [PATCH 0573/2040] Allow pain if the current time is above the allowed next pain time --- code/fgame/player_conditionals.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player_conditionals.cpp b/code/fgame/player_conditionals.cpp index 4c2d5d93..3c61fc69 100644 --- a/code/fgame/player_conditionals.cpp +++ b/code/fgame/player_conditionals.cpp @@ -95,7 +95,7 @@ qboolean Player::CondBlocked(Conditional& condition) qboolean Player::CondPain(Conditional& condition) { - return (pain != 0 || knockdown != 0); + return pain != 0 && level.time > nextpaintime; } qboolean Player::CondOnGround(Conditional& condition) From 6b89ec615a2fdf3331d491dc793a3bd69a8fdb10 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:45:11 +0200 Subject: [PATCH 0574/2040] Set damage angles only for mohaa 1.0-1.11 --- code/fgame/player.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index b6806302..c0c689b0 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -6322,11 +6322,18 @@ void Player::DamageFeedback(void) // damage_blood = 0; - if (IsSubclassOfPlayer()) { - damage_count = 0; - damage_blood = 0; - damage_alpha = 0; - damage_angles = vec_zero; + if (g_target_game >= target_game_e::TG_MOHTA) { + // + // Added in 2.0 + // No more damage angles since MOHTA + // + + if (IsSubclassOfPlayer()) { + damage_count = 0; + damage_blood = 0; + damage_alpha = 0; + damage_angles = vec_zero; + } } } From ebfb6d1846ccc9c41a4a609540d97942d418126e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 23:20:30 +0200 Subject: [PATCH 0575/2040] Fix inwardsphere not being used This fixes emitters looking incorrect, like `animate/adamspark.tik`, for the explosion of electric panels --- code/cgame/cg_tempmodels.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/cgame/cg_tempmodels.cpp b/code/cgame/cg_tempmodels.cpp index fae4fd55..d02722b4 100644 --- a/code/cgame/cg_tempmodels.cpp +++ b/code/cgame/cg_tempmodels.cpp @@ -1146,7 +1146,7 @@ void ClientGameCommandManager::SpawnTempModel(int mcount) newForward = p->cgd.origin - m_spawnthing->cgd.origin; newForward.normalize(); } - } else if (m_spawnthing->cgd.flags & T_SPHERE) { + } else if (m_spawnthing->cgd.flags & T_INWARDSPHERE) { // Project the origin along a random ray, and set the forward // vector pointing back to the origin Vector dir, end; From 864ea083939b055bd3db35cea02277ada0d4f012 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 27 Jul 2024 23:41:12 +0200 Subject: [PATCH 0576/2040] Fix special characters not being handled properly This fixes characters (signed character below 0) being replaced by '?' in UI text elements, like in the console --- code/uilib/uifont.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/code/uilib/uifont.cpp b/code/uilib/uifont.cpp index 89192f2b..9f2fc2ad 100644 --- a/code/uilib/uifont.cpp +++ b/code/uilib/uifont.cpp @@ -182,7 +182,7 @@ int UIFont::DBCSGetWordBlockCount(const char *text, int maxlen) return 0; } - uch = text[0]; + uch = (unsigned char)text[0]; p = (unsigned char *)(text + 1); if (!text[0]) { @@ -201,6 +201,7 @@ int UIFont::DBCSGetWordBlockCount(const char *text, int maxlen) isATokin = DBCSIsAtokin(uch); hasDBCS = DBCSLen > 1; isControl = uch < ' '; + uch2 = (unsigned char)*p; for (;;) { unsigned int subDBCSLen; @@ -671,7 +672,7 @@ int UI_FontStringMaxWidth(fontheader_t *pFont, const char *pszString, int iMaxLe } for (int i = 0; pszString[i] && (iMaxLen == -1 || i < iMaxLen); i++) { - unsigned short uch = pszString[i]; + unsigned short uch = (unsigned char)pszString[i]; if (UI_FontDBCSIsLeadByte(pFont, uch)) { uch = (uch << 8) | pszString[i]; @@ -706,7 +707,7 @@ int UI_FontStringWidth(fontheader_t *pFont, const char *pszString, int iMaxLen) } for (int i = 0; pszString[i] && (iMaxLen == -1 || i < iMaxLen); i++) { - unsigned short uch = pszString[i]; + unsigned short uch = (unsigned char)pszString[i]; if (UI_FontDBCSIsLeadByte(pFont, uch)) { uch = (uch << 8) | pszString[i]; From c7a4e705cb4b164451568c4e480081e75c3c9c3b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jul 2024 16:36:31 +0200 Subject: [PATCH 0577/2040] Fix libmad still producing shared libraries --- code/client/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index efb871d9..cfc2c676 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -36,10 +36,10 @@ if (USE_SOUND_NEW) list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) set(OLD_VALUE ${BUILD_SHARED_LIBS}) - set(BUILD_SHARED_LIBS OFF) - add_subdirectory("../libmad" "./libmad") - set(BUILD_SHARED_LIBS ${OLD_VALUE}) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + add_subdirectory("../libmad" "./libmad" EXCLUDE_FROM_ALL) target_link_libraries(omohclient INTERFACE mad) + set(BUILD_SHARED_LIBS ${OLD_VALUE} CACHE BOOL "" FORCE) else() add_subdirectory("../libmad-0.15.1b" "./libmad") target_link_libraries(omohclient INTERFACE libmad) From 5159a534bbec04cc7060f156058fe5fac5335ab9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jul 2024 19:01:34 +0200 Subject: [PATCH 0578/2040] Fix animated images playing at the same time for all entities --- code/renderer/tr_backend.c | 11 +---------- code/renderer/tr_shade.c | 18 +++++++++++------- code/renderer/tr_shader.c | 2 ++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 373ed828..e94f3bee 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -791,10 +791,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { backEnd.currentStaticModel = NULL; if (entityNum != ENTITYNUM_WORLD) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; - // we have to reset the shaderTime as well otherwise image animations start - // from the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; + backEnd.shaderStartTime = backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori); @@ -811,12 +808,8 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } else { backEnd.currentEntity = &tr.worldEntity; - backEnd.refdef.floatTime = originalTime; backEnd.ori = backEnd.viewParms.world; backEnd.shaderStartTime = 0.0; - // we have to reset the shaderTime as well otherwise image animations on - // the world (like water) continue with the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori); } } @@ -903,8 +896,6 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } - backEnd.refdef.floatTime = originalTime; - // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); diff --git a/code/renderer/tr_shade.c b/code/renderer/tr_shade.c index 2a4f7c60..dd201143 100644 --- a/code/renderer/tr_shade.c +++ b/code/renderer/tr_shade.c @@ -215,24 +215,28 @@ R_BindAnimatedImage ================= */ static void R_BindAnimatedImage( textureBundle_t *bundle ) { - int index; + int index; - if ( bundle->numImageAnimations <= 1 ) { - GL_Bind( bundle->image[0] ); + if (bundle->numImageAnimations <= 1) { + GL_Bind(bundle->image[0]); return; } // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency - index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); + index = myftol((tess.shaderTime + bundle->imageAnimationPhase) * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); index >>= FUNCTABLE_SIZE2; - if ( index < 0 ) { + if (index < 0) { index = 0; // may happen with shader time offsets } - index %= bundle->numImageAnimations; + if (!(bundle->flags & BUNDLE_ANIMATE_ONCE)) { + index %= bundle->numImageAnimations; + } else if (index >= bundle->numImageAnimations) { + index = bundle->numImageAnimations - 1; + } - GL_Bind( bundle->image[ index ] ); + GL_Bind(bundle->image[index]); } /* diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index e301f4fa..442a7f89 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -957,6 +957,8 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) { qboolean phased; + shader.flags |= 3; + if (!Q_stricmp(token, "animMapOnce")) { stage->bundle[cntBundle].flags |= BUNDLE_ANIMATE_ONCE; } From f213943b2d42a325c4ea000915334120b457cb63 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jul 2024 19:02:06 +0200 Subject: [PATCH 0579/2040] Fix RB_SetGL2D --- code/renderer/tr_backend.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index e94f3bee..3ba08d20 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -1014,27 +1014,7 @@ RB_SetGL2D ================ */ void RB_SetGL2D (void) { - backEnd.in2D = qtrue; - - // set 2D virtual screen size - qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1); - qglMatrixMode(GL_MODELVIEW); - qglLoadIdentity (); - - GL_State( GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - qglDisable( GL_CULL_FACE ); - qglDisable( GL_CLIP_PLANE0 ); - - // set time for 2D shaders - backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; + Set2DWindow(0, 0, glConfig.vidWidth, glConfig.vidHeight, 0.0, glConfig.vidWidth, glConfig.vidHeight, 0.0, 0.0, 1.0); } From c13f9dc9a8ef786dc935df6ff7c2525ea66c8b37 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jul 2024 19:12:08 +0200 Subject: [PATCH 0580/2040] Increase MAX_IMAGE_ANIMATIONS This fixes emitters not playing correctly --- code/renderer/tr_local.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 02d29a24..96affbf3 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -446,7 +446,7 @@ typedef struct { } texModInfo_t; -#define MAX_IMAGE_ANIMATIONS 8 +#define MAX_IMAGE_ANIMATIONS 64 #define BUNDLE_ANIMATE_ONCE 1 typedef struct { From 60e4fa7005e40dfc34fc5d9091ce4c54b797a06c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jul 2024 19:12:20 +0200 Subject: [PATCH 0581/2040] Handle shader picmip and fix shaders not rendered properly with force32bit (alpha channel was ignored) --- code/renderer/tr_image.c | 2 +- code/renderer/tr_shader.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 50013d6c..aa7389c6 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -608,7 +608,7 @@ static void Upload32( } else { - internalFormat = GL_RGB8; + internalFormat = GL_RGBA8; } } } else { diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index 442a7f89..50797274 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -790,7 +790,7 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) ParseStage =================== */ -static qboolean ParseStage(shaderStage_t* stage, char** text) +static qboolean ParseStage(shaderStage_t* stage, char** text, qboolean picmip) { char* token; int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0, colorBits = 0; @@ -884,7 +884,7 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) } else { - stage->bundle[cntBundle].image[0] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, GL_REPEAT, GL_REPEAT); + stage->bundle[cntBundle].image[0] = R_FindImageFile(token, !stage->noMipMaps, (!stage->noPicMip ? picmip : 0), stage->force32bit, GL_REPEAT, GL_REPEAT); if (!stage->bundle[cntBundle].image[0]) { ri.Printf(PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name); @@ -943,7 +943,7 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) return qfalse; } - stage->bundle[cntBundle].image[0] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, clampx, clampy); + stage->bundle[cntBundle].image[0] = R_FindImageFile(token, !stage->noMipMaps, (!stage->noPicMip ? picmip : 0), stage->force32bit, clampx, clampy); if (!stage->bundle[cntBundle].image[0]) { ri.Printf(PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name); @@ -995,7 +995,7 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) } num = stage->bundle[cntBundle].numImageAnimations; if ( num < MAX_IMAGE_ANIMATIONS ) { - stage->bundle[cntBundle].image[num] = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, qfalse, GL_REPEAT, GL_REPEAT ); + stage->bundle[cntBundle].image[num] = R_FindImageFile(token, !stage->noMipMaps, (!stage->noPicMip ? picmip : 0), stage->force32bit, GL_REPEAT, GL_REPEAT ); if ( !stage->bundle[cntBundle].image[num] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); @@ -1018,7 +1018,7 @@ static qboolean ParseStage(shaderStage_t* stage, char** text) return qfalse; } - stage->normalMap = R_FindImageFile(token, !stage->noMipMaps, !stage->noPicMip, stage->force32bit, GL_REPEAT, GL_REPEAT); + stage->normalMap = R_FindImageFile(token, !stage->noMipMaps, (!stage->noPicMip ? picmip : 0), stage->force32bit, GL_REPEAT, GL_REPEAT); if (!stage->normalMap) { ri.Printf(PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name); @@ -2143,7 +2143,7 @@ shader. Parse it into the global shader variable. Later functions will optimize it. ================= */ -static qboolean ParseShader( char **text ) +static qboolean ParseShader( char **text, qboolean picmip ) { char *token; int s; @@ -2174,7 +2174,7 @@ static qboolean ParseShader( char **text ) // stage definition else if ( token[0] == '{' ) { - if ( !ParseStage( &unfoggedStages[s], text ) ) + if ( !ParseStage( &unfoggedStages[s], text, picmip ) ) { return qfalse; } @@ -2262,7 +2262,7 @@ static qboolean ParseShader( char **text ) shader_noPicMip = qtrue; continue; } - // no picmip adjustment + // force 32 bit images else if (!Q_stricmp(token, "force32bit")) { shader_force32bit = qtrue; @@ -3225,7 +3225,7 @@ shader_t* R_FindShader(const char* name, int lightmapIndex, qboolean mipRawImage ri.Printf( PRINT_ALL, "*SHADER* %s\n", name ); } - if ( !ParseShader( &shaderText ) ) { + if ( !ParseShader( &shaderText, picmip ) ) { // had errors, so use default shader shader.defaultShader = qtrue; } From f804476fbccea4c7e84cfb1a1130b92f7c7c5427 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 28 Jul 2024 19:55:08 +0200 Subject: [PATCH 0582/2040] Add soft-oal to the build --- .github/workflows/build-cmake.yml | 56 ++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 782bcb6c..417d4e8f 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -41,7 +41,7 @@ jobs: - name: Install required packages run: | - sudo apt update && sudo apt install -y flex bison + sudo apt update && sudo apt install -y flex bison libopenal-dev - name: Install required cross-platform packages (${{ matrix.architecture.triple }}) if: matrix.architecture.name != 'amd64' @@ -59,6 +59,26 @@ jobs: -DCMAKE_C_FLAGS=--target=${{ matrix.architecture.triple }} -DCMAKE_CXX_FLAGS=--target=${{ matrix.architecture.triple }}" + # soft-oal setup + # Use GCC instead of Clang because of missing SSE intrinsics + # It also doesn't enable altivec support on PowerPC by default + - name: Checkout soft-oal + uses: actions/checkout@v4 + with: + repository: 'kcat/openal-soft' + path: 'thirdparties/soft-oal' + ref: '1.23.1' + + - name: Configure and install soft-oal + working-directory: ${{github.workspace}}/thirdparties/soft-oal + run: | + cmake -B ./build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -DCMAKE_INSTALL_PREFIX='${{github.workspace}}/thirdparties/soft-oal/install' \ + -DCMAKE_C_COMPILER=${{ matrix.architecture.triple }}-gcc-12 \ + -DCMAKE_CXX_COMPILER=${{ matrix.architecture.triple }}-g++-12 + cmake --build ./build --config ${{env.BUILD_TYPE}} + cmake --install ./build --config ${{env.BUILD_TYPE}} + - uses: actions/checkout@v4 with: path: 'source' @@ -72,12 +92,14 @@ jobs: -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_FLAGS=--target=${{ matrix.architecture.triple }} \ -DCMAKE_CXX_FLAGS=--target=${{ matrix.architecture.triple }} \ + -DOPENAL_LIBRARY='${{github.workspace}}/thirdparties/soft-oal' \ + -DOPENAL_INCLUDE_DIR='${{github.workspace}}/thirdparties/soft-oal/include' \ -DGIT_REVISION_BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV - name: Configure CMake working-directory: ${{github.workspace}} run: | - cmake -B ./build ${{ env.CMAKE_PARAM }} ./source + cmake -B ./build ${{ env.CMAKE_PARAM }} -DUSE_SOUND_NEW=1 ./source - name: Build working-directory: ${{github.workspace}} @@ -97,7 +119,9 @@ jobs: # Install to the directory defined in CMAKE_INSTALL_PREFIX run: | cmake --install ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - cp '${{steps.sdl.outputs.prefix}}/lib/libSDL2.so' '${{github.workspace}}/install' + # Create hard-link and copy symbolic links + cp -l ${{steps.sdl.outputs.prefix}}/lib/libSDL2-2.0.so.0 '${{github.workspace}}/install/' + cp -l ${{github.workspace}}/thirdparties/soft-oal/install/lib/libopenal.so.1 '${{github.workspace}}/install/' - uses: actions/upload-artifact@v4 with: @@ -124,7 +148,7 @@ jobs: run: | echo "CMAKE_BUILD_PARALLEL_LEVEL=$((Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors * 16)" >> $GITHUB_ENV - # Setup SDL + # Setup SDL - name: Set up SDL id: sdl uses: libsdl-org/setup-sdl@main @@ -142,6 +166,25 @@ jobs: cmake --build winflexbison-build --config Release --parallel cmake --install winflexbison-build + # soft-oal setup + - name: Checkout soft-oal + uses: actions/checkout@v4 + with: + repository: 'kcat/openal-soft' + path: 'thirdparties/soft-oal' + ref: '1.23.1' + + - name: Configure and install soft-oal + working-directory: ${{github.workspace}}/thirdparties/soft-oal + run: | + cmake -B ./build -A ${{ matrix.architecture.config }} ` + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ` + -DCMAKE_INSTALL_PREFIX='${{github.workspace}}/thirdparties/soft-oal/install' + cmake --build ./build --config ${{env.BUILD_TYPE}} + cmake --install ./build --config ${{env.BUILD_TYPE}} + # Unfortunately soft-oal produces a binary called OpenAL32 even in 64-bit + if ([Environment]::Is64BitOperatingSystem) { Rename-Item -Path '.\install\bin\OpenAL32.dll' -NewName 'OpenAL64.dll' } + - uses: actions/checkout@v4 with: path: 'source' @@ -154,12 +197,14 @@ jobs: -DCMAKE_INSTALL_PREFIX='${{github.workspace}}/install' ` -DGIT_REVISION_BUILD_NUMBER=${{ github.run_number }} ` -DBISON_EXECUTABLE='${{github.workspace}}/thirdparties/winflexbison-install/win_bison.exe' ` + -DOPENAL_LIBRARY='${{github.workspace}}/thirdparties/soft-oal' ` + -DOPENAL_INCLUDE_DIR='${{github.workspace}}/thirdparties/soft-oal/include' ` -DFLEX_EXECUTABLE='${{github.workspace}}/thirdparties/winflexbison-install/win_flex.exe'".Replace("`r", "").Replace("`n", "") >> $env:GITHUB_ENV - name: Configure CMake working-directory: ${{github.workspace}} run: | - cmake -B ./build ${{ env.CMAKE_PARAM }} ./source + cmake -B ./build ${{ env.CMAKE_PARAM }} -DUSE_SOUND_NEW=1 ./source - name: Build working-directory: ${{github.workspace}} @@ -180,6 +225,7 @@ jobs: run: | cmake --install ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} Copy-Item '${{steps.sdl.outputs.prefix}}/bin/*.dll' -Destination '${{github.workspace}}/install' + Copy-Item '${{github.workspace}}/thirdparties/soft-oal/install/bin/*.dll' -Destination '${{github.workspace}}/install' - uses: actions/upload-artifact@v4 with: From 391450f090ee9f5ada437b7c76f6ee3d57548b01 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:03:26 +0200 Subject: [PATCH 0583/2040] Swap bsp header on big-endian architectures See #332 where the lump's offset and length are incorrect on big-endian architectures --- code/renderer/tr_bsp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 3d42dd44..9fdf726a 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -2247,11 +2247,14 @@ void RE_LoadWorldMap( const char *name ) { } ri.FS_Read(&header, sizeof(dheader_t), h); + + for (i=0 ; i Date: Mon, 29 Jul 2024 19:04:29 +0200 Subject: [PATCH 0584/2040] R_UnpackTerraPatch: no need to get little-endian values as values are already swapped by R_SwapTerraPatch See #332 --- code/renderer/tr_bsp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 9fdf726a..09345bd4 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -493,31 +493,31 @@ void R_UnpackTerraPatch(cTerraPatch_t* pPacked, cTerraPatchUnpacked_t* pUnpacked for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { - pUnpacked->texCoord[i][j][0] = LittleFloat(pPacked->texCoord[i][j][0]); - pUnpacked->texCoord[i][j][1] = LittleFloat(pPacked->texCoord[i][j][1]); + pUnpacked->texCoord[i][j][0] = pPacked->texCoord[i][j][0]; + pUnpacked->texCoord[i][j][1] = pPacked->texCoord[i][j][1]; } } pUnpacked->x0 = ((int)pPacked->x << 6); pUnpacked->y0 = ((int)pPacked->y << 6); - pUnpacked->z0 = LittleShort(pPacked->iBaseHeight); - pUnpacked->shader = ShaderForShaderNum(LittleShort(pPacked->iShader), LittleShort(pPacked->iLightMap)); - pUnpacked->iNorth = LittleShort(pPacked->iNorth); - pUnpacked->iEast = LittleShort(pPacked->iEast); - pUnpacked->iSouth = LittleShort(pPacked->iSouth); - pUnpacked->iWest = LittleShort(pPacked->iWest); + pUnpacked->z0 = pPacked->iBaseHeight; + pUnpacked->shader = ShaderForShaderNum(pPacked->iShader, pPacked->iLightMap); + pUnpacked->iNorth = pPacked->iNorth; + pUnpacked->iEast = pPacked->iEast; + pUnpacked->iSouth = pPacked->iSouth; + pUnpacked->iWest = pPacked->iWest; for (i = 0; i < 63; i++) { flags.v = pPacked->varTree[0][i].flags; flags.b[1] &= 7; - pUnpacked->varTree[0][i].fVariance = LittleShort(flags.v); - pUnpacked->varTree[0][i].s.flags = LittleShort(pPacked->varTree[0][i].flags) >> 12; + pUnpacked->varTree[0][i].fVariance = flags.v; + pUnpacked->varTree[0][i].s.flags = pPacked->varTree[0][i].flags >> 12; flags.v = pPacked->varTree[1][i].flags; flags.b[1] &= 7; - pUnpacked->varTree[1][i].fVariance = LittleShort(flags.v); - pUnpacked->varTree[1][i].s.flags = LittleShort(pPacked->varTree[1][i].flags) >> 12; + pUnpacked->varTree[1][i].fVariance = flags.v; + pUnpacked->varTree[1][i].s.flags = pPacked->varTree[1][i].flags >> 12; } for (i = 0; i < sizeof(pUnpacked->heightmap) / sizeof(pUnpacked->heightmap[0]); i++) { From 6e3f9596846cffead668afdaaa32dd92e9b61890 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jul 2024 20:32:21 +0200 Subject: [PATCH 0585/2040] Fix header version incorrectly parsed --- code/renderer/tr_bsp.c | 2252 ++++++++++++++++++++-------------------- 1 file changed, 1126 insertions(+), 1126 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 09345bd4..189fee7e 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -74,52 +74,52 @@ static int g_nTerraPatches; static void HSVtoRGB( float h, float s, float v, float rgb[3] ) { - int i; - float f; - float p, q, t; + int i; + float f; + float p, q, t; - h *= 5; + h *= 5; - i = floor( h ); - f = h - i; + i = floor( h ); + f = h - i; - p = v * ( 1 - s ); - q = v * ( 1 - s * f ); - t = v * ( 1 - s * ( 1 - f ) ); + p = v * ( 1 - s ); + q = v * ( 1 - s * f ); + t = v * ( 1 - s * ( 1 - f ) ); - switch ( i ) - { - case 0: - rgb[0] = v; - rgb[1] = t; - rgb[2] = p; - break; - case 1: - rgb[0] = q; - rgb[1] = v; - rgb[2] = p; - break; - case 2: - rgb[0] = p; - rgb[1] = v; - rgb[2] = t; - break; - case 3: - rgb[0] = p; - rgb[1] = q; - rgb[2] = v; - break; - case 4: - rgb[0] = t; - rgb[1] = p; - rgb[2] = v; - break; - case 5: - rgb[0] = v; - rgb[1] = p; - rgb[2] = q; - break; - } + switch ( i ) + { + case 0: + rgb[0] = v; + rgb[1] = t; + rgb[2] = p; + break; + case 1: + rgb[0] = q; + rgb[1] = v; + rgb[2] = p; + break; + case 2: + rgb[0] = p; + rgb[1] = v; + rgb[2] = t; + break; + case 3: + rgb[0] = p; + rgb[1] = q; + rgb[2] = v; + break; + case 4: + rgb[0] = t; + rgb[1] = p; + rgb[2] = v; + break; + case 5: + rgb[0] = v; + rgb[1] = p; + rgb[2] = q; + break; + } } /* @@ -129,27 +129,27 @@ R_ColorShiftLightingBytes =============== */ static void R_ColorShiftLightingBytes( byte in[3], byte out[3] ) { - int r, g, b; + int r, g, b; - // shift the data based on overbright range - r = in[0] << tr.overbrightShift; - g = in[1] << tr.overbrightShift; - b = in[2] << tr.overbrightShift; - - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; + // shift the data based on overbright range + r = in[0] << tr.overbrightShift; + g = in[1] << tr.overbrightShift; + b = in[2] << tr.overbrightShift; + + // normalize by color instead of saturating to white + if ( ( r | g | b ) > 255 ) { + int max; - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; - } + max = r > g ? r : g; + max = max > b ? max : b; + r = r * 255 / max; + g = g * 255 / max; + b = b * 255 / max; + } - out[0] = r; - out[1] = g; - out[2] = b; + out[0] = r; + out[1] = g; + out[2] = b; } /* @@ -159,28 +159,28 @@ R_ColorShiftLightingBytesAlpha =============== */ static void R_ColorShiftLightingBytesAlpha( byte in[4], byte out[4] ) { - int r, g, b; + int r, g, b; - // shift the data based on overbright range - r = in[0] << tr.overbrightShift; - g = in[1] << tr.overbrightShift; - b = in[2] << tr.overbrightShift; - - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; - } + // shift the data based on overbright range + r = in[0] << tr.overbrightShift; + g = in[1] << tr.overbrightShift; + b = in[2] << tr.overbrightShift; + + // normalize by color instead of saturating to white + if ( ( r | g | b ) > 255 ) { + int max; + + max = r > g ? r : g; + max = max > b ? max : b; + r = r * 255 / max; + g = g * 255 / max; + b = b * 255 / max; + } - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = in[3]; } /* @@ -191,12 +191,12 @@ R_LoadLightmaps */ #define LIGHTMAP_SIZE 128 static void R_LoadLightmaps(gamelump_t* l) { - byte *buf, *buf_p; - int len; - MAC_STATIC byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4]; - int i, j; - float maxIntensity = 0; - double sumIntensity = 0; + byte *buf, *buf_p; + int len; + MAC_STATIC byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4]; + int i, j; + float maxIntensity = 0; + double sumIntensity = 0; len = l->length; if (!len) { @@ -204,71 +204,71 @@ static void R_LoadLightmaps(gamelump_t* l) { } buf = l->buffer; - // we are about to upload textures - R_SyncRenderThread(); + // we are about to upload textures + R_SyncRenderThread(); - // create all the lightmaps - tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); + // create all the lightmaps + tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); - // if we are in r_vertexLight mode, we don't need the lightmaps at all - if ( r_vertexLight->integer ) { - return; - } + // if we are in r_vertexLight mode, we don't need the lightmaps at all + if ( r_vertexLight->integer ) { + return; + } - for ( i = 0 ; i < tr.numLightmaps ; i++ ) { - // expand the 24 bit on-disk to 32 bit - buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3; + for ( i = 0 ; i < tr.numLightmaps ; i++ ) { + // expand the 24 bit on-disk to 32 bit + buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3; - if ( r_lightmap->integer == 2 ) - { // color code by intensity as development tool (FIXME: check range) - for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) - { - float r = buf_p[j*3+0]; - float g = buf_p[j*3+1]; - float b = buf_p[j*3+2]; - float intensity; - float out[3]; + if ( r_lightmap->integer == 2 ) + { // color code by intensity as development tool (FIXME: check range) + for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) + { + float r = buf_p[j*3+0]; + float g = buf_p[j*3+1]; + float b = buf_p[j*3+2]; + float intensity; + float out[3]; - intensity = 0.33f * r + 0.685f * g + 0.063f * b; + intensity = 0.33f * r + 0.685f * g + 0.063f * b; - if ( intensity > 255 ) - intensity = 1.0f; - else - intensity /= 255.0f; + if ( intensity > 255 ) + intensity = 1.0f; + else + intensity /= 255.0f; - if ( intensity > maxIntensity ) - maxIntensity = intensity; + if ( intensity > maxIntensity ) + maxIntensity = intensity; - HSVtoRGB( intensity, 1.00, 0.50, out ); + HSVtoRGB( intensity, 1.00, 0.50, out ); - image[j*4+0] = out[0] * 255; - image[j*4+1] = out[1] * 255; - image[j*4+2] = out[2] * 255; - image[j*4+3] = 255; + image[j*4+0] = out[0] * 255; + image[j*4+1] = out[1] * 255; + image[j*4+2] = out[2] * 255; + image[j*4+3] = 255; - sumIntensity += intensity; - } - } else { - for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) { - R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); - image[j*4+3] = 255; - } - } - tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, - LIGHTMAP_SIZE, LIGHTMAP_SIZE, 0, 1, qfalse, qfalse, qfalse, qfalse, GL_CLAMP, GL_CLAMP); - } + sumIntensity += intensity; + } + } else { + for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) { + R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); + image[j*4+3] = 255; + } + } + tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, + LIGHTMAP_SIZE, LIGHTMAP_SIZE, 0, 1, qfalse, qfalse, qfalse, qfalse, GL_CLAMP, GL_CLAMP); + } - if ( r_lightmap->integer == 2 ) { - ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); - } + if ( r_lightmap->integer == 2 ) { + ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); + } - if (r_fastdlights->integer) { - s_worldData.lighting = NULL; - } - else { - s_worldData.lighting = ri.Hunk_Alloc(l->length, h_dontcare); - Com_Memcpy(s_worldData.lighting, l->buffer, l->length); - } + if (r_fastdlights->integer) { + s_worldData.lighting = NULL; + } + else { + s_worldData.lighting = ri.Hunk_Alloc(l->length, h_dontcare); + Com_Memcpy(s_worldData.lighting, l->buffer, l->length); + } } @@ -281,7 +281,7 @@ space in big maps... ================= */ void RE_SetWorldVisData( const byte *vis ) { - tr.externalVisData = vis; + tr.externalVisData = vis; } @@ -291,12 +291,12 @@ R_LoadVisibility ================= */ static void R_LoadVisibility(gamelump_t* l) { - int len; - byte *buf; + int len; + byte *buf; - len = ( s_worldData.numClusters + 63 ) & ~63; - s_worldData.novis = ri.Hunk_Alloc( len, h_dontcare ); - Com_Memset( s_worldData.novis, 0xff, len ); + len = ( s_worldData.numClusters + 63 ) & ~63; + s_worldData.novis = ri.Hunk_Alloc( len, h_dontcare ); + Com_Memset( s_worldData.novis, 0xff, len ); len = l->length; if (!len) { @@ -304,20 +304,20 @@ static void R_LoadVisibility(gamelump_t* l) { } buf = l->buffer; - s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); - s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); + s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); + s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); - // CM_Load should have given us the vis data to share, so - // we don't need to allocate another copy - if ( tr.externalVisData ) { - s_worldData.vis = tr.externalVisData; - } else { - byte *dest; + // CM_Load should have given us the vis data to share, so + // we don't need to allocate another copy + if ( tr.externalVisData ) { + s_worldData.vis = tr.externalVisData; + } else { + byte *dest; - dest = ri.Hunk_Alloc( len - 8, h_dontcare ); - Com_Memcpy( dest, buf + 8, len - 8 ); - s_worldData.vis = dest; - } + dest = ri.Hunk_Alloc( len - 8, h_dontcare ); + Com_Memcpy( dest, buf + 8, len - 8 ); + s_worldData.vis = dest; + } } /* @@ -432,31 +432,31 @@ ShaderForShaderNum =============== */ static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { - shader_t *shader; - dshader_t *dsh; + shader_t *shader; + dshader_t *dsh; - shaderNum = LittleLong( shaderNum ); - if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) { - ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum ); - } - dsh = &s_worldData.shaders[ shaderNum ]; + shaderNum = LittleLong( shaderNum ); + if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) { + ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum ); + } + dsh = &s_worldData.shaders[ shaderNum ]; - if ( r_vertexLight->integer ) { - lightmapNum = LIGHTMAP_BY_VERTEX; - } + if ( r_vertexLight->integer ) { + lightmapNum = LIGHTMAP_BY_VERTEX; + } - if ( r_fullbright->integer || !tr.numLightmaps ) { - lightmapNum = LIGHTMAP_WHITEIMAGE; - } + if ( r_fullbright->integer || !tr.numLightmaps ) { + lightmapNum = LIGHTMAP_WHITEIMAGE; + } - shader = R_FindShader( dsh->shader, lightmapNum, qtrue, qtrue, qtrue, qtrue); + shader = R_FindShader( dsh->shader, lightmapNum, qtrue, qtrue, qtrue, qtrue); - // if the shader had errors, just use default shader - if ( shader->defaultShader ) { - return tr.defaultShader; - } + // if the shader had errors, just use default shader + if ( shader->defaultShader ) { + return tr.defaultShader; + } - return shader; + return shader; } /* @@ -465,11 +465,11 @@ R_UnpackTerraPatch ================ */ void R_UnpackTerraPatch(cTerraPatch_t* pPacked, cTerraPatchUnpacked_t* pUnpacked) { - int i, j; - union { - int16_t v; - uint8_t b[2]; - } flags; + int i, j; + union { + int16_t v; + uint8_t b[2]; + } flags; pUnpacked->byDirty = qfalse; pUnpacked->visCountCheck = 0; @@ -486,20 +486,20 @@ void R_UnpackTerraPatch(cTerraPatch_t* pPacked, cTerraPatchUnpacked_t* pUnpacked pUnpacked->t = ((float)pPacked->t + 0.5) / LIGHTMAP_SIZE; if( s_worldData.lighting ) { - pUnpacked->drawinfo.lmData = &s_worldData.lighting[pPacked->iLightMap * (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3) + 3 * pPacked->s + 3 * LIGHTMAP_SIZE * pPacked->t]; + pUnpacked->drawinfo.lmData = &s_worldData.lighting[pPacked->iLightMap * (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3) + 3 * pPacked->s + 3 * LIGHTMAP_SIZE * pPacked->t]; } else { - pUnpacked->drawinfo.lmData = NULL; + pUnpacked->drawinfo.lmData = NULL; } - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - pUnpacked->texCoord[i][j][0] = pPacked->texCoord[i][j][0]; - pUnpacked->texCoord[i][j][1] = pPacked->texCoord[i][j][1]; - } - } + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + pUnpacked->texCoord[i][j][0] = pPacked->texCoord[i][j][0]; + pUnpacked->texCoord[i][j][1] = pPacked->texCoord[i][j][1]; + } + } - pUnpacked->x0 = ((int)pPacked->x << 6); - pUnpacked->y0 = ((int)pPacked->y << 6); + pUnpacked->x0 = ((int)pPacked->x << 6); + pUnpacked->y0 = ((int)pPacked->y << 6); pUnpacked->z0 = pPacked->iBaseHeight; pUnpacked->shader = ShaderForShaderNum(pPacked->iShader, pPacked->iLightMap); pUnpacked->iNorth = pPacked->iNorth; @@ -508,21 +508,21 @@ void R_UnpackTerraPatch(cTerraPatch_t* pPacked, cTerraPatchUnpacked_t* pUnpacked pUnpacked->iWest = pPacked->iWest; for (i = 0; i < 63; i++) - { - flags.v = pPacked->varTree[0][i].flags; - flags.b[1] &= 7; - pUnpacked->varTree[0][i].fVariance = flags.v; - pUnpacked->varTree[0][i].s.flags = pPacked->varTree[0][i].flags >> 12; + { + flags.v = pPacked->varTree[0][i].flags; + flags.b[1] &= 7; + pUnpacked->varTree[0][i].fVariance = flags.v; + pUnpacked->varTree[0][i].s.flags = pPacked->varTree[0][i].flags >> 12; - flags.v = pPacked->varTree[1][i].flags; - flags.b[1] &= 7; - pUnpacked->varTree[1][i].fVariance = flags.v; - pUnpacked->varTree[1][i].s.flags = pPacked->varTree[1][i].flags >> 12; + flags.v = pPacked->varTree[1][i].flags; + flags.b[1] &= 7; + pUnpacked->varTree[1][i].fVariance = flags.v; + pUnpacked->varTree[1][i].s.flags = pPacked->varTree[1][i].flags >> 12; } - for (i = 0; i < sizeof(pUnpacked->heightmap) / sizeof(pUnpacked->heightmap[0]); i++) { - pUnpacked->heightmap[i] = pPacked->heightmap[i]; - } + for (i = 0; i < sizeof(pUnpacked->heightmap) / sizeof(pUnpacked->heightmap[0]); i++) { + pUnpacked->heightmap[i] = pPacked->heightmap[i]; + } pUnpacked->zmax = 0; pUnpacked->flags = pPacked->flags; @@ -566,7 +566,7 @@ void R_LoadTerrain(gamelump_t* lump) { out = s_worldData.terraPatches; for (i = 0; i < s_worldData.numTerraPatches; in++, out++, i++) { - R_SwapTerraPatch(in); + R_SwapTerraPatch(in); R_UnpackTerraPatch(in, out); } } @@ -608,109 +608,109 @@ ParseFace =============== */ static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - int i, j; - srfSurfaceFace_t *cv; - int numPoints, numIndexes; - int lightmapNum; + int i, j; + srfSurfaceFace_t *cv; + int numPoints, numIndexes; + int lightmapNum; int sfaceSize, ofsIndexes; static surfaceType_t skipData = SF_SKIP; - lightmapNum = LittleLong( ds->lightmapNum ); + lightmapNum = LittleLong( ds->lightmapNum ); - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } + // get shader value + surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } - if (surf->shader->surfaceFlags & SURF_NODRAW) { - // Nodraw surface doesn't need any processing - surf->data = &skipData; - return; - } + if (surf->shader->surfaceFlags & SURF_NODRAW) { + // Nodraw surface doesn't need any processing + surf->data = &skipData; + return; + } - numPoints = LittleLong( ds->numVerts ); - if (numPoints > MAX_FACE_POINTS) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints); + numPoints = LittleLong( ds->numVerts ); + if (numPoints > MAX_FACE_POINTS) { + ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints); numPoints = MAX_FACE_POINTS; surf->shader = tr.defaultShader; - } + } - numIndexes = LittleLong( ds->numIndexes ); + numIndexes = LittleLong( ds->numIndexes ); - // create the srfSurfaceFace_t - sfaceSize = ( int ) &((srfSurfaceFace_t *)0)->points[numPoints]; - ofsIndexes = sfaceSize; - sfaceSize += sizeof( int ) * numIndexes; + // create the srfSurfaceFace_t + sfaceSize = ( int ) &((srfSurfaceFace_t *)0)->points[numPoints]; + ofsIndexes = sfaceSize; + sfaceSize += sizeof( int ) * numIndexes; - cv = ri.Hunk_Alloc( sfaceSize, h_dontcare ); - cv->surfaceType = SF_FACE; - cv->numPoints = numPoints; - cv->numIndices = numIndexes; - cv->ofsIndices = ofsIndexes; + cv = ri.Hunk_Alloc( sfaceSize, h_dontcare ); + cv->surfaceType = SF_FACE; + cv->numPoints = numPoints; + cv->numIndices = numIndexes; + cv->ofsIndices = ofsIndexes; - verts += LittleLong( ds->firstVert ); - for ( i = 0 ; i < numPoints ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - cv->points[i][j] = LittleFloat( verts[i].xyz[j] ); - } - for ( j = 0 ; j < 2 ; j++ ) { - cv->points[i][3+j] = LittleFloat( verts[i].st[j] ); - cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] ); - } - R_ColorShiftLightingBytesAlpha( verts[i].color, (byte *)&cv->points[i][7] ); - } + verts += LittleLong( ds->firstVert ); + for ( i = 0 ; i < numPoints ; i++ ) { + for ( j = 0 ; j < 3 ; j++ ) { + cv->points[i][j] = LittleFloat( verts[i].xyz[j] ); + } + for ( j = 0 ; j < 2 ; j++ ) { + cv->points[i][3+j] = LittleFloat( verts[i].st[j] ); + cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] ); + } + R_ColorShiftLightingBytesAlpha( verts[i].color, (byte *)&cv->points[i][7] ); + } - indexes += LittleLong( ds->firstIndex ); - for ( i = 0 ; i < numIndexes ; i++ ) { - ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] ); - } + indexes += LittleLong( ds->firstIndex ); + for ( i = 0 ; i < numIndexes ; i++ ) { + ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] ); + } - // take the plane information from the lightmap vector - for ( i = 0 ; i < 3 ; i++ ) { - cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } - cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal ); - SetPlaneSignbits( &cv->plane ); - cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); + // take the plane information from the lightmap vector + for ( i = 0 ; i < 3 ; i++ ) { + cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); + } + cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal ); + SetPlaneSignbits( &cv->plane ); + cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); - if (tr.numLightmaps && lightmapNum != -1 && surf->shader->lightmapIndex >= 0) - { - float inv; + if (tr.numLightmaps && lightmapNum != -1 && surf->shader->lightmapIndex >= 0) + { + float inv; - cv->lmX = LittleLong(ds->lightmapX); - cv->lmY = LittleLong(ds->lightmapY); - cv->lmWidth = LittleLong(ds->lightmapWidth); - cv->lmHeight = LittleLong(ds->lightmapHeight); + cv->lmX = LittleLong(ds->lightmapX); + cv->lmY = LittleLong(ds->lightmapY); + cv->lmWidth = LittleLong(ds->lightmapWidth); + cv->lmHeight = LittleLong(ds->lightmapHeight); - if (s_worldData.lighting) { - cv->lmData = &s_worldData.lighting[lightmapNum * (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3) + 3 * cv->lmX + 3 * LIGHTMAP_SIZE * cv->lmY]; - } else { - cv->lmData = NULL; - } + if (s_worldData.lighting) { + cv->lmData = &s_worldData.lighting[lightmapNum * (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3) + 3 * cv->lmX + 3 * LIGHTMAP_SIZE * cv->lmY]; + } else { + cv->lmData = NULL; + } - for (i = 0; i < 3; i++) - { - cv->lmOrigin[i] = LittleFloat(ds->lightmapOrigin[i]); + for (i = 0; i < 3; i++) + { + cv->lmOrigin[i] = LittleFloat(ds->lightmapOrigin[i]); cv->lmVecs[0][i] = LittleFloat(ds->lightmapVecs[0][i]); cv->lmVecs[1][i] = LittleFloat(ds->lightmapVecs[1][i]); - } + } - inv = VectorNormalize2(cv->lmVecs[0], cv->lmInverseVecs[0]); - cv->lmInverseVecs[0][0] *= 1.0 / inv; - cv->lmInverseVecs[0][1] *= 1.0 / inv; - cv->lmInverseVecs[0][2] *= 1.0 / inv; + inv = VectorNormalize2(cv->lmVecs[0], cv->lmInverseVecs[0]); + cv->lmInverseVecs[0][0] *= 1.0 / inv; + cv->lmInverseVecs[0][1] *= 1.0 / inv; + cv->lmInverseVecs[0][2] *= 1.0 / inv; - inv = VectorNormalize2(cv->lmVecs[1], cv->lmInverseVecs[1]); - cv->lmInverseVecs[1][0] *= 1.0 / inv; - cv->lmInverseVecs[1][1] *= 1.0 / inv; - cv->lmInverseVecs[1][2] *= 1.0 / inv; - } - else - { - cv->lmData = NULL; - } - surf->data = (surfaceType_t *)cv; + inv = VectorNormalize2(cv->lmVecs[1], cv->lmInverseVecs[1]); + cv->lmInverseVecs[1][0] *= 1.0 / inv; + cv->lmInverseVecs[1][1] *= 1.0 / inv; + cv->lmInverseVecs[1][2] *= 1.0 / inv; + } + else + { + cv->lmData = NULL; + } + surf->data = (surfaceType_t *)cv; } @@ -720,84 +720,84 @@ ParseMesh =============== */ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { - srfGridMesh_t *grid; - int i, j; - int width, height, numPoints; - MAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; - int lightmapNum; - vec3_t bounds[2]; - vec3_t tmpVec; - static surfaceType_t skipData = SF_SKIP; + srfGridMesh_t *grid; + int i, j; + int width, height, numPoints; + MAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; + int lightmapNum; + vec3_t bounds[2]; + vec3_t tmpVec; + static surfaceType_t skipData = SF_SKIP; - lightmapNum = LittleLong( ds->lightmapNum ); + lightmapNum = LittleLong( ds->lightmapNum ); - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } + // get shader value + surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } - // we may have a nodraw surface, because they might still need to - // be around for movement clipping - if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { - surf->data = &skipData; - return; - } + // we may have a nodraw surface, because they might still need to + // be around for movement clipping + if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { + surf->data = &skipData; + return; + } - width = LittleLong( ds->patchWidth ); - height = LittleLong( ds->patchHeight ); + width = LittleLong( ds->patchWidth ); + height = LittleLong( ds->patchHeight ); - verts += LittleLong( ds->firstVert ); - numPoints = width * height; - for ( i = 0 ; i < numPoints ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - points[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); - points[i].normal[j] = LittleFloat( verts[i].normal[j] ); - } - for ( j = 0 ; j < 2 ; j++ ) { - points[i].st[j] = LittleFloat( verts[i].st[j] ); - points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); - } - R_ColorShiftLightingBytesAlpha( verts[i].color, points[i].color ); - } + verts += LittleLong( ds->firstVert ); + numPoints = width * height; + for ( i = 0 ; i < numPoints ; i++ ) { + for ( j = 0 ; j < 3 ; j++ ) { + points[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); + points[i].normal[j] = LittleFloat( verts[i].normal[j] ); + } + for ( j = 0 ; j < 2 ; j++ ) { + points[i].st[j] = LittleFloat( verts[i].st[j] ); + points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); + } + R_ColorShiftLightingBytesAlpha( verts[i].color, points[i].color ); + } // pre-tesseleate - if (ds->subdivisions) { - grid = R_SubdividePatchToGrid(width, height, ds->subdivisions * (r_subdivisions->value / 10.0), points); + if (ds->subdivisions) { + grid = R_SubdividePatchToGrid(width, height, ds->subdivisions * (r_subdivisions->value / 10.0), points); } else if (surf->shader->subdivisions) { grid = R_SubdividePatchToGrid(width, height, surf->shader->subdivisions * (r_subdivisions->value / 10.0), points); } else { grid = R_SubdividePatchToGrid(width, height, r_subdivisions->value, points); } - surf->data = (surfaceType_t *)grid; + surf->data = (surfaceType_t *)grid; - if (tr.numLightmaps && lightmapNum != -1 && surf->shader->lightmapIndex >= 0) - { - grid->lmX = LittleLong(ds->lightmapX); - grid->lmY = LittleLong(ds->lightmapY); - grid->lmWidth = LittleLong(ds->lightmapWidth); - grid->lmHeight = LittleLong(ds->lightmapHeight); - if (s_worldData.lighting) { - grid->lmData = &s_worldData.lighting[lightmapNum * (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3) + 3 * grid->lmX + 3 * LIGHTMAP_SIZE * grid->lmY]; - } else { - grid->lmData = NULL; - } - } + if (tr.numLightmaps && lightmapNum != -1 && surf->shader->lightmapIndex >= 0) + { + grid->lmX = LittleLong(ds->lightmapX); + grid->lmY = LittleLong(ds->lightmapY); + grid->lmWidth = LittleLong(ds->lightmapWidth); + grid->lmHeight = LittleLong(ds->lightmapHeight); + if (s_worldData.lighting) { + grid->lmData = &s_worldData.lighting[lightmapNum * (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3) + 3 * grid->lmX + 3 * LIGHTMAP_SIZE * grid->lmY]; + } else { + grid->lmData = NULL; + } + } - // copy the level of detail origin, which is the center - // of the group of all curves that must subdivide the same - // to avoid cracking - for ( i = 0 ; i < 3 ; i++ ) { - bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); - bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); - } - VectorAdd( bounds[0], bounds[1], bounds[1] ); - VectorScale( bounds[1], 0.5f, grid->lodOrigin ); - VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); - grid->lodRadius = VectorLength( tmpVec ); + // copy the level of detail origin, which is the center + // of the group of all curves that must subdivide the same + // to avoid cracking + for ( i = 0 ; i < 3 ; i++ ) { + bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); + bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); + } + VectorAdd( bounds[0], bounds[1], bounds[1] ); + VectorScale( bounds[1], 0.5f, grid->lodOrigin ); + VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); + grid->lodRadius = VectorLength( tmpVec ); } /* @@ -806,57 +806,57 @@ ParseTriSurf =============== */ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfTriangles_t *tri; - int i, j; - int numVerts, numIndexes; + srfTriangles_t *tri; + int i, j; + int numVerts, numIndexes; - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } + // get shader + surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } - numVerts = LittleLong( ds->numVerts ); - numIndexes = LittleLong( ds->numIndexes ); + numVerts = LittleLong( ds->numVerts ); + numIndexes = LittleLong( ds->numIndexes ); - tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) - + numIndexes * sizeof( tri->indexes[0] ), h_dontcare ); - tri->surfaceType = SF_TRIANGLES; - tri->numVerts = numVerts; - tri->numIndexes = numIndexes; - tri->verts = (drawVert_t *)(tri + 1); - tri->indexes = (int *)(tri->verts + tri->numVerts ); + tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) + + numIndexes * sizeof( tri->indexes[0] ), h_dontcare ); + tri->surfaceType = SF_TRIANGLES; + tri->numVerts = numVerts; + tri->numIndexes = numIndexes; + tri->verts = (drawVert_t *)(tri + 1); + tri->indexes = (int *)(tri->verts + tri->numVerts ); - surf->data = (surfaceType_t *)tri; + surf->data = (surfaceType_t *)tri; - // copy vertexes - ClearBounds( tri->bounds[0], tri->bounds[1] ); - verts += LittleLong( ds->firstVert ); - for ( i = 0 ; i < numVerts ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); - tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] ); - } - AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] ); - for ( j = 0 ; j < 2 ; j++ ) { - tri->verts[i].st[j] = LittleFloat( verts[i].st[j] ); - tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); - } + // copy vertexes + ClearBounds( tri->bounds[0], tri->bounds[1] ); + verts += LittleLong( ds->firstVert ); + for ( i = 0 ; i < numVerts ; i++ ) { + for ( j = 0 ; j < 3 ; j++ ) { + tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); + tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] ); + } + AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] ); + for ( j = 0 ; j < 2 ; j++ ) { + tri->verts[i].st[j] = LittleFloat( verts[i].st[j] ); + tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); + } - R_ColorShiftLightingBytesAlpha( verts[i].color, tri->verts[i].color ); - } + R_ColorShiftLightingBytesAlpha( verts[i].color, tri->verts[i].color ); + } - // copy indexes - indexes += LittleLong( ds->firstIndex ); - for ( i = 0 ; i < numIndexes ; i++ ) { - tri->indexes[i] = LittleLong( indexes[i] ); - if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) { - ri.Error( ERR_DROP, "Bad index in triangle surface" ); - } - } + // copy indexes + indexes += LittleLong( ds->firstIndex ); + for ( i = 0 ; i < numIndexes ; i++ ) { + tri->indexes[i] = LittleLong( indexes[i] ); + if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) { + ri.Error( ERR_DROP, "Bad index in triangle surface" ); + } + } } /* @@ -865,28 +865,28 @@ ParseFlare =============== */ static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfFlare_t *flare; - int i; + srfFlare_t *flare; + int i; - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } + // get shader + surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } - flare = ri.Hunk_Alloc( sizeof( *flare ), h_dontcare ); - flare->surfaceType = SF_FLARE; + flare = ri.Hunk_Alloc( sizeof( *flare ), h_dontcare ); + flare->surfaceType = SF_FLARE; - surf->data = (surfaceType_t *)flare; + surf->data = (surfaceType_t *)flare; - for ( i = 0 ; i < 3 ; i++ ) { - flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); - flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); - flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } + for ( i = 0 ; i < 3 ; i++ ) { + flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); + flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); + flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); + } } @@ -898,17 +898,17 @@ returns true if there are grid points merged on a width edge ================= */ int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) { - int i, j; + int i, j; - for (i = 1; i < grid->width-1; i++) { - for (j = i + 1; j < grid->width-1; j++) { - if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; + for (i = 1; i < grid->width-1; i++) { + for (j = i + 1; j < grid->width-1; j++) { + if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; + if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; + if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; + return qtrue; + } + } + return qfalse; } /* @@ -919,17 +919,17 @@ returns true if there are grid points merged on a height edge ================= */ int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) { - int i, j; + int i, j; - for (i = 1; i < grid->height-1; i++) { - for (j = i + 1; j < grid->height-1; j++) { - if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; + for (i = 1; i < grid->height-1; i++) { + for (j = i + 1; j < grid->height-1; j++) { + if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; + if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; + if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; + return qtrue; + } + } + return qfalse; } /* @@ -942,107 +942,107 @@ FIXME: write generalized version that also avoids cracks between a patch and one ================= */ void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) { - int j, k, l, m, n, offset1, offset2, touch; - srfGridMesh_t *grid2; + int j, k, l, m, n, offset1, offset2, touch; + srfGridMesh_t *grid2; - for ( j = start; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // if the LOD errors are already fixed for this patch - if ( grid2->lodFixed == 2 ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - touch = qfalse; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->width-1; k++) { - for (m = 0; m < 2; m++) { + for ( j = start; j < s_worldData.numsurfaces; j++ ) { + // + grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; + // if this surface is not a grid + if ( grid2->surfaceType != SF_GRID ) continue; + // if the LOD errors are already fixed for this patch + if ( grid2->lodFixed == 2 ) continue; + // grids in the same LOD group should have the exact same lod radius + if ( grid1->lodRadius != grid2->lodRadius ) continue; + // grids in the same LOD group should have the exact same lod origin + if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; + if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; + if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; + // + touch = qfalse; + for (n = 0; n < 2; n++) { + // + if (n) offset1 = (grid1->height-1) * grid1->width; + else offset1 = 0; + if (R_MergedWidthPoints(grid1, offset1)) continue; + for (k = 1; k < grid1->width-1; k++) { + for (m = 0; m < 2; m++) { - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + if (R_MergedWidthPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->width-1; l++) { + // + if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->widthLodError[l] = grid1->widthLodError[k]; + touch = qtrue; + } + } + for (m = 0; m < 2; m++) { - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->height-1; k++) { - for (m = 0; m < 2; m++) { + if (m) offset2 = grid2->width-1; + else offset2 = 0; + if (R_MergedHeightPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->height-1; l++) { + // + if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->heightLodError[l] = grid1->widthLodError[k]; + touch = qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = grid1->width-1; + else offset1 = 0; + if (R_MergedHeightPoints(grid1, offset1)) continue; + for (k = 1; k < grid1->height-1; k++) { + for (m = 0; m < 2; m++) { - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + if (R_MergedWidthPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->width-1; l++) { + // + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->widthLodError[l] = grid1->heightLodError[k]; + touch = qtrue; + } + } + for (m = 0; m < 2; m++) { - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - } - } - if (touch) { - grid2->lodFixed = 2; - R_FixSharedVertexLodError_r ( start, grid2 ); - //NOTE: this would be correct but makes things really slow - //grid2->lodFixed = 1; - } - } + if (m) offset2 = grid2->width-1; + else offset2 = 0; + if (R_MergedHeightPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->height-1; l++) { + // + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->heightLodError[l] = grid1->heightLodError[k]; + touch = qtrue; + } + } + } + } + if (touch) { + grid2->lodFixed = 2; + R_FixSharedVertexLodError_r ( start, grid2 ); + //NOTE: this would be correct but makes things really slow + //grid2->lodFixed = 1; + } + } } /* @@ -1054,23 +1054,23 @@ If this is not the case this function will still do its job but won't fix the hi ================= */ void R_FixSharedVertexLodError( void ) { - int i; - srfGridMesh_t *grid1; + int i; + srfGridMesh_t *grid1; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodFixed ) - continue; - // - grid1->lodFixed = 2; - // recursively fix other patches in the same LOD group - R_FixSharedVertexLodError_r( i + 1, grid1); - } + for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + // + grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; + // if this surface is not a grid + if ( grid1->surfaceType != SF_GRID ) + continue; + // + if ( grid1->lodFixed ) + continue; + // + grid1->lodFixed = 2; + // recursively fix other patches in the same LOD group + R_FixSharedVertexLodError_r( i + 1, grid1); + } } @@ -1080,405 +1080,405 @@ R_StitchPatches =============== */ int R_StitchPatches( int grid1num, int grid2num ) { - float *v1, *v2; - srfGridMesh_t *grid1, *grid2; - int k, l, m, n, offset1, offset2, row, column; + float *v1, *v2; + srfGridMesh_t *grid1, *grid2; + int k, l, m, n, offset1, offset2, row, column; - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->width-2; k += 2) { + grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; + grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data; + for (n = 0; n < 2; n++) { + // + if (n) offset1 = (grid1->height-1) * grid1->width; + else offset1 = 0; + if (R_MergedWidthPoints(grid1, offset1)) + continue; + for (k = 0; k < grid1->width-2; k += 2) { - for (m = 0; m < 2; m++) { + for (m = 0; m < 2; m++) { - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { + v1 = grid1->verts[k + 2 + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->height-2; k += 2) { - for (m = 0; m < 2; m++) { + v1 = grid1->verts[k + 2 + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = grid1->width-1; + else offset1 = 0; + if (R_MergedHeightPoints(grid1, offset1)) + continue; + for (k = 0; k < grid1->height-2; k += 2) { + for (m = 0; m < 2; m++) { - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { + v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[(l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = grid1->width-1; k > 1; k -= 2) { + v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = (grid1->height-1) * grid1->width; + else offset1 = 0; + if (R_MergedWidthPoints(grid1, offset1)) + continue; + for (k = grid1->width-1; k > 1; k -= 2) { - for (m = 0; m < 2; m++) { + for (m = 0; m < 2; m++) { - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { + v1 = grid1->verts[k - 2 + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[(l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - if (!grid2) - break; - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = grid1->height-1; k > 1; k -= 2) { - for (m = 0; m < 2; m++) { + v1 = grid1->verts[k - 2 + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); + if (!grid2) + break; + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = grid1->width-1; + else offset1 = 0; + if (R_MergedHeightPoints(grid1, offset1)) + continue; + for (k = grid1->height-1; k > 1; k -= 2) { + for (m = 0; m < 2; m++) { - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { + v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[(l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - return qfalse; + v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + return qfalse; } /* @@ -1495,29 +1495,29 @@ might still appear at that side. =============== */ int R_TryStitchingPatch( int grid1num ) { - int j, numstitches; - srfGridMesh_t *grid1, *grid2; + int j, numstitches; + srfGridMesh_t *grid1, *grid2; - numstitches = 0; - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - for ( j = 0; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - while (R_StitchPatches(grid1num, j)) - { - numstitches++; - } - } - return numstitches; + numstitches = 0; + grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; + for ( j = 0; j < s_worldData.numsurfaces; j++ ) { + // + grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; + // if this surface is not a grid + if ( grid2->surfaceType != SF_GRID ) continue; + // grids in the same LOD group should have the exact same lod radius + if ( grid1->lodRadius != grid2->lodRadius ) continue; + // grids in the same LOD group should have the exact same lod origin + if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; + if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; + if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; + // + while (R_StitchPatches(grid1num, j)) + { + numstitches++; + } + } + return numstitches; } /* @@ -1526,31 +1526,31 @@ R_StitchAllPatches =============== */ void R_StitchAllPatches( void ) { - int i, stitched, numstitches; - srfGridMesh_t *grid1; + int i, stitched, numstitches; + srfGridMesh_t *grid1; - numstitches = 0; - do - { - stitched = qfalse; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodStitched ) - continue; - // - grid1->lodStitched = qtrue; - stitched = qtrue; - // - numstitches += R_TryStitchingPatch( i ); - } - } - while (stitched); - ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); + numstitches = 0; + do + { + stitched = qfalse; + for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + // + grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; + // if this surface is not a grid + if ( grid1->surfaceType != SF_GRID ) + continue; + // + if ( grid1->lodStitched ) + continue; + // + grid1->lodStitched = qtrue; + stitched = qtrue; + // + numstitches += R_TryStitchingPatch( i ); + } + } + while (stitched); + ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); } /* @@ -1559,30 +1559,30 @@ R_MovePatchSurfacesToHunk =============== */ void R_MovePatchSurfacesToHunk(void) { - int i, size; - srfGridMesh_t *grid, *hunkgrid; + int i, size; + srfGridMesh_t *grid, *hunkgrid; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid->surfaceType != SF_GRID ) - continue; - // - size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); - hunkgrid = ri.Hunk_Alloc( size, h_dontcare ); - Com_Memcpy(hunkgrid, grid, size); + for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + // + grid = (srfGridMesh_t *) s_worldData.surfaces[i].data; + // if this surface is not a grid + if ( grid->surfaceType != SF_GRID ) + continue; + // + size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); + hunkgrid = ri.Hunk_Alloc( size, h_dontcare ); + Com_Memcpy(hunkgrid, grid, size); - hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_dontcare ); - Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); + hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_dontcare ); + Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); - hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_dontcare ); - Com_Memcpy( grid->heightLodError, grid->heightLodError, grid->height * 4 ); + hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_dontcare ); + Com_Memcpy( grid->heightLodError, grid->heightLodError, grid->height * 4 ); - R_FreeSurfaceGridMesh( grid ); + R_FreeSurfaceGridMesh( grid ); - s_worldData.surfaces[i].data = (void *) hunkgrid; - } + s_worldData.surfaces[i].data = (void *) hunkgrid; + } } /* @@ -1591,18 +1591,18 @@ R_LoadSurfaces =============== */ static void R_LoadSurfaces(gamelump_t* surfs, gamelump_t* verts, gamelump_t* indexLump) { - dsurface_t *in; - msurface_t *out; - drawVert_t *dv; - int *indexes; - int count; - int numFaces, numMeshes, numTriSurfs, numFlares; - int i; + dsurface_t *in; + msurface_t *out; + drawVert_t *dv; + int *indexes; + int count; + int numFaces, numMeshes, numTriSurfs, numFlares; + int i; - numFaces = 0; - numMeshes = 0; - numTriSurfs = 0; - numFlares = 0; + numFaces = 0; + numMeshes = 0; + numTriSurfs = 0; + numFlares = 0; if (surfs->length % sizeof(*in)) ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name); @@ -1617,46 +1617,46 @@ static void R_LoadSurfaces(gamelump_t* surfs, gamelump_t* verts, gamelump_t* ind ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name); in = (void*)surfs->buffer; - out = ri.Hunk_Alloc ( count * sizeof(*out), h_dontcare ); + out = ri.Hunk_Alloc ( count * sizeof(*out), h_dontcare ); - s_worldData.surfaces = out; - s_worldData.numsurfaces = count; + s_worldData.surfaces = out; + s_worldData.numsurfaces = count; - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - ParseMesh ( in, dv, out ); - numMeshes++; - break; - case MST_TRIANGLE_SOUP: - ParseTriSurf( in, dv, out, indexes ); - numTriSurfs++; - break; - case MST_PLANAR: - ParseFace( in, dv, out, indexes ); - numFaces++; - break; - case MST_FLARE: - ParseFlare( in, dv, out, indexes ); - numFlares++; - break; - default: - ri.Error( ERR_DROP, "Bad surfaceType" ); - } - } + for ( i = 0 ; i < count ; i++, in++, out++ ) { + switch ( LittleLong( in->surfaceType ) ) { + case MST_PATCH: + ParseMesh ( in, dv, out ); + numMeshes++; + break; + case MST_TRIANGLE_SOUP: + ParseTriSurf( in, dv, out, indexes ); + numTriSurfs++; + break; + case MST_PLANAR: + ParseFace( in, dv, out, indexes ); + numFaces++; + break; + case MST_FLARE: + ParseFlare( in, dv, out, indexes ); + numFlares++; + break; + default: + ri.Error( ERR_DROP, "Bad surfaceType" ); + } + } #ifdef PATCH_STITCHING - R_StitchAllPatches(); + R_StitchAllPatches(); #endif - R_FixSharedVertexLodError(); + R_FixSharedVertexLodError(); #ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(); + R_MovePatchSurfacesToHunk(); #endif - ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", - numFaces, numMeshes, numTriSurfs, numFlares ); + ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", + numFaces, numMeshes, numTriSurfs, numFlares ); } @@ -1667,36 +1667,36 @@ R_LoadSubmodels ================= */ static void R_LoadSubmodels(gamelump_t* l) { - dmodel_t *in; - bmodel_t *out; - int i, j, count; + dmodel_t *in; + bmodel_t *out; + int i, j, count; in = (void*)l->buffer; if (l->length % sizeof(*in)) ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name); count = l->length / sizeof(*in); - s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_dontcare ); + s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_dontcare ); - for ( i=0 ; itype = MOD_BRUSH; - model->d.bmodel = out; - Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); + model->type = MOD_BRUSH; + model->d.bmodel = out; + Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); - for (j=0 ; j<3 ; j++) { - out->bounds[0][j] = LittleFloat (in->mins[j]); - out->bounds[1][j] = LittleFloat (in->maxs[j]); - } + for (j=0 ; j<3 ; j++) { + out->bounds[0][j] = LittleFloat (in->mins[j]); + out->bounds[1][j] = LittleFloat (in->maxs[j]); + } - out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface ); - out->numSurfaces = LittleLong( in->numSurfaces ); - } + out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface ); + out->numSurfaces = LittleLong( in->numSurfaces ); + } } @@ -1710,11 +1710,11 @@ R_SetParent */ static void R_SetParent (mnode_t *node, mnode_t *parent) { - node->parent = parent; - if (node->contents != -1) - return; - R_SetParent (node->children[0], node); - R_SetParent (node->children[1], node); + node->parent = parent; + if (node->contents != -1) + return; + R_SetParent (node->children[0], node); + R_SetParent (node->children[1], node); } /* @@ -1978,72 +1978,72 @@ R_LoadLightGrid ================ */ void R_LoadLightGrid(gamelump_t* plPal, gamelump_t* plOffsets, gamelump_t* plData) { - int i; - vec3_t maxs; - int numGridPoints; - world_t *w; - float *wMins, *wMaxs; + int i; + vec3_t maxs; + int numGridPoints; + world_t *w; + float *wMins, *wMaxs; - w = &s_worldData; + w = &s_worldData; - if (!plPal->buffer || !plOffsets->buffer || !plData->buffer) { - ri.Printf(PRINT_WARNING, "WARNING: No light grid data present\n"); - w->lightGridOffsets = 0; - w->lightGridData = 0; - return; - } + if (!plPal->buffer || !plOffsets->buffer || !plData->buffer) { + ri.Printf(PRINT_WARNING, "WARNING: No light grid data present\n"); + w->lightGridOffsets = 0; + w->lightGridData = 0; + return; + } - switch (map_version) - { + switch (map_version) + { case 21: w->lightGridSize[0] = 80.0; w->lightGridSize[1] = 80.0; w->lightGridSize[2] = 80.0; - break; + break; case 20: w->lightGridSize[0] = 48.0; w->lightGridSize[1] = 48.0; w->lightGridSize[2] = 64.0; - break; + break; default: w->lightGridSize[0] = 32.0; w->lightGridSize[1] = 32.0; w->lightGridSize[2] = 32.0; - break; - } + break; + } - w->lightGridOOSize[0] = 1.0f / w->lightGridSize[0]; - w->lightGridOOSize[1] = 1.0f / w->lightGridSize[1]; - w->lightGridOOSize[2] = 1.0f / w->lightGridSize[2]; + w->lightGridOOSize[0] = 1.0f / w->lightGridSize[0]; + w->lightGridOOSize[1] = 1.0f / w->lightGridSize[1]; + w->lightGridOOSize[2] = 1.0f / w->lightGridSize[2]; - wMins = w->bmodels[0].bounds[0]; - wMaxs = w->bmodels[0].bounds[1]; + wMins = w->bmodels[0].bounds[0]; + wMaxs = w->bmodels[0].bounds[1]; - for ( i = 0 ; i < 3 ; i++ ) { - w->lightGridMins[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); - maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); - w->lightGridBounds[i] = (maxs[i] - w->lightGridMins[i])/w->lightGridSize[i] + 1; - } + for ( i = 0 ; i < 3 ; i++ ) { + w->lightGridMins[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); + maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); + w->lightGridBounds[i] = (maxs[i] - w->lightGridMins[i])/w->lightGridSize[i] + 1; + } - numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] + w->lightGridBounds[0]; + numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] + w->lightGridBounds[0]; if (plOffsets->length != numGridPoints * 2) { - ri.Printf(PRINT_WARNING, "WARNING: light grid offset size mismatch\n"); - w->lightGridOffsets = NULL; + ri.Printf(PRINT_WARNING, "WARNING: light grid offset size mismatch\n"); + w->lightGridOffsets = NULL; w->lightGridData = NULL; return; } - if (plPal->length != 768) { - ri.Printf(PRINT_WARNING, "WARNING: light grid palette size mismatch\n"); - w->lightGridOffsets = NULL; - w->lightGridData = NULL; - return; - } + if (plPal->length != 768) { + ri.Printf(PRINT_WARNING, "WARNING: light grid palette size mismatch\n"); + w->lightGridOffsets = NULL; + w->lightGridData = NULL; + return; + } - w->lightGridOffsets = ri.Hunk_Alloc(plOffsets->length, h_dontcare); - Com_Memcpy(w->lightGridOffsets, plOffsets->buffer, plOffsets->length); - Com_Memcpy(w->lightGridPalette, plPal->buffer, sizeof(s_worldData.lightGridPalette)); + w->lightGridOffsets = ri.Hunk_Alloc(plOffsets->length, h_dontcare); + Com_Memcpy(w->lightGridOffsets, plOffsets->buffer, plOffsets->length); + Com_Memcpy(w->lightGridPalette, plPal->buffer, sizeof(s_worldData.lightGridPalette)); w->lightGridData = ri.Hunk_Alloc(plData->length, h_dontcare); Com_Memcpy(w->lightGridData, plData->buffer, plData->length); @@ -2078,10 +2078,10 @@ void R_LoadStaticModelData(gamelump_t* lump) { for (i = 0; i < lump->length; i += sizeof(byte) * 3) { - // Colors are stored as integers - pDstColors[0] = pSrcColors[0]; - pDstColors[1] = pSrcColors[1]; - pDstColors[2] = pSrcColors[2]; + // Colors are stored as integers + pDstColors[0] = pSrcColors[0]; + pDstColors[1] = pSrcColors[1]; + pDstColors[2] = pSrcColors[2]; pDstColors[3] = 0xFF; pSrcColors += sizeof(byte) * 3; @@ -2096,12 +2096,12 @@ R_CopyStaticModel */ void R_CopyStaticModel(cStaticModel_t* pSM, cStaticModelUnpacked_t* pUnpackedSM) { pUnpackedSM->visCount = 0; - pUnpackedSM->angles[0] = LittleFloat(pSM->angles[0]); - pUnpackedSM->angles[1] = LittleFloat(pSM->angles[1]); - pUnpackedSM->angles[2] = LittleFloat(pSM->angles[2]); - pUnpackedSM->origin[0] = LittleFloat(pSM->origin[0]); - pUnpackedSM->origin[1] = LittleFloat(pSM->origin[1]); - pUnpackedSM->origin[2] = LittleFloat(pSM->origin[2]); + pUnpackedSM->angles[0] = LittleFloat(pSM->angles[0]); + pUnpackedSM->angles[1] = LittleFloat(pSM->angles[1]); + pUnpackedSM->angles[2] = LittleFloat(pSM->angles[2]); + pUnpackedSM->origin[0] = LittleFloat(pSM->origin[0]); + pUnpackedSM->origin[1] = LittleFloat(pSM->origin[1]); + pUnpackedSM->origin[2] = LittleFloat(pSM->origin[2]); pUnpackedSM->scale = LittleFloat(pSM->scale); pUnpackedSM->firstVertexData = LittleLong(pSM->firstVertexData) * sizeof(color4ub_t) / (sizeof(byte) * 3); pUnpackedSM->numVertexData = LittleLong(pSM->numVertexData); @@ -2220,25 +2220,25 @@ Called directly from cgame ================= */ void RE_LoadWorldMap( const char *name ) { - int i; + int i; dheader_t header; fileHandle_t h; int length; - vec3_t vDefSundir; + vec3_t vDefSundir; gamelump_t lump, lump2, lump3; vDefSundir[0] = 0.45f; vDefSundir[1] = 0.3f; vDefSundir[2] = 0.9f; - _R(52); + _R(52); - // set default sun direction to be used if it isn't - // overridden by a shader - VectorCopy(vDefSundir, tr.sunDirection); - VectorNormalize( tr.sunDirection ); + // set default sun direction to be used if it isn't + // overridden by a shader + VectorCopy(vDefSundir, tr.sunDirection); + VectorNormalize( tr.sunDirection ); - tr.worldMapLoaded = qtrue; + tr.worldMapLoaded = qtrue; // load it length = ri.FS_OpenFile(name, &h, qtrue, qtrue); @@ -2248,32 +2248,32 @@ void RE_LoadWorldMap( const char *name ) { ri.FS_Read(&header, sizeof(dheader_t), h); - for (i=0 ; i BSP_MAX_VERSION) { ri.Error(ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be between %i and %i)", name, i, BSP_MIN_VERSION, BSP_MAX_VERSION); } - // load into heap + // load into heap // load into heap _R(53); numShaders = R_LoadLump(h, &header.lumps[LUMP_SHADERS], &lump, sizeof(dshader_t)); @@ -2291,9 +2291,9 @@ void RE_LoadWorldMap( const char *name ) { _R(59); R_LoadLightmaps(&lump); _R(60); - R_FreeLump(&lump); - _R(61); - numDrawSurfaces = R_LoadLump(h, &header.lumps[LUMP_SURFACES], &lump, sizeof(dsurface_t)); + R_FreeLump(&lump); + _R(61); + numDrawSurfaces = R_LoadLump(h, &header.lumps[LUMP_SURFACES], &lump, sizeof(dsurface_t)); _R(62); numDrawVerts = R_LoadLump(h, &header.lumps[LUMP_DRAWVERTS], &lump2, sizeof(drawVert_t)); _R(63); @@ -2328,7 +2328,7 @@ void RE_LoadWorldMap( const char *name ) { _R(75); R_FreeLump(&lump2); _R(76); - numFogs = 0; + numFogs = 0; nummodels = R_LoadLump(h, &header.lumps[LUMP_MODELS], &lump, sizeof(bmodel_t)); _R(77); R_LoadSubmodels(&lump); @@ -2407,8 +2407,8 @@ void RE_LoadWorldMap( const char *name ) { g_nStaticModelIndices = 0; } - // only set tr.world now that we know the entire level has loaded properly - tr.world = &s_worldData; + // only set tr.world now that we know the entire level has loaded properly + tr.world = &s_worldData; ri.FS_CloseFile(h); From c7900b6048b7772cb1eafcf1e1c25791dc8a0f60 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:12:17 +0200 Subject: [PATCH 0586/2040] Fix static model index endianness --- code/renderer/tr_bsp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 189fee7e..2e56eac7 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -2145,8 +2145,8 @@ R_LoadStaticModelIndexes ================ */ void R_LoadStaticModelIndexes(gamelump_t* lump) { - int i; - short* in; + int i; + unsigned short* in; cStaticModelUnpacked_t** out; if (lump->length % sizeof(short)) { @@ -2160,7 +2160,13 @@ void R_LoadStaticModelIndexes(gamelump_t* lump) { out = s_worldData.visStaticModels; for (i = 0; i < s_worldData.numVisStaticModels; in++, out++, i++) { - *out = &s_worldData.staticModels[*in]; + unsigned short index = LittleUnsignedShort(*in); + if (index >= s_worldData.numStaticModels) { + // Added in OPM + Com_Error(ERR_DROP, "R_LoadStaticModelIndexes: bad static model index %d", index); + } + + *out = &s_worldData.staticModels[index]; } } From 1d4fe357c8c83039ee89628a95ad852040fd7121 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:39:24 +0200 Subject: [PATCH 0587/2040] Fix `ShaderForShaderNum` incorrectly swapping the shader num --- code/renderer/tr_bsp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 2e56eac7..39d3338e 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -435,7 +435,6 @@ static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { shader_t *shader; dshader_t *dsh; - shaderNum = LittleLong( shaderNum ); if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) { ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum ); } @@ -618,7 +617,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int lightmapNum = LittleLong( ds->lightmapNum ); // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); + surf->shader = ShaderForShaderNum(LittleLong(ds->shaderNum), lightmapNum); if ( r_singleShader->integer && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -735,7 +734,7 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { surf->fogIndex = LittleLong( ds->fogNum ) + 1; // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); + surf->shader = ShaderForShaderNum(LittleLong(ds->shaderNum), lightmapNum); if ( r_singleShader->integer && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -814,7 +813,7 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, i surf->fogIndex = LittleLong( ds->fogNum ) + 1; // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); + surf->shader = ShaderForShaderNum(LittleLong(ds->shaderNum), LIGHTMAP_BY_VERTEX); if ( r_singleShader->integer && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } @@ -872,7 +871,7 @@ static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int surf->fogIndex = LittleLong( ds->fogNum ) + 1; // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); + surf->shader = ShaderForShaderNum(LittleLong(ds->shaderNum), LIGHTMAP_BY_VERTEX); if ( r_singleShader->integer && !surf->shader->isSky ) { surf->shader = tr.defaultShader; } From f8b97405ffe608b02bca83ec54d90bb5a7223ee1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:59:27 +0200 Subject: [PATCH 0588/2040] Fix infinite loop in DownSampleWav when `s_khz` is less than 44 kHz This fixes #330 where `s_khz` below 44 (the usual sample rate of mohaa wav files) would cause an infinite loop due to improper usage of the `ii` variable in the loop where another variable would be accidentally incremented instead --- code/client/snd_mem_new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_mem_new.cpp b/code/client/snd_mem_new.cpp index e6aea697..ee9844db 100644 --- a/code/client/snd_mem_new.cpp +++ b/code/client/snd_mem_new.cpp @@ -396,7 +396,7 @@ qboolean DownSampleWav(wavinfo_t *info, byte *wav, int wavlength, int newkhz, by error += newkhz; while (error > oldrate) { error -= oldrate; - for (ii = 0; ii < width; i++) { + for (ii = 0; ii < width; ii++) { data_p[ii] = datap[ii]; } From 39b3ed3d4420089a4a8782640a6ef98331a002e8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 3 Aug 2024 18:37:02 +0200 Subject: [PATCH 0589/2040] Fix part blend mult being incorrectly archived This may have been the cause of animations not properly playing and the player being unable to climb on ladders --- code/fgame/player.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/player.h b/code/fgame/player.h index a67ece67..e93056a9 100644 --- a/code/fgame/player.h +++ b/code/fgame/player.h @@ -979,7 +979,7 @@ inline void Player::Archive(Archiver& arc) arc.ArchiveFloat(&m_fPartBlends[0]); arc.ArchiveFloat(&m_fPartBlends[1]); arc.ArchiveFloat(&partBlendMult[0]); - arc.ArchiveFloat(&partBlendMult[0]); + arc.ArchiveFloat(&partBlendMult[1]); arc.ArchiveString(&last_torso_anim_name); arc.ArchiveString(&last_leg_anim_name); From d5da32b8a901e403d0430a0eff3b9582547db70d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:43:40 +0200 Subject: [PATCH 0590/2040] Fix AI damage --- code/fgame/sentient.cpp | 116 +++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/code/fgame/sentient.cpp b/code/fgame/sentient.cpp index 900e6da7..ddffc88a 100644 --- a/code/fgame/sentient.cpp +++ b/code/fgame/sentient.cpp @@ -1354,24 +1354,22 @@ void Sentient::ArmorDamage(Event *ev) { Entity *inflictor; Sentient *attacker; - float damage; - Vector momentum; - Vector position; - Vector normal; - Vector direction; + float damage; + Vector momentum; + Vector position; + Vector normal; + Vector direction; Event *event; - int dflags; - int meansofdeath; - int knockback; - int location; + int dflags; + int meansofdeath; + int knockback; + int location; - /* - qboolean blocked; + //qboolean blocked; float damage_red; float damage_green; float damage_time; - qboolean set_means_of_death; -*/ + //qboolean set_means_of_death; static bool tmp = false; static cvar_t *AIDamageMult = NULL; @@ -1396,7 +1394,7 @@ void Sentient::ArmorDamage(Event *ev) meansofdeath = ev->GetInteger(9); location = CheckHitLocation(ev->GetInteger(10)); - if (location == -2) { + if (location == HITLOC_MISS) { return; } @@ -1404,12 +1402,10 @@ void Sentient::ArmorDamage(Event *ev) return; } - if ((client && !g_gametype->integer) || (location < 0 || location > 18)) { - if (attacker && attacker->IsSubclassOfActor()) { - damage *= AIDamageMult->value; - } - } else { + if ((!isClient() || g_gametype->integer != GT_SINGLE_PLAYER) && (location > HITLOC_GENERAL && location < NUMBODYLOCATIONS)) { damage *= m_fDamageMultipliers[location]; + } else if (isClient() && attacker && attacker->IsSubclassOfActor() && g_gametype->integer == GT_SINGLE_PLAYER) { + damage *= AIDamageMult->value; } // See if sentient is immune to this type of damage @@ -1471,34 +1467,6 @@ void Sentient::ArmorDamage(Event *ev) } */ - /* -if( meansofdeath == MOD_SLIME ) -{ - damage_green = damage / 50; - if( damage_green > 1.0f ) - damage_green = 1.0f; - if( ( damage_green < 0.2 ) && ( damage_green > 0 ) ) - damage_green = 0.2f; - damage_red = 0; -} -else -{ - damage_red = damage / 50; - if( damage_red > 1.0f ) - damage_red = 1.0f; - if( ( damage_red < 0.2 ) && ( damage_red > 0 ) ) - damage_red = 0.2f; - damage_green = 0; -} - -damage_time = damage / 50; - -if( damage_time > 2 ) - damage_time = 2; - -SetOffsetColor( damage_red, damage_green, 0, damage_time ); -*/ - // Do the kick if (!(dflags & DAMAGE_NO_KNOCKBACK)) { if ((knockback) && (movetype != MOVETYPE_NONE) && (movetype != MOVETYPE_STATIONARY) @@ -1506,14 +1474,14 @@ SetOffsetColor( damage_red, damage_green, 0, damage_time ); float m; Event *immunity_event; - if (mass < 50) { - m = 50; + if (mass < 20) { + m = 20; } else { m = mass; } direction.normalize(); - if (isClient() && (attacker == this) && g_gametype->integer) { + if (isClient() && (attacker == this) && deathmatch->integer) { momentum = direction * (1700.0f * (float)knockback / m); // the rocket jump hack... } else { momentum = direction * (500.0f * (float)knockback / m); @@ -1542,8 +1510,8 @@ SetOffsetColor( damage_red, damage_green, 0, damage_time ); } if (!(flags & FL_GODMODE) - && ((g_gametype->integer) || !(attacker) || (attacker) == this || !(attacker->IsSubclassOfPlayer()) - || !(attacker->IsTeamMate(this)))) { + && ((g_gametype->integer != GT_SINGLE_PLAYER) || !(attacker) || (attacker) == this || !(attacker->IsSubclassOfSentient()) + || (attacker->m_Team != m_Team))) { health -= damage; } @@ -1573,9 +1541,38 @@ SetOffsetColor( damage_red, damage_green, 0, damage_time ); } } - if (health > 0) { - // Send pain event - event = new Event(EV_Pain, 10); + if (meansofdeath == MOD_SLIME) + { + damage_green = damage / 50; + if (damage_green > 1.0f) + damage_green = 1.0f; + if ((damage_green < 0.2) && (damage_green > 0)) + damage_green = 0.2f; + damage_red = 0; + } + else + { + damage_red = damage / 50; + if (damage_red > 1.0f) + damage_red = 1.0f; + if ((damage_red < 0.2) && (damage_red > 0)) + damage_red = 0.2f; + damage_green = 0; + } + + damage_time = damage / 50; + + if (damage_time > 2) + damage_time = 2; + + //SetOffsetColor(damage_red, damage_green, 0, damage_time); + + if (health < 0.1) { + // Make sure health is now 0 + + health = 0; + + event = new Event(EV_Killed, 10); event->AddEntity(attacker); event->AddFloat(damage); event->AddEntity(inflictor); @@ -1590,12 +1587,9 @@ SetOffsetColor( damage_red, damage_green, 0, damage_time ); ProcessEvent(event); } - if (health < 0.1) { - // Make sure health is now 0 - - health = 0; - - event = new Event(EV_Killed, 10); + if (health > 0) { + // Send pain event + event = new Event(EV_Pain, 10); event->AddEntity(attacker); event->AddFloat(damage); event->AddEntity(inflictor); From 6b3402c631134eb6670df9248e9727d85609910e Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:43:56 +0200 Subject: [PATCH 0591/2040] Fix actor accuracy being crazy, killing the player easily --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index a1e213c0..65054c3f 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -10135,7 +10135,7 @@ Vector Actor::GunTarget(bool bNoCollision, const vec3_t position, const vec3_t f float fAccuracy, fCoverFactor; Vector aimDir; - fCoverFactor = mAccuracy * (1.0 - m_fVisibilityAlpha) * aiMinAccuracy->value + m_fVisibilityAlpha; + fCoverFactor = mAccuracy * ((1.0 - m_fVisibilityAlpha) * aiMinAccuracy->value + m_fVisibilityAlpha); if (doInit) { aiRanges[0] = gi.Cvar_Get("g_aishortrange", "500", 0); From a6d508d791e33ddac5665fe8483963748a896fbf Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:49:16 +0200 Subject: [PATCH 0592/2040] Fix sounds replaying when unpausing This caused some sounds to play again when saving --- code/client/snd_openal_new.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 7214807d..753a5cd2 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -965,6 +965,7 @@ void S_UnpauseSound() } if (pChannel->is_paused() || (pChannel->iFlags & CHANNEL_FLAG_PLAYABLE)) { + pChannel->iFlags &= ~CHANNEL_FLAG_PLAYABLE; pChannel->play(); } } From 9c5297882cb64bd53c648927e53737710ef66d86 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:49:41 +0200 Subject: [PATCH 0593/2040] Renamed CHANNEL_FLAG_PLAYABLE to CHANNEL_FLAG_PLAY_DEFERRED --- code/client/snd_local_new.h | 2 +- code/client/snd_openal_new.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/client/snd_local_new.h b/code/client/snd_local_new.h index 19ebcc60..ffeeb94b 100644 --- a/code/client/snd_local_new.h +++ b/code/client/snd_local_new.h @@ -138,7 +138,7 @@ typedef struct { } soundsystemsavegame_t; enum channel_flags_t { - CHANNEL_FLAG_PLAYABLE = 1, + CHANNEL_FLAG_PLAY_DEFERRED = 1, CHANNEL_FLAG_LOCAL_LISTENER = 16, CHANNEL_FLAG_NO_ENTITY = 32, CHANNEL_FLAG_PAUSED = 64, diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 753a5cd2..cc3faede 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -964,8 +964,8 @@ void S_UnpauseSound() continue; } - if (pChannel->is_paused() || (pChannel->iFlags & CHANNEL_FLAG_PLAYABLE)) { - pChannel->iFlags &= ~CHANNEL_FLAG_PLAYABLE; + if (pChannel->is_paused() || (pChannel->iFlags & CHANNEL_FLAG_PLAY_DEFERRED)) { + pChannel->iFlags &= ~CHANNEL_FLAG_PLAY_DEFERRED; pChannel->play(); } } @@ -1746,7 +1746,7 @@ static int S_OPENAL_Start2DLoopSound( if (!pChannel->set_sfx(pLoopSound->pSfx)) { Com_DPrintf("Set sample error\n"); - pChannel->iFlags &= ~CHANNEL_FLAG_PLAYABLE; + pChannel->iFlags &= ~CHANNEL_FLAG_PLAY_DEFERRED; return -1; } @@ -2585,7 +2585,7 @@ S_StartSoundFromBase(channelbasesavegame_t *pBase, openal_channel *pChannel, sfx { if (!pChannel->set_sfx(pSfx)) { Com_DPrintf("Set sample error - %s\n", pSfx->name); - pChannel->iFlags &= ~CHANNEL_FLAG_PLAYABLE; + pChannel->iFlags &= ~CHANNEL_FLAG_PLAY_DEFERRED; return; } @@ -2615,7 +2615,7 @@ S_StartSoundFromBase(channelbasesavegame_t *pBase, openal_channel *pChannel, sfx if (bStartUnpaused) { pChannel->resume_sample(); } else { - pChannel->iFlags |= CHANNEL_FLAG_PLAYABLE; + pChannel->iFlags |= CHANNEL_FLAG_PLAY_DEFERRED; } } From 279b1413ec3285cdf126f29b0d5ee99607331cc0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 19:09:29 +0200 Subject: [PATCH 0594/2040] Clear the active music when stopping the triggered music --- code/client/snd_openal_new.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index cc3faede..deb5e4de 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -4027,6 +4027,10 @@ void S_TriggeredMusic_Stop() } openal.chan_trig_music.stop(); + // Fixed in OPM + // Make sure to clear the triggered music in case snd_restart is called + openal.tm_filename[0] = 0; + openal.tm_loopcount = 0; } /* From 192f9ac5146cc12eae9575a80a4ef1b90a7f94b1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 19:14:30 +0200 Subject: [PATCH 0595/2040] Added S_CurrentSoundtrack() --- code/client/new/snd_main_new.cpp | 10 ++++++++++ code/client/new/snd_public_new.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index 9e3fbbbc..66fa6f1f 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -381,6 +381,16 @@ void MUSIC_CheckForStoppedSongs(void) STUB(); } +/* +============== +S_CurrentSoundtrack +============== +*/ +const char* S_CurrentSoundtrack() +{ + return ""; +} + /* ================= S_IsSoundRegistered diff --git a/code/client/new/snd_public_new.h b/code/client/new/snd_public_new.h index c945052a..30defc6a 100644 --- a/code/client/new/snd_public_new.h +++ b/code/client/new/snd_public_new.h @@ -68,6 +68,8 @@ void S_TriggeredMusic_Start(); void S_TriggeredMusic_StartLoop(); void S_TriggeredMusic_Stop(); +const char* S_CurrentSoundtrack(); + void S_StopSound(int entnum, int channel); void S_StopAllSounds2(qboolean stop_music); float S_GetSoundTime(sfxHandle_t handle); From 64f4f591651d31f7aa44838c56af3cfbd756e943 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 19:20:07 +0200 Subject: [PATCH 0596/2040] Fix `vid_restart` and `snd_restart` resetting the sound system (experimental sound system only) This fixes #335 where one of those commands would clear all active sounds as well as the triggered music, and the soundtrack --- code/client/cl_main.cpp | 55 +++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index f668bc43..825ea52c 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -1515,6 +1515,12 @@ because the renderer doesn't know what graphics to reload ================= */ void CL_Vid_Restart_f( void ) { + soundsystemsavegame_t save; + char tm_filename[MAX_RES_NAME]; + int tm_loopcount; + int tm_offset; + char current_soundtrack[128]; + if (!CL_Allowed_Vid_Restart()) { return; } @@ -1522,11 +1528,18 @@ void CL_Vid_Restart_f( void ) { Com_Printf("-------- CL_Vid_Restart_f --------\n"); cls.vid_restart = qtrue; - // don't let them loop during the restart - S_StopAllSounds2(qtrue); + // + // Save the current music + // + Q_strncpyz(tm_filename, S_GetMusicFilename(), sizeof(tm_filename)); + tm_loopcount = S_GetMusicLoopCount(); + tm_offset = S_GetMusicOffset(); SV_ClearSvsTimeFixups(); + S_SaveData(&save); + Q_strncpyz(current_soundtrack, S_CurrentSoundtrack(), sizeof(current_soundtrack)); + S_BeginRegistration(); // shutdown the renderer and clear the renderer interface @@ -1547,13 +1560,22 @@ void CL_Vid_Restart_f( void ) { CL_StartHunkUsers(qfalse); +#if defined(USE_SOUND_NEW) && USE_SOUND_NEW + s_bSoundPaused = true; + S_LoadData(&save); +#else + S_Init(); +#endif + SV_FinishSvsTimeFixups(); -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW - S_Init(); -#else - S_Init(qtrue); -#endif + S_ReLoad(&save); + + if (tm_filename[0]) { + S_TriggeredMusic_SetupHandle(tm_filename, tm_loopcount, tm_offset, 0); + } + + MUSIC_NewSoundtrack(current_soundtrack); if (clc.state > CA_CONNECTED && clc.state != CA_CINEMATIC) { @@ -1578,26 +1600,28 @@ void CL_Snd_Restart_f( void ) { #if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW S_Shutdown(); S_Init(); + CL_Vid_Restart_f(); #else qboolean full; soundsystemsavegame_t save; - char tm_filename[MAX_RES_NAME]; + char tm_filename[MAX_RES_NAME]; int tm_loopcount; int tm_offset; char current_soundtrack[128]; full = S_NeedFullRestart(); - // - // FIXME: there is a stub function - tm_loopcount = 0; - tm_offset = 0; - // + // + // Save the current music + // + Q_strncpyz(tm_filename, S_GetMusicFilename(), sizeof(tm_filename)); + tm_loopcount = S_GetMusicLoopCount(); + tm_offset = S_GetMusicOffset(); SV_ClearSvsTimeFixups(); S_SaveData(&save); - strcpy(current_soundtrack, S_CurrentSoundtrack()); + Q_strncpyz(current_soundtrack, S_CurrentSoundtrack(), sizeof(current_soundtrack)); S_Shutdown(qfalse); S_Init(qfalse); @@ -1614,12 +1638,11 @@ void CL_Snd_Restart_f( void ) { } MUSIC_NewSoundtrack(current_soundtrack); + if (full) { CL_Vid_Restart_f(); } #endif - - CL_Vid_Restart_f(); } From 1d60405eaa423fc5d54499c88f1e375b4d3fed6d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 19:46:49 +0200 Subject: [PATCH 0597/2040] Fix heap corruption when taking screenshots with non-standard resolutions like 1366x768 --- code/renderer/tr_init.c | 153 ++++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 45 deletions(-) diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index ef34b507..ca35ea32 100644 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -473,17 +473,63 @@ FIXME: the statics don't get a reinit between fs_game changes ============================================================================== */ +/* +================== +RB_ReadPixels + +Reads an image but takes care of alignment issues for reading RGB images. + +Reads a minimum offset for where the RGB data starts in the image from +integer stored at pointer offset. When the function has returned the actual +offset was written back to address offset. This address will always have an +alignment of packAlign to ensure efficient copying. + +Stores the length of padding after a line of pixels to address padlen + +Return value must be freed with ri.Hunk_FreeTempMemory() +================== +*/ + +byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen) +{ + byte *buffer, *bufstart; + int padwidth, linelen; + GLint packAlign; + + qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); + + linelen = width * 3; + padwidth = PAD(linelen, packAlign); + + // Allocate a few more bytes so that we can choose an alignment we like + buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); + + bufstart = PADP((intptr_t) buffer + *offset, packAlign); + qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); + + *offset = bufstart - buffer; + *padlen = padwidth - linelen; + + return buffer; +} + /* ================== RB_TakeScreenshot ================== */ void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { - byte *buffer; - int i, c, temp; + byte *allbuf, *buffer; + byte *srcptr, *destptr; + byte *endline, *endmem; + byte temp; + + int linelen, padlen; + size_t offset = 18, memcount; - buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18); - + allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); + buffer = allbuf + offset - 18; + Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width & 255; @@ -492,24 +538,39 @@ void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { buffer[15] = height >> 8; buffer[16] = 24; // pixel size - qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + // swap rgb to bgr and remove padding from line endings + linelen = width * 3; + + srcptr = destptr = allbuf + offset; + endmem = srcptr + (linelen + padlen) * height; + + while(srcptr < endmem) + { + endline = srcptr + linelen; - // swap rgb to bgr - c = 18 + width * height * 3; - for (i=18 ; i 0 ) && glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); - } + if(glConfig.deviceSupportsGamma) + R_GammaCorrect(allbuf + offset, memcount); - ri.FS_WriteFile( fileName, buffer, c ); + ri.FS_WriteFile(fileName, buffer, memcount + 18); - ri.Hunk_FreeTempMemory( buffer ); + ri.Hunk_FreeTempMemory(allbuf); } /* @@ -520,21 +581,19 @@ RB_TakeScreenshotJPEG void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { // FIXME: unimplemented #if 0 - byte *buffer; + byte *buffer; + size_t offset = 0, memcount; + int padlen; - buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); - - qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); + buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); + memcount = (width * 3 + padlen) * height; // gamma correct - if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); - } + if(glConfig.deviceSupportsGamma) + R_GammaCorrect(buffer + offset, memcount); - ri.FS_WriteFile( fileName, buffer, 1 ); // create path - SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer); - - ri.Hunk_FreeTempMemory( buffer ); + RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); + ri.Hunk_FreeTempMemory(buffer); #endif } @@ -638,14 +697,17 @@ R_ResampledScreenShot void R_ResampledScreenShot(const char* filename, int destwidth, int destheight) { char checkname[MAX_OSPATH]; byte *buffer; - byte *source; + byte *source, *allsource; byte *src, *dst; + size_t offset = 0; + int padlen; int x, y; int r, g, b; float xScale, yScale; int xx, yy; - source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); + allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); + source = allsource + offset; buffer = ri.Hunk_AllocateTempMemory(destheight * destwidth * 3 + 18); Com_Memset (buffer, 0, 18); @@ -656,8 +718,6 @@ void R_ResampledScreenShot(const char* filename, int destwidth, int destheight) buffer[15] = destheight >> 8; buffer[16] = 24; // pixel size - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); - // resample from source xScale = glConfig.vidWidth / (float)(destwidth * 4); yScale = glConfig.vidHeight / (float)(destheight * 3); @@ -666,7 +726,8 @@ void R_ResampledScreenShot(const char* filename, int destwidth, int destheight) r = g = b = 0; for ( yy = 0 ; yy < 3 ; yy++ ) { for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) ); + src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + + 3 * (int) ((x*4 + xx) * xScale); r += src[0]; g += src[1]; b += src[2]; @@ -680,14 +741,14 @@ void R_ResampledScreenShot(const char* filename, int destwidth, int destheight) } // gamma correct - if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, destheight * destwidth * 3 ); + if ( glConfig.deviceSupportsGamma ) { + R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); } ri.FS_WriteFile( filename, buffer, destheight * destwidth * 3 + 18 ); ri.Hunk_FreeTempMemory( buffer ); - ri.Hunk_FreeTempMemory( source ); + ri.Hunk_FreeTempMemory( allsource ); } /* @@ -701,26 +762,27 @@ the menu system, sampled down from full screen distorted images void R_LevelShot( void ) { char checkname[MAX_OSPATH]; byte *buffer; - byte *source; + byte *source, *allsource; byte *src, *dst; + size_t offset = 0; + int padlen; int x, y; int r, g, b; float xScale, yScale; int xx, yy; - sprintf( checkname, "levelshots/%s.tga", tr.world->baseName ); + Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); - source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); + allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); + source = allsource + offset; - buffer = ri.Hunk_AllocateTempMemory( 128 * 128*3 + 18); + buffer = ri.Hunk_AllocateTempMemory(128 * 128*3 + 18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = 128; buffer[14] = 128; buffer[16] = 24; // pixel size - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); - // resample from source xScale = glConfig.vidWidth / 512.0f; yScale = glConfig.vidHeight / 384.0f; @@ -729,7 +791,8 @@ void R_LevelShot( void ) { r = g = b = 0; for ( yy = 0 ; yy < 3 ; yy++ ) { for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) ); + src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + + 3 * (int) ((x*4 + xx) * xScale); r += src[0]; g += src[1]; b += src[2]; @@ -743,14 +806,14 @@ void R_LevelShot( void ) { } // gamma correct - if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + if ( glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); } ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); - ri.Hunk_FreeTempMemory( buffer ); - ri.Hunk_FreeTempMemory( source ); + ri.Hunk_FreeTempMemory(buffer); + ri.Hunk_FreeTempMemory(allsource); ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); } From 5b80ea20c7ced11ab02ef596a4491d10dcf952cb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:11:26 +0200 Subject: [PATCH 0598/2040] Fix filename case sensitivity on Linux This fixes #334 where some sounds wouldn't play because some scripts reference sounds without respecting the case --- code/qcommon/files.cpp | 57 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/code/qcommon/files.cpp b/code/qcommon/files.cpp index 595c6a1a..1563c2b8 100644 --- a/code/qcommon/files.cpp +++ b/code/qcommon/files.cpp @@ -33,6 +33,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "qcommon.h" #include "unzip.h" +#ifndef _WIN32 +# include +# include +#endif + /* ============================================================================= @@ -522,17 +527,51 @@ check_filecase ==================== */ static int check_filecase( char *Path ) { - /* - int retval; + int retval; + +#ifdef _WIN32 + retval = 0; +#else char *ptr; char *filename; char *basedir; + DIR* dir; - // of course there is no portable way to open a dir in Linux or Windows - // DAMNIT - // FIXME: stub - */ - return 0; + retval = 0; + ptr = strrchr(Path, '/'); + filename = Path; + + if (ptr) { + filename = ptr + 1; + } + + basedir = "."; + if (ptr) + { + basedir = Path; + *ptr = 0; + } + + dir = opendir(basedir); + if (dir) + { + dirent* ent; + + for (ent = readdir(dir); ent && !retval; ent = readdir(dir)) { + if (!Q_stricmp(ent->d_name, filename)) { + strcpy(filename, ent->d_name); + retval = 1; + } + } + + closedir(dir); + } + + if (ptr) { + *ptr = '/'; + } +#endif + return retval; } /* @@ -564,9 +603,7 @@ void FS_CorrectCase( char *path ) { *ptr = 0; } - getOut = access( path, 0 ); - - if( getOut ) { + if( access(path, 0) ) { getOut = !check_filecase( path ); } From 434aaf3eafee3917f11e51c4389a74b60d345877 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 5 Aug 2024 23:41:17 +0200 Subject: [PATCH 0599/2040] Initialize last animation time --- code/cgame/cg_modelanim.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/cgame/cg_modelanim.c b/code/cgame/cg_modelanim.c index 5386db19..960aadf8 100644 --- a/code/cgame/cg_modelanim.c +++ b/code/cgame/cg_modelanim.c @@ -1323,7 +1323,12 @@ void CG_ModelAnim(centity_t *cent, qboolean bDoShaderTime) if (model.frameInfo[i].weight) { if (!((cent->animLastWeight >> i) & 1) || model.frameInfo[i].index != cent->animLast[i]) { CG_ProcessEntityCommands(TIKI_FRAME_ENTRY, model.frameInfo[i].index, s1->number, &model, cent); - cent->animLastTimes[i] = 0.0; + if (cent->animLastTimes[i] == -1) { + cent->animLast[i] = model.frameInfo[i].index; + cent->animLastTimes[i] = model.frameInfo[i].time; + } else { + cent->animLastTimes[i] = 0; + } } CG_ClientCommands(&model, cent, i); From cd6ec5e3a7def94bac2e5915a6c57247eae00c61 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:43:15 +0200 Subject: [PATCH 0600/2040] Fix streamed sound, use 2D instead with properly implemented panning --- code/client/snd_openal_new.cpp | 47 +++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index deb5e4de..2884c784 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -481,7 +481,7 @@ qboolean S_OPENAL_Init() } } - al_current_volume = s_volume->value * s_volume->value; + al_current_volume = Square(s_volume->value); qalListenerf(AL_GAIN, al_current_volume); alDieIfError(); @@ -1358,9 +1358,8 @@ void S_OPENAL_StartSound( return; } - // Fixed in OPM - // 3D streamed or MP3 sound should be supported - if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET)) //|| pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + //if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET)) //|| pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) { S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist); return; @@ -1370,12 +1369,10 @@ void S_OPENAL_StartSound( iEntNum &= ~S_FLAG_DO_CALLBACK; pSfxInfo = &sfx_infos[pSfx->sfx_info_index]; - // Fixed in OPM - // 3D streamed sound should be supported - //if (pSfx->iFlags & SFX_FLAG_STREAMED) { - // Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name); - // return; - //} + if (pSfx->iFlags & SFX_FLAG_STREAMED) { + Com_DPrintf("3D sounds not supported - couldn't play '%s'\n", pSfx->name); + return; + } iChannel = S_OPENAL_PickChannel3D(iEntNum, iEntChannel); if (iChannel < 0) { @@ -1792,11 +1789,9 @@ static int S_OPENAL_Start3DLoopSound( int iSoundOffset; openal_channel *pChan3D; - // Fixed in OPM - // 3D streamed sound should be supported - //if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { - // return -1; - //} + if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { + return -1; + } iChannel = S_OPENAL_PickChannel3D(0, 0); if (iChannel < 0) { @@ -1874,7 +1869,8 @@ static bool S_OPENAL_UpdateLoopSound( pChannel->iStartTime = cl.serverTime; - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) // || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + //if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) // || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { vec3_t vOrigin; int iPan; @@ -2093,7 +2089,8 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name); } - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) //|| pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + //if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) //|| pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { iChannel = S_OPENAL_Start2DLoopSound( pLoopSound, fVolume, S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, vLoopOrigin @@ -2199,7 +2196,7 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi //vTempAxis[0] = -vAxis[0][1]; //vTempAxis[1] = vAxis[2][1]; //vTempAxis[2] = -vAxis[1][1]; - VectorCopy(vAxis[0], vTempAxis); + VectorCopy(vAxis[1], vTempAxis); fVolume = 1; iPan = 64; @@ -2351,7 +2348,7 @@ static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const ve pan = 0; } - return pan * 128.f; + return ceilf(pan * 127); } /* @@ -2417,7 +2414,7 @@ void S_OPENAL_Update() music_volume_changed = true; s_volume->modified = 0; - al_current_volume = Square(s_volume->value * s_volume->value); + al_current_volume = Square(s_volume->value); qalListenerf(AL_GAIN, al_current_volume); alDieIfError(); } @@ -3046,7 +3043,15 @@ void openal_channel::end_sample() openal_channel::set_sample_pan ============== */ -void openal_channel::set_sample_pan(S32 pan) {} +void openal_channel::set_sample_pan(S32 pan) +{ + const float panning = (pan - 64) / 127.f; + const ALfloat sourcePosition[3] = {panning, 0, sqrtf(1.f - Square(panning))}; + + qalSourcef(source, AL_ROLLOFF_FACTOR, 0); + qalSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + qalSourcefv(source, AL_POSITION, sourcePosition); +} /* ============== From 236afa7c3fbb278c5c9122b0403f99f98159d293 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:21:00 +0200 Subject: [PATCH 0601/2040] Implement obfuscation mapping setup The implementation reads all obfuscation csv and return a list of visual obfuscations --- code/qcommon/cm_trace_obfuscation.cpp | 207 +++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 5 deletions(-) diff --git a/code/qcommon/cm_trace_obfuscation.cpp b/code/qcommon/cm_trace_obfuscation.cpp index 171e5a49..caa0be5f 100644 --- a/code/qcommon/cm_trace_obfuscation.cpp +++ b/code/qcommon/cm_trace_obfuscation.cpp @@ -22,14 +22,92 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "cm_local.h" +static char com_token[MAX_TOKEN_CHARS]; + +/* +================ +CM_NextCsvToken +================ +*/ char* CM_NextCsvToken(char** text, qboolean crossline) { - // FIXME: unimplemented - return NULL; + char* p; + char* out; + char c; + int i; + qboolean newline; + qboolean comma; + + com_token[0] = 0; + p = *text; + if (!p) { + return com_token; + } + + for (c = *p; isspace(c); p++, c = *p) + { + if (c == '\n' && !crossline) { + break; + } + } + + out = com_token; + + for (i = 0; ; i++, p++) { + c = *p; + + newline = qfalse; + comma = qfalse; + + if (*p && c != ',') { + comma = qtrue; + } + + if (comma && c != '\n') { + newline = qtrue; + } + + if (!newline) { + break; + } + + *out = c; + out++; + } + + if (c == ',') { + p++; + } + + while (i > 0) { + if (!isspace(com_token[i - 1])) { + break; + } + + i--; + } + + com_token[i] = 0; + *text = p; + + if (!p[0]) { + *text = NULL; + } + + return com_token; } +/* +================ +CM_SetupObfuscationMapping +================ +*/ obfuscation_t* CM_SetupObfuscationMapping() { obfuscation_t* list; - int i; + obfuscation_t* obfuscation; + char** files; + int numFiles; + int numObfuscations; + int i, j; list = (obfuscation_t*)Hunk_AllocateTempMemory(sizeof(obfuscation_t) * MAX_OBFUSCATIONS); for (i = 0; i < MAX_OBFUSCATIONS; i++) { @@ -37,14 +115,122 @@ obfuscation_t* CM_SetupObfuscationMapping() { list[i].heightDensity = 0; list[i].widthDensity = 0; } - // FIXME: unimplemented + + files = FS_ListFiles("scripts/", ".csv", qfalse, &numFiles); + numObfuscations = 0; + + for (i = 0; i < numFiles; ++i) { + const char* filename = va("scripts/%s", files[i]); + void* buffer; + char* text; + char* token; + + if (FS_ReadFile(filename, &buffer) < 0) { + continue; + } + + text = (char*)buffer; + while (text) { + token = CM_NextCsvToken(&text, qtrue); + if (!token[0]) { + break; + } + + for (j = 0; j < numObfuscations; ++j) + { + if (!Q_stricmp(token, list[j].name)) + { + Com_Printf("WARNING: using redefinition of obfuscation for '%s' in '%s'\n", token, files[i]); + break; + } + } + + obfuscation = &list[j]; + strcpy(obfuscation->name, token); + + token = CM_NextCsvToken(&text, qfalse); + if (!text) { + Com_Printf( + "WARNING: unexpected EOF in definition of obfuscation for '%s' in '%s'; skipping\n", + obfuscation->name, + files[i] + ); + break; + } + + if (token[0]) { + float maxNumVolumes = atof(token); + + if (maxNumVolumes > 0) { + obfuscation->widthDensity = 0.5f / maxNumVolumes; + } else { + obfuscation->widthDensity = 0; + } + + token = CM_NextCsvToken(&text, 0); + if (!text) { + Com_Printf( + "WARNING: unexpected EOF in definition of obfuscation for '%s' in '%s'; skipping\n", + obfuscation->name, + files[i] + ); + break; + } + + if (token[0]) { + float maxDist = atof(token); + + if (maxDist > 0) { + obfuscation->heightDensity = 1.f / maxDist; + } else { + obfuscation->heightDensity = 0; + } + + if (numObfuscations == MAX_OBFUSCATIONS) { + Com_Printf("WARNING: exceeded MAX_OBFUSCATIONS (%i)", numObfuscations); + } else { + numObfuscations++; + } + } else { + Com_Printf( + "WARNING: missing max distance thorugh obscuring volumes for '%s' in '%s'; skipping\n", + obfuscation->name, + files[i] + ); + SkipRestOfLine(&text); + } + } else { + Com_Printf( + "WARNING: missing max number of obscuring volumes for '%s' in '%s'; skipping\n", + obfuscation->name, + files[i] + ); + SkipRestOfLine(&text); + } + } + + FS_FreeFile(buffer); + } + + list[numObfuscations].name[0] = 0; + return list; } +/* +================ +CM_ReleaseObfuscationMapping +================ +*/ void CM_ReleaseObfuscationMapping(obfuscation_t* obfuscation) { Hunk_FreeTempMemory(obfuscation); } +/* +================ +CM_ObfuscationForShader +================ +*/ void CM_ObfuscationForShader(obfuscation_t* list, const char* shaderName, float* widthDensity, float* heightDensity) { obfuscation_t* current; @@ -276,11 +462,22 @@ float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float return CM_ObfuscationTraceThroughTree( tw, node->children[side^1], midf, p2f, mid, p2 ); } +/* +================ +CM_ObfuscationTrace +================ +*/ float CM_ObfuscationTrace(const vec3_t start, const vec3_t end, clipHandle_t model) { // FIXME: unimplemented return 0.f; } -float CM_VisualObfuscation(const vec3_t start, const vec3_t end) { // FIXME: unimplemented +/* +================ +CM_VisualObfuscation +================ +*/ +float CM_VisualObfuscation(const vec3_t start, const vec3_t end) { + // FIXME: unimplemented return 0.f; } From 88174672164af94c2eccaef7c7a63c512f11c795 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:58:16 +0200 Subject: [PATCH 0602/2040] Implement trace obfuscation --- code/qcommon/cm_trace_obfuscation.cpp | 134 ++++++++++++-------------- 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/code/qcommon/cm_trace_obfuscation.cpp b/code/qcommon/cm_trace_obfuscation.cpp index caa0be5f..803f145d 100644 --- a/code/qcommon/cm_trace_obfuscation.cpp +++ b/code/qcommon/cm_trace_obfuscation.cpp @@ -252,31 +252,21 @@ CM_ObfuscationTraceThroughBrush ================ */ float CM_ObfuscationTraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { - int i; - cplane_t *plane, *clipplane, *clipplane2; - float dist; - float enterFrac, leaveFrac, leaveFrac2; - float d1, d2; - qboolean getout, startout; - float f; - cbrushside_t *side, *leadside, *leadside2; - float t; - float alpha; + int i; + cplane_t* plane; + float dist; + float enterFrac, leaveFrac; + float enterDensity, leaveDensity; + float delta; + float d1, d2; + float f; + cbrushside_t* side; - if( !brush->numsides ) { - return tw->radius * cm.shaders[brush->shaderNum].obfuscationHeightDensity; - } - - enterFrac = -1.0; + enterFrac = 0; + enterDensity = 0; leaveFrac = 1.0; - clipplane = NULL; + leaveDensity = 0; - c_brush_traces++; - - getout = qfalse; - startout = qfalse; - - leadside = NULL; // // compare the trace against all planes of the brush // find the latest time the trace crosses a plane towards the interior @@ -287,41 +277,38 @@ float CM_ObfuscationTraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { plane = side->plane; // adjust the plane distance apropriately for mins/maxs - dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal ); + //dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal ); + dist = plane->dist; d1 = DotProduct( tw->start, plane->normal ) - dist; d2 = DotProduct( tw->end, plane->normal ) - dist; // if it doesn't cross the plane, the plane isn't relevent if( d1 >= 0 && d2 >= 0 ) { - continue; + return 0; } - // crosses face - if( d1 > d2 ) { // enter - f = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 ); - if( f < 0 ) { - f = 0; - } - if( f > enterFrac ) { - enterFrac = f; - clipplane = plane; - leadside = side; - } - } else { // leave - f = ( d1 + SURFACE_CLIP_EPSILON ) / ( d1 - d2 ); - if( f > 1 ) { - f = 1; - } - if( f < leaveFrac ) { - leaveFrac = f; - } - } + if (d1 < 0 && d2 > 0) { + f = d1 / (d1 - d2); + if (leaveFrac > f) { + leaveFrac = f; + } + leaveDensity = cm.shaders[brush->shaderNum].obfuscationWidthDensity; + } else if (d1 > 0 && d2 < 0) { + f = d1 / (d1 - d2); + if (enterFrac < f) { + enterFrac = f; + } + enterDensity = cm.shaders[brush->shaderNum].obfuscationWidthDensity; + } } - alpha = 1.f; - // FIXME: unimplemented - return alpha; + delta = leaveFrac - enterFrac; + if (delta <= 0) { + return 0; + } + + return enterDensity + cm.shaders[brush->shaderNum].obfuscationHeightDensity * tw->radius * delta + leaveDensity; } /* @@ -366,7 +353,7 @@ a smaller intercept fraction. float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) { cNode_t *node; cplane_t *plane; - float t1, t2, offset; + float t1, t2; float frac, frac2; float idist; vec3_t mid; @@ -391,23 +378,16 @@ float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float if ( plane->type < 3 ) { t1 = p1[plane->type] - plane->dist; t2 = p2[plane->type] - plane->dist; - offset = tw->extents[plane->type]; } else { t1 = DotProduct (plane->normal, p1) - plane->dist; t2 = DotProduct (plane->normal, p2) - plane->dist; - if ( tw->isPoint ) { - offset = 0; - } else { - // this is silly - offset = 2048; - } } // see which sides we need to consider - if ( t1 >= offset + 1 && t2 >= offset + 1 ) { + if ( t1 >= SURFACE_CLIP_EPSILON && t2 >= SURFACE_CLIP_EPSILON) { return CM_ObfuscationTraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 ); } - if ( t1 < -offset - 1 && t2 < -offset - 1 ) { + if ( t1 < -SURFACE_CLIP_EPSILON && t2 < -SURFACE_CLIP_EPSILON) { return CM_ObfuscationTraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 ); } @@ -415,13 +395,13 @@ float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float if ( t1 < t2 ) { idist = 1.0/(t1-t2); side = 1; - frac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist; - frac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist; + frac2 = (t1 + SURFACE_CLIP_EPSILON)*idist; + frac = (t1 + SURFACE_CLIP_EPSILON)*idist; } else if (t1 > t2) { idist = 1.0/(t1-t2); side = 0; - frac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist; - frac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist; + frac2 = (t1 - SURFACE_CLIP_EPSILON)*idist; + frac = (t1 + SURFACE_CLIP_EPSILON)*idist; } else { side = 0; frac = 1; @@ -431,8 +411,7 @@ float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float // move up to the node if ( frac < 0 ) { frac = 0; - } - if ( frac > 1 ) { + } else if ( frac > 1 ) { frac = 1; } @@ -448,8 +427,7 @@ float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float // go past the node if ( frac2 < 0 ) { frac2 = 0; - } - if ( frac2 > 1 ) { + } else if ( frac2 > 1 ) { frac2 = 1; } @@ -467,9 +445,26 @@ float CM_ObfuscationTraceThroughTree( traceWork_t *tw, int num, float p1f, float CM_ObfuscationTrace ================ */ -float CM_ObfuscationTrace(const vec3_t start, const vec3_t end, clipHandle_t model) { - // FIXME: unimplemented - return 0.f; +float CM_ObfuscationTrace(const vec3_t start, const vec3_t end, clipHandle_t handle) { + cmodel_t* model; + vec3_t delta; + traceWork_t tw; + + model = CM_ClipHandleToModel(handle); + + c_traces++; + cm.checkcount++; + + VectorCopy(start, tw.start); + VectorCopy(end, tw.end); + VectorSubtract(tw.end, tw.start, delta); + tw.radius = VectorLength(delta); + + if (handle) { + return CM_ObfuscationTraceToLeaf(&tw, &model->leaf); + } else { + return CM_ObfuscationTraceThroughTree(&tw, 0, 0.0, 1.0, tw.start, tw.end); + } } /* @@ -478,6 +473,5 @@ CM_VisualObfuscation ================ */ float CM_VisualObfuscation(const vec3_t start, const vec3_t end) { - // FIXME: unimplemented - return 0.f; + return CM_ObfuscationTrace(start, end, 0); } From d22dea5e8ea2f55e22ec0101f880e1d2402c61da Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:55:37 +0200 Subject: [PATCH 0603/2040] Count renderer memory --- code/null/null_client.c | 3 ++ code/qcommon/memory.c | 6 ++-- code/qcommon/qcommon.h | 1 + code/renderer/tr_image.c | 62 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/code/null/null_client.c b/code/null/null_client.c index 4027e404..ab6c7c15 100644 --- a/code/null/null_client.c +++ b/code/null/null_client.c @@ -125,3 +125,6 @@ void SCR_DebugGraph( float value ) { qboolean CL_FinishedIntro( void ) { return qtrue; } + +int R_CountTextureMemory() { +} diff --git a/code/qcommon/memory.c b/code/qcommon/memory.c index e28c3480..23055ffe 100644 --- a/code/qcommon/memory.c +++ b/code/qcommon/memory.c @@ -325,9 +325,9 @@ void Z_Meminfo_f( void ) Com_Printf( "\n%.2f Kbytes in %zu blocks in all memory pools\n", ( float )totalBytes / 1024.0f, totalBlocks ); // FIXME: Count texture memory - //Com_Printf( "\n%.2f megabytes in 'new' system memory\n", 1.024f ); - //Com_Printf( "\n%.2f megabytes in texture memory\n", ( float )R_CountTextureMemory() / 1024.0f ); - //Com_Printf( "\n%.1f megabytes in total allocations\n", ( float )R_CountTextureMemory() + totalBytes - 1 / 1024.0f ); + Com_Printf( "\n%.2f megabytes in 'new' system memory\n", 1.024f ); + Com_Printf( "\n%.2f megabytes in texture memory\n", ( float )R_CountTextureMemory() / 1024.0f ); + Com_Printf( "\n%.1f megabytes in total allocations\n", ( float )R_CountTextureMemory() + totalBytes - 1 / 1024.0f ); } /* diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 8ddcf7d4..3dcd5a44 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -1211,6 +1211,7 @@ void Com_FakeUnpause(); void Com_Pause_f(); void SV_SoundCallback( int entnum, int channel_number, const char *name ); +int R_CountTextureMemory(); /* ============================================================== diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index aa7389c6..945ea70c 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -2928,7 +2928,7 @@ void R_DeleteTextures( void ) { int i; for ( i=0; iimgName, strlen(image->imgName), stat_file); + FS_Write(", ", 2, stat_file); + + // Write the number of bytes (in KiB) + itoa(image->bytesUsed >> 10, str_buffer, 10); + FS_Write(str_buffer, strlen(str_buffer), stat_file); + FS_Write(", ", 2, stat_file); + + // Write the sequence + itoa(image->r_sequence, str_buffer, 10); + FS_Write(str_buffer, strlen(str_buffer), stat_file); + FS_Write(", ", 2, stat_file); + } +} + +/* +=============== +R_CountTextureMemory +=============== +*/ +int R_CountTextureMemory() { + int total_bytes; + int i; + + R_DumpTextureMemory(); + + total_bytes = 0; + + for (i = 0; i < tr.numImages; i++) { + total_bytes = tr.images[i].bytesUsed; + } + + return total_bytes; +} + /* ============================================================================ From 7b59f07181b79d535e41a06bf818df1415559dfc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:01:38 +0200 Subject: [PATCH 0604/2040] Allow precaching image manually with `r_precacheimages` --- code/renderer/tr_backend.c | 8 +++++--- code/renderer/tr_init.c | 12 ++++++++++-- code/renderer/tr_local.h | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 3ba08d20..6fb946fb 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -1294,7 +1294,7 @@ was there. This is used to test for texture thrashing. Also called by RE_EndRegistration =============== */ -void RB_ShowImages( void ) { +void RB_ShowImages( qboolean quiet ) { int i; image_t *image; float x, y, w, h; @@ -1340,8 +1340,10 @@ void RB_ShowImages( void ) { qglFinish(); end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); + if (!quiet) { + ri.Printf(PRINT_ALL, "%i msec to draw all images\n", end - start); + } } @@ -1361,7 +1363,7 @@ const void *RB_SwapBuffers( const void *data ) { // texture swapping test if ( r_showImages->integer ) { - RB_ShowImages(); + RB_ShowImages(qfalse); } cmd = (const swapBuffersCommand_t *)data; diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index ca35ea32..35838184 100644 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -1602,8 +1602,16 @@ Touch all images to make sure they are resident */ void RE_EndRegistration( void ) { R_SyncRenderThread(); - if (!Sys_LowPhysicalMemory()) { - RB_ShowImages(); + if (r_precacheimages->integer) { + int start, end; + + start = Sys_Milliseconds(); + + RB_ShowImages(qtrue); + + end = Sys_Milliseconds(); + + Com_Printf("RB_ShowImages: %5.2f seconds\n", (float)((end - start) / 1000.f)); } } diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 96affbf3..03f4c40b 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1902,7 +1902,7 @@ void RB_StageIteratorLightmappedMultitextureUnfogged( void ); void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ); void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ); -void RB_ShowImages( void ); +void RB_ShowImages( qboolean quiet ); /* From 53d812666cd358acb833b87c5ab6a51137f3fe2a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:02:48 +0200 Subject: [PATCH 0605/2040] Remove FIXME section --- code/qcommon/memory.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/qcommon/memory.c b/code/qcommon/memory.c index 23055ffe..7845eae1 100644 --- a/code/qcommon/memory.c +++ b/code/qcommon/memory.c @@ -323,8 +323,6 @@ void Z_Meminfo_f( void ) } Com_Printf( "\n%.2f Kbytes in %zu blocks in all memory pools\n", ( float )totalBytes / 1024.0f, totalBlocks ); - - // FIXME: Count texture memory Com_Printf( "\n%.2f megabytes in 'new' system memory\n", 1.024f ); Com_Printf( "\n%.2f megabytes in texture memory\n", ( float )R_CountTextureMemory() / 1024.0f ); Com_Printf( "\n%.1f megabytes in total allocations\n", ( float )R_CountTextureMemory() + totalBytes - 1 / 1024.0f ); From 7f8a0c99313f0e5f90c33daab96cb2e0508106de Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:10:04 +0200 Subject: [PATCH 0606/2040] Fix the image texture number not properly matching the image It caused issues with textures being messed up sometimes, after multiple maps were loaded --- code/renderer/tr_image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 945ea70c..55195111 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -918,7 +918,7 @@ image_t* R_CreateImage( } image = &tr.images[i]; - image->texnum = 1024 + tr.numImages; + image->texnum = 1024 + i; image->numMipmaps = numMipmaps; image->allowPicmip = allowPicmip; From b463c905cf7845cae0793367a58da70b8f9e9076 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:11:11 +0200 Subject: [PATCH 0607/2040] Free up unused images This fixes #93 where the game would hit `MAX_DRAWIMAGES` after loading a few maps --- code/renderer/tr_image.c | 17 +++++++++++++++++ code/renderer/tr_init.c | 7 +++++++ code/renderer/tr_local.h | 1 + 3 files changed, 25 insertions(+) diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 55195111..ae7f56c8 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -3007,6 +3007,23 @@ int R_CountTextureMemory() { return total_bytes; } +/* +=============== +R_FreeUnusedImages +=============== +*/ +void R_FreeUnusedImages() { + int i; + + for (i = 0; i < tr.numImages; i++) { + image_t* image = &tr.images[i]; + + if (image->imgName[0] && image->r_sequence != r_sequencenumber && image->r_sequence != -1) { + R_FreeImage(image); + } + } +} + /* ============================================================================ diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index 35838184..d9f5d235 100644 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -1613,8 +1613,15 @@ void RE_EndRegistration( void ) { Com_Printf("RB_ShowImages: %5.2f seconds\n", (float)((end - start) / 1000.f)); } + + R_FreeUnusedImages(); } +/* +============= +RE_SetRenderTime +============= +*/ void RE_SetRenderTime(int t) { // FIXME: unimplemented } diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 03f4c40b..809aafa2 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1794,6 +1794,7 @@ void R_ScreenShot_f( void ); void R_InitImages( void ); void R_FreeImage(image_t* image); void R_DeleteTextures( void ); +void R_FreeUnusedImages( void ); int R_SumOfUsedImages( void ); skin_t *R_GetSkinByHandle( qhandle_t hSkin ); From 7b92d99afac816ee9dd725584bb3812691e24228 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:24:52 +0200 Subject: [PATCH 0608/2040] Fix compile error --- code/null/null_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/null/null_client.c b/code/null/null_client.c index ab6c7c15..b4d3394b 100644 --- a/code/null/null_client.c +++ b/code/null/null_client.c @@ -127,4 +127,5 @@ qboolean CL_FinishedIntro( void ) { } int R_CountTextureMemory() { + return 0; } From d809975882f73b2c14c8f81d5ddb6ca4d8175be5 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:27:02 +0200 Subject: [PATCH 0609/2040] Use Q_snprintf because itoa is non-standard --- code/renderer/tr_image.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index ae7f56c8..2698fb1a 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -2976,12 +2976,12 @@ void R_DumpTextureMemory() { FS_Write(", ", 2, stat_file); // Write the number of bytes (in KiB) - itoa(image->bytesUsed >> 10, str_buffer, 10); + Q_snprintf(str_buffer, sizeof(str_buffer), "%d", image->bytesUsed >> 10); FS_Write(str_buffer, strlen(str_buffer), stat_file); FS_Write(", ", 2, stat_file); // Write the sequence - itoa(image->r_sequence, str_buffer, 10); + Q_snprintf(str_buffer, sizeof(str_buffer), "%d", image->r_sequence); FS_Write(str_buffer, strlen(str_buffer), stat_file); FS_Write(", ", 2, stat_file); } From e19b72647ed2284c41d46f645bcac9b516d8287b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:07:09 +0200 Subject: [PATCH 0610/2040] Use qglGenTextures to guarantee the uniqueness of the texture number --- code/renderer/tr_image.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 2698fb1a..9caeffba 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -918,7 +918,11 @@ image_t* R_CreateImage( } image = &tr.images[i]; - image->texnum = 1024 + i; + //image->texnum = 1024 + i; + // Fixed in OPM / ioquake3 + // Original mohaa uses a fixed texnum instead of generating one regardless of the platform. + // Here, by using glGenTextures, it will guarantee the uniqueness of the texture + qglGenTextures(1, &image->texnum); image->numMipmaps = numMipmaps; image->allowPicmip = allowPicmip; From 9150d1cc44568d9e2a78682cbb5ee9c167f0dafc Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:31:19 +0200 Subject: [PATCH 0611/2040] Fix lighting grid being incorrect It fixes #321 where impacts like bullets would have an incorrect color (like red, green...) --- code/renderer/tr_light.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/code/renderer/tr_light.c b/code/renderer/tr_light.c index 2a8dd722..c16519cf 100644 --- a/code/renderer/tr_light.c +++ b/code/renderer/tr_light.c @@ -725,6 +725,7 @@ void R_GetLightingGridValue(const vec3_t vPos, vec3_t vLight) float fOMFrac[3]; float fWeight, fWeight2; float fTotalFactor; + int iCurData; vec3_t vLightOrigin; byte* pCurData; @@ -737,7 +738,7 @@ void R_GetLightingGridValue(const vec3_t vPos, vec3_t vLight) for (i = 0; i < 3; i++) { fV = vLightOrigin[i] * tr.world->lightGridOOSize[i]; - iGridPos[i] = myftol(fV); + iGridPos[i] = floor(fV); fFrac[i] = fV - iGridPos[i]; fOMFrac[i] = 1.0 - fFrac[i]; @@ -758,23 +759,23 @@ void R_GetLightingGridValue(const vec3_t vPos, vec3_t vLight) { case 0: fWeight = fOMFrac[0] * fOMFrac[1] * fOMFrac[2]; - fWeight2 = fWeight; + fWeight2 = fOMFrac[0] * fOMFrac[1] * fFrac[2]; iOffset = tr.world->lightGridOffsets[iBaseOffset] + (tr.world->lightGridOffsets[iGridPos[0]] << 8); break; case 1: - fWeight = fFrac[0] * fFrac[1] * fOMFrac[2]; - fWeight2 = fFrac[0] * fFrac[1] * fFrac[2]; - iOffset = tr.world->lightGridOffsets[iArrayXStep + 1 + iBaseOffset]; + fWeight = fOMFrac[0] * fFrac[1] * fOMFrac[2]; + fWeight2 = fOMFrac[0] * fFrac[1] * fFrac[2]; + iOffset = tr.world->lightGridOffsets[iBaseOffset + 1] + (tr.world->lightGridOffsets[iGridPos[0]] << 8); break; case 2: fWeight = fFrac[0] * fOMFrac[1] * fOMFrac[2]; fWeight2 = fFrac[0] * fOMFrac[1] * fFrac[2]; - iOffset = tr.world->lightGridOffsets[iArrayXStep + iBaseOffset]; + iOffset = tr.world->lightGridOffsets[iBaseOffset + iArrayXStep] + (tr.world->lightGridOffsets[iGridPos[0] + 1] << 8); break; case 3: fWeight = fFrac[0] * fFrac[1] * fOMFrac[2]; fWeight2 = fFrac[0] * fFrac[1] * fFrac[2]; - iOffset = tr.world->lightGridOffsets[iArrayXStep + 1 + iBaseOffset]; + iOffset = tr.world->lightGridOffsets[iBaseOffset + iArrayXStep + 1] + (tr.world->lightGridOffsets[iGridPos[0] + 1] << 8); break; } @@ -786,11 +787,13 @@ void R_GetLightingGridValue(const vec3_t vPos, vec3_t vLight) { while (1) { - if (pCurData[iData] >= 0ul) { + iCurData = pCurData[iData]; + iData++; + if (iCurData >= 0ul) { break; } - iLen = -pCurData[iData]; + iLen = -iCurData; if (iLen > iRowPos) { iData += iRowPos; if (pCurData[iData]) { @@ -816,7 +819,7 @@ void R_GetLightingGridValue(const vec3_t vPos, vec3_t vLight) iData += iLen + 1; } - iLen = pCurData[iData] + 2; + iLen = iCurData + 2; if (iLen - 1 >= iRowPos) { break; } From 513fe7773f0629b70c78bb64024091be7b671ebb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:44:00 +0200 Subject: [PATCH 0612/2040] Don't append a '\' at the beginning during autocompletion --- code/qcommon/common.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 75c4971d..5edc49db 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -2596,6 +2596,7 @@ void Field_CompleteCommand(char* cmd, else completionString = Cmd_Argv(completionArgument - 1); +#if 0 #ifndef DEDICATED // add a '\' to the start of the buffer if it might be sent as chat otherwise if (con_autochat->integer && completionField->buffer[0] && @@ -2616,6 +2617,7 @@ void Field_CompleteCommand(char* cmd, completionField->buffer[0] = '\\'; } +#endif #endif if (completionArgument > 1) From 3af24ee0eaa7c7f270d33d024f9e0665e3bc5c5f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 9 Aug 2024 20:30:35 +0200 Subject: [PATCH 0613/2040] Exclude new sound CPP files directly when not using the new sound system instead of using #ifdef --- code/client/CMakeLists.txt | 8 ++++++-- code/client/snd_dma_new.cpp | 12 ++++-------- code/client/snd_mem_new.cpp | 4 ---- code/client/snd_openal_new.cpp | 14 +++++--------- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index cfc2c676..a768d968 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -3,7 +3,7 @@ project(omohclient) add_subdirectory("../cgame" "./cgame") -file(GLOB_RECURSE SOURCES_CLIENT "./*.c*") +file(GLOB SOURCES_CLIENT "./*.c*") file(GLOB_RECURSE SOURCES_UILIB "../uilib/*.c*") # Made as an interface and not static, as static only links used methods @@ -32,7 +32,7 @@ if (USE_SOUND_NEW) endif() list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.c$") - file(GLOB_RECURSE SOURCES_CLIENT_SND "./snd_*_new.c*" "./snd_codec*.c*") + file(GLOB SOURCES_CLIENT_SND "./snd_*_new.c*" "./snd_codec*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) set(OLD_VALUE ${BUILD_SHARED_LIBS}) @@ -43,6 +43,10 @@ if (USE_SOUND_NEW) else() add_subdirectory("../libmad-0.15.1b" "./libmad") target_link_libraries(omohclient INTERFACE libmad) + + list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.cpp$") + file(GLOB_RECURSE SOURCES_CLIENT_SND "./new/*.c*") + list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) endif() if (USE_OPENAL) diff --git a/code/client/snd_dma_new.cpp b/code/client/snd_dma_new.cpp index efa4735d..c2227e4e 100644 --- a/code/client/snd_dma_new.cpp +++ b/code/client/snd_dma_new.cpp @@ -20,12 +20,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#if USE_SOUND_NEW - -# include "snd_local.h" -# include "snd_openal_new.h" -# include "client.h" -# include "cl_ui.h" +#include "snd_local.h" +#include "snd_openal_new.h" +#include "client.h" +#include "cl_ui.h" typedef struct { vec3_t origin; @@ -816,5 +814,3 @@ unsigned int S_GetMusicOffset() { return S_Driver_GetMusicOffset(); } - -#endif diff --git a/code/client/snd_mem_new.cpp b/code/client/snd_mem_new.cpp index ee9844db..d1ee0948 100644 --- a/code/client/snd_mem_new.cpp +++ b/code/client/snd_mem_new.cpp @@ -20,8 +20,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#if USE_SOUND_NEW - #include "snd_local.h" #include "cl_ui.h" @@ -570,5 +568,3 @@ qboolean S_LoadMP3(const char *fileName, sfx_t *sfx) return qtrue; } - -#endif diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 2884c784..d8d0b9ee 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -20,13 +20,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#if USE_SOUND_NEW - -# include "snd_local.h" -# include "snd_openal_new.h" -# include "client.h" -# include "../server/server.h" -# include "snd_codec.h" +#include "snd_local.h" +#include "snd_openal_new.h" +#include "client.h" +#include "../server/server.h" +#include "snd_codec.h" typedef struct { char *funcname; @@ -4180,5 +4178,3 @@ static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx) return true; } - -#endif From eb04e2682317ef8693ccebb53002afe890405a2f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 9 Aug 2024 20:33:59 +0200 Subject: [PATCH 0614/2040] Use the new libmad version as it seems stable enough --- code/client/CMakeLists.txt | 15 ++++++--------- code/client/snd_codec_mp3.c | 6 +----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index a768d968..e974e7af 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -34,21 +34,18 @@ if (USE_SOUND_NEW) list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.c$") file(GLOB SOURCES_CLIENT_SND "./snd_*_new.c*" "./snd_codec*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) - - set(OLD_VALUE ${BUILD_SHARED_LIBS}) - set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) - add_subdirectory("../libmad" "./libmad" EXCLUDE_FROM_ALL) - target_link_libraries(omohclient INTERFACE mad) - set(BUILD_SHARED_LIBS ${OLD_VALUE} CACHE BOOL "" FORCE) else() - add_subdirectory("../libmad-0.15.1b" "./libmad") - target_link_libraries(omohclient INTERFACE libmad) - list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.cpp$") file(GLOB_RECURSE SOURCES_CLIENT_SND "./new/*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) endif() +set(OLD_VALUE ${BUILD_SHARED_LIBS}) +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +add_subdirectory("../libmad" "./libmad" EXCLUDE_FROM_ALL) +target_link_libraries(omohclient INTERFACE mad) +set(BUILD_SHARED_LIBS ${OLD_VALUE} CACHE BOOL "" FORCE) + if (USE_OPENAL) # Try to use OpenAL find_package(OpenAL) diff --git a/code/client/snd_codec_mp3.c b/code/client/snd_codec_mp3.c index 06d1f1c7..47c1ac86 100644 --- a/code/client/snd_codec_mp3.c +++ b/code/client/snd_codec_mp3.c @@ -31,11 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_codec.h" // includes for the MP3 codec -#if USE_SOUND_NEW -# include "mad.h" -#else -# include "../libmad-0.15.1b/synth.h" -#endif +#include "mad.h" #define MP3_SAMPLE_WIDTH 2 #define MP3_PCMSAMPLES_PERSLICE 32 From bbb7aa3771a06482e0d31280870e3cc0be5f9a2c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Aug 2024 18:23:03 +0200 Subject: [PATCH 0615/2040] Updated CodeQL actions to use newer version of steps --- .github/workflows/codeql.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fc4f71a7..b2ebb262 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Setup SDL - name: Set up SDL @@ -52,7 +52,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # â„¹ï¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -79,6 +79,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" From deb18c53b7cda8176796dc30fd412d2fda75fe06 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:25:04 +0200 Subject: [PATCH 0616/2040] Implement streaming support for OpenAL See #333, and #324 --- code/client/snd_openal_new.cpp | 303 +++++++++++++++++++++++++++++++-- code/client/snd_openal_new.h | 45 ++++- 2 files changed, 327 insertions(+), 21 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index d8d0b9ee..d2037518 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2467,6 +2467,10 @@ void S_OPENAL_Update() S_OPENAL_StopLoopingSound(&openal.loop_sounds[i]); } } + + for (i = 0; i < MAX_OPENAL_CHANNELS; i++) { + openal.channel[i]->update(); + } } /* @@ -2930,7 +2934,6 @@ bool openal_channel::set_sfx(sfx_t *pSfx) qalGenBuffers(1, &pSfx->buffer); alDieIfError(); - //if (!_alutLoadMP3_LOKI(pSfx->buffer, pSfx->data, pSfx->length)) { if (!S_OPENAL_LoadMP3_Codec(pSfx->name, pSfx)) { qalDeleteBuffers(1, &pSfx->buffer); alDieIfError(); @@ -3742,14 +3745,14 @@ MUSIC_PlaySong */ qboolean MUSIC_PlaySong(const char *alias) { - int channel_number; - song_t *song; - int songnum; - int channel_to_play_on; - int fading_song; - openal_channel *song_channel; - unsigned int loop_start; - int rate; + int channel_number; + song_t *song; + int songnum; + int channel_to_play_on; + int fading_song; + openal_channel_two_d_stream *song_channel; + unsigned int loop_start; + int rate; fading_song = 0; songnum = MUSIC_FindSong(alias); @@ -3785,8 +3788,7 @@ qboolean MUSIC_PlaySong(const char *alias) MUSIC_StopChannel(channel_to_play_on); } - //if (!S_OPENAL_LoadMP3(FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), song->path), song_channel)) { - if (!S_OPENAL_LoadMP3(song->path, song_channel)) { + if (!song_channel->queue_stream(song->path)) { Com_DPrintf("Could not start music file '%s'!", song->path); return false; } @@ -3934,6 +3936,7 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs const char *pszRealName; float fVolume = 1.0; AliasListNode_t *pSoundAlias = NULL; + void *stream = NULL; if (!s_bSoundStarted) { return; @@ -3962,8 +3965,7 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs pszFilename = FS_BuildOSPath(Cvar_VariableString("fs_basepath"), FS_Gamedir(), pszRealName); - //if (!S_OPENAL_LoadMP3(pszFilename, &openal.chan_trig_music)) { - if (!S_OPENAL_LoadMP3(pszRealName, &openal.chan_trig_music)) { + if (!openal.chan_trig_music.queue_stream(pszRealName)) { S_OPENAL_InitChannel(OPENAL_CHANNEL_TRIGGER_MUSIC_ID, &openal.chan_trig_music); Com_DPrintf("Could not start triggered music '%s'\n", pszName); return; @@ -4178,3 +4180,278 @@ static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx) return true; } + +void openal_channel::update() +{ + +} + +void openal_channel_two_d_stream::stop() +{ + openal_channel::stop(); + + clear_stream(); +} + +bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { + ALint freq = 0; + snd_stream_t* stream; + int bytesToRead = 0; + int bytesRead; + char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; + + assert(!pSfx->buffer); + + stop(); + + sampleLoopCount = 1; + + this->pSfx = pSfx; + Q_strncpyz(this->fileName, pSfx->name, sizeof(this->fileName)); + + streamHandle = S_CodecLoad(pSfx->name, NULL); + if (!streamHandle) { + qalDeleteBuffers(1, &pSfx->buffer); + alDieIfError(); + + Com_Printf("OpenAL: Failed to load MP3.\n"); + return false; + } + + stream = (snd_stream_t*)streamHandle; + pSfx->info.channels = stream->info.channels; + pSfx->info.dataofs = stream->info.dataofs; + pSfx->info.datasize = stream->info.size; + pSfx->info.rate = stream->info.rate; + pSfx->info.samples = stream->info.samples; + pSfx->info.width = stream->info.width; + + pSfx->info.format = S_OPENAL_Format(stream->info.width, stream->info.channels); + if (!pSfx->info.format) { + Com_Printf( + "OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n", + pSfx->info.channels, + (int)(pSfx->info.width * 8.f), + pSfx->name + ); + + S_CodecCloseStream(stream); + return false; + } + + qalGenBuffers(MAX_STREAM_BUFFERS, buffers); + alDieIfError(); + + // Read a smaller sample + bytesToRead = Q_min(stream->info.width * stream->info.channels * (MAX_BUFFER_SAMPLES / 2), sizeof(rawData)); + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + if (!bytesRead) { + // Valid stream but no data? + S_CodecCloseStream(stream); + return true; + } + + qalBufferData(buffers[currentBuf], pSfx->info.format, rawData, bytesRead, stream->info.rate); + alDieIfError(); + + qalSourceQueueBuffers(source, 1, &buffers[currentBuf]); + alDieIfError(); + + qalSourceStop(source); + alDieIfError(); + + iBaseRate = stream->info.rate; + currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; + streaming = true; + + return true; +} + +void openal_channel_two_d_stream::set_sample_loop_count(S32 count) +{ + sampleLoopCount = count; + sampleLooped = 0; +} + +openal_channel_two_d_stream::openal_channel_two_d_stream() { + int i; + + streamHandle = NULL; + for (i = 0; i < MAX_STREAM_BUFFERS; i++) { + buffers[i] = 0; + } + currentBuf = 0; + sampleLoopCount = 0; + sampleLooped = 0; + streaming = false; +} + +void openal_channel_two_d_stream::update() +{ + snd_stream_t* stream = (snd_stream_t*)streamHandle; + int bytesToRead, bytesRead; + ALuint format; + ALint numProcessedBuffers = 0; + ALint numQueuedBuffers = 0; + ALint state = get_state(); + // 2 channels with a width of 2 + char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; + + if (!streaming) { + return; + } + + qalGetSourcei(source, AL_BUFFERS_PROCESSED, &numProcessedBuffers); + alDieIfError(); + + qalGetSourcei(source, AL_BUFFERS_QUEUED, &numQueuedBuffers); + alDieIfError(); + + // Unqueue processed buffers + while (numProcessedBuffers-- > 0) { + ALuint tmpBuffer; + qalSourceUnqueueBuffers(source, 1, &tmpBuffer); + } + + if (numQueuedBuffers >= MAX_STREAM_BUFFERS) { + return; + } + + if (sampleLoopCount && sampleLooped >= sampleLoopCount) { + if (!is_playing()) { + // Can clear the stream + clear_stream(); + } + return; + } + + bytesToRead = Q_min(stream->info.width * stream->info.channels * MAX_BUFFER_SAMPLES, sizeof(rawData)); + + format = S_OPENAL_Format(stream->info.width, stream->info.channels); + + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + if (!bytesRead) { + S_CodecCloseStream(stream); + + sampleLooped++; + if (sampleLoopCount && sampleLooped >= sampleLoopCount) { + // Finished the last loop + streamHandle = NULL; + return; + } + + streamHandle = S_CodecLoad(this->fileName, NULL); + if (!streamHandle) { + clear_stream(); + return; + } + + stream = (snd_stream_t*)streamHandle; + // + // Re-read the format, we never know... + // + format = S_OPENAL_Format(stream->info.width, stream->info.channels); + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + if (!bytesRead) { + S_CodecCloseStream(stream); + streamHandle = NULL; + return; + } + } + + qalBufferData(buffers[currentBuf], format, rawData, bytesRead, stream->info.rate); + alDieIfError(); + + qalSourceQueueBuffers(source, 1, &buffers[currentBuf]); + alDieIfError(); + + currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; +} + +bool openal_channel_two_d_stream::queue_stream(const char* fileName) { + + ALint freq = 0; + ALuint format = 0; + snd_stream_t* stream; + int bytesToRead = 0; + int bytesRead; + ALuint old = 0; + int i; + char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; + + // Store the filename so it can be looped later + Q_strncpyz(this->fileName, fileName, sizeof(this->fileName)); + clear_stream(); + + sampleLoopCount = 1; + + // + // Load the file + // + streamHandle = S_CodecLoad(this->fileName, NULL); + if (!streamHandle) { + return false; + } + stream = (snd_stream_t*)streamHandle; + + iStartTime = cl.serverTime; + iEndTime = (int)(cl.serverTime + (stream->info.samples / stream->info.rate * 1000.f)); + + format = S_OPENAL_Format(stream->info.width, stream->info.channels); + if (!format) { + Com_Printf( + "OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n", + pSfx->info.channels, + (int)(pSfx->info.width * 8.f), + pSfx->name + ); + + S_CodecCloseStream(stream); + return false; + } + + qalGenBuffers(MAX_STREAM_BUFFERS, buffers); + alDieIfError(); + + // Read a smaller sample + bytesToRead = Q_min(stream->info.width * stream->info.channels * (MAX_BUFFER_SAMPLES / 2), sizeof(rawData)); + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + if (!bytesRead) { + // Valid stream but no data? + return true; + } + + qalBufferData(buffers[currentBuf], format, rawData, bytesRead, stream->info.rate); + alDieIfError(); + + qalSourceQueueBuffers(source, 1, &buffers[currentBuf]); + alDieIfError(); + + currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; + + streaming = true; + + return true; +} + +void openal_channel_two_d_stream::clear_stream() { + if (!streaming) { + return; + } + + qalSourceStop(source); + qalSourcei(source, AL_BUFFER, 0); + qalSourceUnqueueBuffers(source, MAX_STREAM_BUFFERS, buffers); + qalDeleteBuffers(1, buffers); + + if (streamHandle) { + S_CodecCloseStream((snd_stream_t*)streamHandle); + } + + fileName[0] = 0; + streamHandle = NULL; + + currentBuf = 0; + streaming = false; + sampleLooped = 0; +} diff --git a/code/client/snd_openal_new.h b/code/client/snd_openal_new.h index f786c465..26f63a32 100644 --- a/code/client/snd_openal_new.h +++ b/code/client/snd_openal_new.h @@ -45,6 +45,9 @@ typedef unsigned int U32; #define OPENAL_CHANNEL_TRIGGER_MUSIC_ID (OPENAL_CHANNEL_MP3_ID + 1) #define OPENAL_CHANNEL_MOVIE_ID (OPENAL_CHANNEL_TRIGGER_MUSIC_ID + 1) +#define MAX_STREAM_BUFFERS 16 +#define MAX_BUFFER_SAMPLES 16384 + typedef enum { FADE_NONE, FADE_IN, @@ -103,7 +106,7 @@ struct openal_channel { public: void play(); - void stop(); + virtual void stop(); void pause(); void set_no_3d(); @@ -119,7 +122,7 @@ public: bool is_playing(); void force_free(); - bool set_sfx(sfx_t *pSfx); + virtual bool set_sfx(sfx_t *pSfx); void start_sample(); void stop_sample(); @@ -136,20 +139,46 @@ public: U32 sample_loop_count(); void set_sample_offset(U32 offset); void set_sample_ms_offset(U32 offset); - void set_sample_loop_count(S32 count); + virtual void set_sample_loop_count(S32 count); void set_sample_loop_block(S32 start_offset, S32 end_offset); U32 sample_status(); + +public: + virtual void update(); +}; + +struct openal_channel_two_d_stream : public openal_channel { +private: + char fileName[64]; + void *streamHandle; + unsigned int buffers[MAX_STREAM_BUFFERS]; + unsigned int currentBuf; + int sampleLoopCount; + int sampleLooped; + bool streaming; + +public: + openal_channel_two_d_stream(); + + void stop() override; + bool set_sfx(sfx_t* pSfx) override; + void set_sample_loop_count(S32 count) override; + void update() override; + bool queue_stream(const char* fileName); + +private: + void clear_stream(); }; struct openal_internal_t { openal_channel chan_3D[MAX_OPENAL_CHANNELS_3D]; openal_channel chan_2D[MAX_OPENAL_CHANNELS_2D]; - openal_channel chan_2D_stream[MAX_OPENAL_CHANNELS_2D_STREAM]; - openal_channel chan_song[MAX_OPENAL_SONGS]; - openal_channel chan_mp3; - openal_channel chan_trig_music; - openal_channel chan_movie; + openal_channel_two_d_stream chan_2D_stream[MAX_OPENAL_CHANNELS_2D_STREAM]; + openal_channel_two_d_stream chan_song[MAX_OPENAL_SONGS]; + openal_channel_two_d_stream chan_mp3; + openal_channel_two_d_stream chan_trig_music; + openal_channel_two_d_stream chan_movie; // Pointers to channels openal_channel *channel[MAX_OPENAL_CHANNELS]; From 679bfb90eae3791fd08873d7a67e528a48742882 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:38:39 +0200 Subject: [PATCH 0617/2040] Fix accessing 8th leaves element before finishing the loop This caused the 8th element to be taken into account when enabling optimizations with GCC (invalid pointer to the leaf) --- code/renderer/tr_sphere_shade.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_sphere_shade.cpp b/code/renderer/tr_sphere_shade.cpp index 0a039ef2..99ea54e2 100644 --- a/code/renderer/tr_sphere_shade.cpp +++ b/code/renderer/tr_sphere_shade.cpp @@ -1049,8 +1049,12 @@ static void RB_Sphere_BuildStaticLights() if (tr.world->vis) { int cntarea; - for (curleaf = 0, leaf = backEnd.currentSphere->leaves[curleaf]; curleaf < 8 && leaf; - curleaf++, leaf = backEnd.currentSphere->leaves[curleaf]) { + for (curleaf = 0; curleaf < 8; curleaf++) { + leaf = backEnd.currentSphere->leaves[curleaf]; + if (!leaf) { + break; + } + cntarea = leaf->numlights; if (cntarea) { From 81b8fe3f61ac0a2390b2f91513ffb10afa38ee6d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:42:45 +0200 Subject: [PATCH 0618/2040] Use a pointer to an array instead of accessing the tiki mesh field directly to avoid loop badly optimized due to the compiler thinking there can be only 1 element This fixes #337 --- code/tiki/tiki_files.cpp | 54 ++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 8ebe3ca0..fa23b8b2 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -302,8 +302,9 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapname, loadsurfaces, &numSurfacesSetUp, @@ -326,33 +331,33 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapmodelDataSize, keyValues ); - if (!temp.tiki.numMeshes) { + if (!temp_tiki->numMeshes) { Com_Printf("^~^~^ Model '%s' has no skelmodel\n", tikianim->name); return NULL; } defsize = sizeof(dtiki_t) - sizeof(tiki->mesh); - defsize += temp.tiki.numMeshes * sizeof(short); + defsize += temp_tiki->numMeshes * sizeof(short); defsize += strlen(name) + 1; defsize = PAD(defsize, sizeof(void *)); - defsize += temp.tiki.num_surfaces * sizeof(dtikisurface_t); + defsize += temp_tiki->num_surfaces * sizeof(dtikisurface_t); tiki = (dtiki_t *)TIKI_Alloc(defsize); memset(tiki, 0, defsize); start_ptr = (byte *)tiki; max_ptr = start_ptr + defsize; - ptr = start_ptr + sizeof(dtiki_t) - sizeof(tiki->mesh) + temp.tiki.numMeshes * sizeof(tiki->mesh[0]); + ptr = start_ptr + sizeof(dtiki_t) - sizeof(tiki->mesh) + temp_tiki->numMeshes * sizeof(tiki->mesh[0]); tiki->a = tikianim; tiki->m_boneList.InitChannels(); tiki->skeletor = NULL; - tiki->load_scale = temp.tiki.load_scale; - tiki->lod_scale = temp.tiki.lod_scale; - tiki->lod_bias = temp.tiki.lod_bias; - tiki->num_surfaces = temp.tiki.num_surfaces; - tiki->numMeshes = temp.tiki.numMeshes; - tiki->radius = temp.tiki.radius; + tiki->load_scale = temp_tiki->load_scale; + tiki->lod_scale = temp_tiki->lod_scale; + tiki->lod_bias = temp_tiki->lod_bias; + tiki->num_surfaces = temp_tiki->num_surfaces; + tiki->numMeshes = temp_tiki->numMeshes; + tiki->radius = temp_tiki->radius; tiki->name = (char *)ptr; strcpy(tiki->name, name); ptr += strlen(tiki->name) + 1; @@ -360,12 +365,13 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapm_boneList.ZeroChannels(); - assert((byte *)(tikiSurf + temp.tiki.num_surfaces) <= max_ptr); + assert((byte *)(tikiSurf + temp_tiki->num_surfaces) <= max_ptr); - for (i = 0; i < temp.tiki.numMeshes; i++) { - mesh = temp.tiki.mesh[i]; + for (i = 0; i < temp_tiki->numMeshes; i++) { + mesh = temp_tiki->mesh[i]; tiki->mesh[i] = mesh; - skelmodel = skelcache[mesh].skel; + + skelmodel = skelcache[mesh].skel; skelcache[mesh].numuses++; for (j = 0; j < skelmodel->numBones; j++) { @@ -374,8 +380,8 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapm_boneList.PackChannels(); - VectorCopy(temp.tiki.light_offset, tiki->light_offset); - VectorCopy(temp.tiki.load_origin, tiki->load_origin); + VectorCopy(temp_tiki->light_offset, tiki->light_offset); + VectorCopy(temp_tiki->load_origin, tiki->load_origin); tiki->surfaces = tikiSurf; for (i = 0; i < numSurfacesSetUp; i++) { @@ -386,8 +392,8 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapname, "all")) { - for (j = 0; j < temp.tiki.numMeshes; j++) { - mesh = temp.tiki.mesh[j]; + for (j = 0; j < temp_tiki->numMeshes; j++) { + mesh = temp_tiki->mesh[j]; skelmodel = TIKI_GetSkel(mesh); surf = skelmodel->pSurfaces; @@ -407,8 +413,8 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapnumSurfaces; } } else { - for (j = 0; j < temp.tiki.numMeshes; j++) { - mesh = temp.tiki.mesh[j]; + for (j = 0; j < temp_tiki->numMeshes; j++) { + mesh = temp_tiki->mesh[j]; skelmodel = TIKI_GetSkel(mesh); surf = skelmodel->pSurfaces; @@ -450,8 +456,8 @@ dtiki_t *TIKI_LoadTikiModel(dtikianim_t *tikianim, const char *name, con_mapnumSurfaces) { - skelmodel = TIKI_GetSkel(temp.tiki.mesh[i]); + for (i = 0; i < temp_tiki->numMeshes; i++, surfOffset += skelmodel->numSurfaces) { + skelmodel = TIKI_GetSkel(temp_tiki->mesh[i]); surf = skelmodel->pSurfaces; From f776d842d1d93bc506b157f544b96d8d8282501c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 14 Aug 2024 19:08:20 +0200 Subject: [PATCH 0619/2040] Don't load sound immediately if they must be streamed This removes more hiccups --- code/client/snd_mem_new.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/client/snd_mem_new.cpp b/code/client/snd_mem_new.cpp index d1ee0948..374a97f1 100644 --- a/code/client/snd_mem_new.cpp +++ b/code/client/snd_mem_new.cpp @@ -439,8 +439,6 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo return qfalse; } - // Removed because of OpenAL - /* if (streamed) { // // Added in 2.0 @@ -449,10 +447,9 @@ qboolean S_LoadSound(const char *fileName, sfx_t *sfx, int streamed, qboolean fo sfx->width = 1; sfx->iFlags |= SFX_FLAG_STREAMED; sfx->time_length = 5000.0; - sfx->data = 0; + sfx->data = NULL; return qtrue; } - */ if (clc.state != CA_LOADING && !force_load) { Com_Printf("**************S_LoadSound: %s\n", fileName); From 1254146223c7ceaf87323fc9ac4d3fbab7513e01 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:09:35 +0200 Subject: [PATCH 0620/2040] Fix streamed sound stopping before end --- code/client/snd_openal_new.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index d2037518..bba79e4d 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -4365,6 +4365,13 @@ void openal_channel_two_d_stream::update() qalSourceQueueBuffers(source, 1, &buffers[currentBuf]); alDieIfError(); + if (!is_playing()) { + // The sample has stopped during stream + // Could be because the storage is slow enough for the buffer + // or because the storage was powering on after standby + play(); + } + currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; } From 783c24d6f7198ac91219a47abde551b19f8e33c9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 17 Aug 2024 17:24:17 +0200 Subject: [PATCH 0621/2040] Fix sound never playing from entities that are not sent to clients --- code/client/snd_openal_new.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index bba79e4d..209cbe13 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1469,6 +1469,13 @@ void S_OPENAL_StartSound( if (bSupportWaitTillSoundDone) { pChannel->iTime = 0; } + + if (s_entity[iEntNum].time < pChannel->iTime) { + // Fixed in OPM + // Not sure if it's the real solution, but script_origin entities are usually + // never sent to client so the sound will immediately get stopped + pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; + } } else { VectorClear(pChannel->vOrigin); pChannel->iTime = 0; From a399fdf6cf881e954af36e31bad75393dfd5c754 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 17 Aug 2024 21:07:25 +0200 Subject: [PATCH 0622/2040] Removed useless comments --- code/client/snd_openal_new.cpp | 65 ---------------------------------- 1 file changed, 65 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 209cbe13..7b86034c 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1028,7 +1028,6 @@ static qboolean S_OPENAL_ShouldStart(const vec3_t vOrigin, float fMinDist, float qalGetListenerfv(AL_POSITION, alvec); - //VectorScale(alvec, 52.49f, vListenerOrigin); VectorCopy(alvec, vListenerOrigin); VectorSubtract(vOrigin, vListenerOrigin, vDir); @@ -1259,18 +1258,12 @@ static void S_OPENAL_Start2DSound( pChannel->iEntNum = 0; if (vOrigin) { - //pChannel->vOrigin[0] = -vOrigin[0]; - //pChannel->vOrigin[1] = vOrigin[2]; - //pChannel->vOrigin[2] = -vOrigin[1]; VectorCopy(vOrigin, pChannel->vOrigin); } } else { pChannel->iFlags &= ~CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = iRealEntNum; if (vOrigin) { - //pChannel->vOrigin[0] = -vOrigin[0]; - //pChannel->vOrigin[1] = vOrigin[2]; - //pChannel->vOrigin[2] = -vOrigin[1]; VectorCopy(vOrigin, pChannel->vOrigin); bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; @@ -1356,7 +1349,6 @@ void S_OPENAL_StartSound( return; } - //if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET)) //|| pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) if ((pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3)) || iEntChannel == CHAN_MENU || iEntChannel == CHAN_LOCAL) { S_OPENAL_Start2DSound(vOrigin, iEntNum, iEntChannel, pSfx, fVolume, fMinDist, fPitch, fMaxDist); @@ -1437,9 +1429,6 @@ void S_OPENAL_StartSound( pChannel->set_velocity(0, 0, 0); if (iEntNum == ENTITYNUM_NONE) { if (vOrigin) { - //pChannel->vOrigin[0] = -vOrigin[0]; - //pChannel->vOrigin[1] = vOrigin[2]; - //pChannel->vOrigin[2] = -vOrigin[1]; VectorCopy(vOrigin, pChannel->vOrigin); } else { //VectorClear(vOrigin); @@ -1448,20 +1437,12 @@ void S_OPENAL_StartSound( VectorClear(pChannel->vOrigin); } - /* - pChannel->set_position( - pChannel->vOrigin[0] / 52.49f, pChannel->vOrigin[1] / 52.49f, pChannel->vOrigin[2] / 52.49f - ); - */ pChannel->set_position(pChannel->vOrigin[0], pChannel->vOrigin[1], pChannel->vOrigin[2]); pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = 0; } else { pChannel->iEntNum = iEntNum; if (vOrigin) { - //pChannel->vOrigin[0] = -vOrigin[0]; - //pChannel->vOrigin[1] = vOrigin[2]; - //pChannel->vOrigin[2] = -vOrigin[1]; VectorCopy(vOrigin, pChannel->vOrigin); bSupportWaitTillSoundDone = cl.serverTime - 1 < 0; @@ -1558,12 +1539,6 @@ void S_OPENAL_AddLoopingSound( } pLoopSound = &openal.loop_sounds[iFreeLoopSound]; - //pLoopSound->vOrigin[0] = -vOrigin[0]; - //pLoopSound->vOrigin[1] = vOrigin[2]; - //pLoopSound->vOrigin[2] = -vOrigin[1]; - //pLoopSound->vVelocity[0] = -vVelocity[0] / 52.49f / 500.f; - //pLoopSound->vVelocity[1] = vVelocity[2] / 52.49f / 500.f; - //pLoopSound->vVelocity[2] = -vVelocity[1] / 52.49f / 500.f; VectorCopy(vOrigin, pLoopSound->vOrigin); VectorCopy(vVelocity, pLoopSound->vVelocity); pLoopSound->pSfx = pSfx; @@ -1815,12 +1790,6 @@ static int S_OPENAL_Start3DLoopSound( return -1; } - /* - pChan3D->set_position(vLoopOrigin[0] / 52.49f, pLoopSound->vVelocity[1] / 52.49f, vLoopOrigin[2] / 52.49f); - pChan3D->set_velocity( - pLoopSound->vVelocity[0] / 52.49f, vLoopOrigin[1] / 52.49f, pLoopSound->vVelocity[2] / 52.49f - ); - */ pChan3D->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]); pChan3D->set_velocity(pLoopSound->vVelocity[0], pLoopSound->vVelocity[1], pLoopSound->vVelocity[2]); pChan3D->pSfx = pLoopSound->pSfx; @@ -1874,7 +1843,6 @@ static bool S_OPENAL_UpdateLoopSound( pChannel->iStartTime = cl.serverTime; - //if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) // || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { vec3_t vOrigin; @@ -1904,7 +1872,6 @@ static bool S_OPENAL_UpdateLoopSound( pChannel->set_gain(fVolume); pChannel->set_sample_pan(iPan); } else { - //pChannel->set_position(vLoopOrigin[0] / 52.49f, vLoopOrigin[1] / 52.49f, vLoopOrigin[2] / 52.49f); pChannel->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]); pChannel->fVolume = fVolumeToPlay; pChannel->set_gain(fVolumeToPlay); @@ -1944,7 +1911,6 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) qalGetListenerfv(AL_POSITION, alvec); VectorCopy(alvec, vListenerOrigin); - //VectorScale(alvec, 52.49f, vListenerOrigin); for (i = 0; i < MAX_OPENAL_LOOP_SOUNDS; i++) { vec3_t vDir; @@ -2094,7 +2060,6 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name); } - //if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) //|| pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { iChannel = S_OPENAL_Start2DLoopSound( @@ -2170,9 +2135,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi // // Position // - //alvec[0] = -vHeadPos[0] / 52.49f; - //alvec[1] = vHeadPos[2] / 52.49f; - //alvec[2] = -vHeadPos[1] / 52.49f; VectorCopy(vHeadPos, alvec); VectorCopy(alvec, vListenerOrigin); qalListenerfv(AL_POSITION, alvec); @@ -2181,14 +2143,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi // // Orientation // - /* - alorientation[0][0] = -vAxis[0][0]; - alorientation[0][1] = vAxis[2][0]; - alorientation[0][2] = -vAxis[1][0]; - alorientation[1][0] = -vAxis[0][2]; - alorientation[1][1] = vAxis[2][2]; - alorientation[1][2] = -vAxis[1][2]; - */ alorientation[0][0] = vAxis[0][0]; alorientation[0][1] = vAxis[0][1]; alorientation[0][2] = vAxis[0][2]; @@ -2198,9 +2152,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi qalListenerfv(AL_ORIENTATION, (const ALfloat *)alorientation); alDieIfError(); - //vTempAxis[0] = -vAxis[0][1]; - //vTempAxis[1] = vAxis[2][1]; - //vTempAxis[2] = -vAxis[1][1]; VectorCopy(vAxis[1], vTempAxis); fVolume = 1; @@ -2231,7 +2182,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi fVolume = fMaxVolume; iPan = 64; } else { - //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); } } else { @@ -2249,7 +2199,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi * fMaxVolume; } } else { - //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); } } @@ -2259,7 +2208,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi fVolume = fMaxVolume; iPan = 64; } else { - //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); } } else { @@ -2271,9 +2219,6 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi } } else { VectorCopy(s_entity[pChannel->iEntNum].position, vEntOrigin); - //vOrigin[1] = vEntOrigin[2] / 52.49f; - //vOrigin[0] = -vEntOrigin[0] / 52.49f; - //vOrigin[2] = -vEntOrigin[1] / 52.49f; VectorCopy(vEntOrigin, vOrigin); VectorCopy(vOrigin, pChannel->vOrigin); pChannel->iTime = s_entity[pChannel->iEntNum].time; @@ -2306,15 +2251,9 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi (1.0 - (fDist - pChannel->fMinDist) / (pChannel->fMaxDist - pChannel->fMinDist)) * fMaxVolume; } } else { - //pChannel->set_position(vOrigin[0] / 52.49f, vOrigin[1] / 52.49f, vOrigin[2] / 52.49f); pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); VectorCopy(s_entity[pChannel->iEntNum].velocity, vEntVelocity); - - //vVelocity[0] = -vEntVelocity[0] / 52.49f / 500.f; - //vVelocity[1] = vEntVelocity[2] / 52.49f / 500.f; - //vVelocity[2] = -vEntVelocity[1] / 52.49f / 500.f; VectorCopy(vEntVelocity, vVelocity); - //pChannel->set_velocity(vVelocity[0] / 52.49f, vVelocity[1] / 52.49f, vVelocity[2] / 52.49f); pChannel->set_velocity(vVelocity[0], vVelocity[1], vVelocity[2]); } } @@ -3991,10 +3930,6 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs if (!autostart) { openal.chan_trig_music.pause(); } - - //if (autostart) { - // openal.chan_trig_music.play(); - //} } /* From 377b0896c255a09f73a44f2e73b97fdf93d16686 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 18 Aug 2024 12:03:01 +0200 Subject: [PATCH 0623/2040] Fix drivable vehicle not having the `death` waittill after loading from save This caused some vehicles to be destroyed immediately after being handled from script (like the halftrack in t2l1) --- code/fgame/vehicle.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index 158ee1dd..d8a7efb6 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -6857,11 +6857,6 @@ DrivableVehicle::DrivableVehicle */ DrivableVehicle::DrivableVehicle() { - if (LoadingSavegame) { - // Archive function will setup all necessary data - return; - } - AddWaitTill(STRING_DEATH); drivable = true; From 8c59d6020e138924518f370eab24effbf2ffdd50 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 18 Aug 2024 13:20:26 +0200 Subject: [PATCH 0624/2040] Backported ioquake3 fixes for https://www.cvedetails.com/cve/CVE-2017-11721/ (Buffer overflow) --- code/qcommon/huffman.c | 454 --------------------------------------- code/qcommon/huffman.cpp | 52 +++-- code/qcommon/msg.cpp | 43 ++-- code/qcommon/qcommon.h | 6 +- 4 files changed, 65 insertions(+), 490 deletions(-) delete mode 100644 code/qcommon/huffman.c diff --git a/code/qcommon/huffman.c b/code/qcommon/huffman.c deleted file mode 100644 index 0283fb70..00000000 --- a/code/qcommon/huffman.c +++ /dev/null @@ -1,454 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/* This is based on the Adaptive Huffman algorithm described in Sayood's Data - * Compression book. The ranks are not actually stored, but implicitly defined - * by the location of a node within a doubly-linked list */ - -#include "q_shared.h" -#include "qcommon.h" - -static int bloc = 0; - -void Huff_putBit( int bit, byte *fout, int *offset) { - bloc = *offset; - if ((bloc&7) == 0) { - fout[(bloc>>3)] = 0; - } - fout[(bloc>>3)] |= bit << (bloc&7); - bloc++; - *offset = bloc; -} - -int Huff_getBloc(void) -{ - return bloc; -} - -void Huff_setBloc(int _bloc) -{ - bloc = _bloc; -} - -int Huff_getBit( byte *fin, int *offset) { - int t; - bloc = *offset; - t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1; - bloc++; - *offset = bloc; - return t; -} - -/* Add a bit to the output file (buffered) */ -static void add_bit (char bit, byte *fout) { - if ((bloc&7) == 0) { - fout[(bloc>>3)] = 0; - } - fout[(bloc>>3)] |= bit << (bloc&7); - bloc++; -} - -/* Receive one bit from the input file (buffered) */ -static int get_bit (byte *fin) { - int t; - t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1; - bloc++; - return t; -} - -static node_t **get_ppnode(huff_t* huff) { - node_t **tppnode; - if (!huff->freelist) { - return &(huff->nodePtrs[huff->blocPtrs++]); - } else { - tppnode = huff->freelist; - huff->freelist = (node_t **)*tppnode; - return tppnode; - } -} - -static void free_ppnode(huff_t* huff, node_t **ppnode) { - *ppnode = (node_t *)huff->freelist; - huff->freelist = ppnode; -} - -/* Swap the location of these two nodes in the tree */ -static void swap (huff_t* huff, node_t *node1, node_t *node2) { - node_t *par1, *par2; - - par1 = node1->parent; - par2 = node2->parent; - - if (par1) { - if (par1->left == node1) { - par1->left = node2; - } else { - par1->right = node2; - } - } else { - huff->tree = node2; - } - - if (par2) { - if (par2->left == node2) { - par2->left = node1; - } else { - par2->right = node1; - } - } else { - huff->tree = node1; - } - - node1->parent = par2; - node2->parent = par1; -} - -/* Swap these two nodes in the linked list (update ranks) */ -static void swaplist(node_t *node1, node_t *node2) { - node_t *par1; - - par1 = node1->next; - node1->next = node2->next; - node2->next = par1; - - par1 = node1->prev; - node1->prev = node2->prev; - node2->prev = par1; - - if (node1->next == node1) { - node1->next = node2; - } - if (node2->next == node2) { - node2->next = node1; - } - if (node1->next) { - node1->next->prev = node1; - } - if (node2->next) { - node2->next->prev = node2; - } - if (node1->prev) { - node1->prev->next = node1; - } - if (node2->prev) { - node2->prev->next = node2; - } -} - -/* Do the increments */ -static void increment(huff_t* huff, node_t *node) { - node_t *lnode; - - if (!node) { - return; - } - - if (node->next != NULL && node->next->weight == node->weight) { - lnode = *node->head; - if (lnode != node->parent) { - swap(huff, lnode, node); - } - swaplist(lnode, node); - } - if (node->prev && node->prev->weight == node->weight) { - *node->head = node->prev; - } else { - *node->head = NULL; - free_ppnode(huff, node->head); - } - node->weight++; - if (node->next && node->next->weight == node->weight) { - node->head = node->next->head; - } else { - node->head = get_ppnode(huff); - *node->head = node; - } - if (node->parent) { - increment(huff, node->parent); - if (node->prev == node->parent) { - swaplist(node, node->parent); - if (*node->head == node) { - *node->head = node->parent; - } - } - } -} - -void Huff_addRef(huff_t* huff, byte ch) { - node_t *tnode, *tnode2; - if (huff->loc[ch] == NULL) { /* if this is the first transmission of this node */ - tnode = &(huff->nodeList[huff->blocNode++]); - tnode2 = &(huff->nodeList[huff->blocNode++]); - - tnode2->symbol = INTERNAL_NODE; - tnode2->weight = 1; - tnode2->next = huff->lhead->next; - if (huff->lhead->next) { - huff->lhead->next->prev = tnode2; - if (huff->lhead->next->weight == 1) { - tnode2->head = huff->lhead->next->head; - } else { - tnode2->head = get_ppnode(huff); - *tnode2->head = tnode2; - } - } else { - tnode2->head = get_ppnode(huff); - *tnode2->head = tnode2; - } - huff->lhead->next = tnode2; - tnode2->prev = huff->lhead; - - tnode->symbol = ch; - tnode->weight = 1; - tnode->next = huff->lhead->next; - if (huff->lhead->next) { - huff->lhead->next->prev = tnode; - if (huff->lhead->next->weight == 1) { - tnode->head = huff->lhead->next->head; - } else { - /* this should never happen */ - tnode->head = get_ppnode(huff); - *tnode->head = tnode2; - } - } else { - /* this should never happen */ - tnode->head = get_ppnode(huff); - *tnode->head = tnode; - } - huff->lhead->next = tnode; - tnode->prev = huff->lhead; - tnode->left = tnode->right = NULL; - - if (huff->lhead->parent) { - if (huff->lhead->parent->left == huff->lhead) { /* lhead is guaranteed to by the NYT */ - huff->lhead->parent->left = tnode2; - } else { - huff->lhead->parent->right = tnode2; - } - } else { - huff->tree = tnode2; - } - - tnode2->right = tnode; - tnode2->left = huff->lhead; - - tnode2->parent = huff->lhead->parent; - huff->lhead->parent = tnode->parent = tnode2; - - huff->loc[ch] = tnode; - - increment(huff, tnode2->parent); - } else { - increment(huff, huff->loc[ch]); - } -} - -/* Get a symbol */ -int Huff_Receive (node_t *node, int *ch, byte *fin) { - while (node && node->symbol == INTERNAL_NODE) { - if (get_bit(fin)) { - node = node->right; - } else { - node = node->left; - } - } - if (!node) { - return 0; -// Com_Error(ERR_DROP, "Illegal tree!"); - } - return (*ch = node->symbol); -} - -/* Get a symbol */ -void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset) { - bloc = *offset; - while (node && node->symbol == INTERNAL_NODE) { - if (bloc >= maxoffset) { - *ch = 0; - *offset = maxoffset + 1; - return; - } - if (get_bit(fin)) { - node = node->right; - } else { - node = node->left; - } - } - if (!node) { - *ch = 0; - return; -// Com_Error(ERR_DROP, "Illegal tree!"); - } - *ch = node->symbol; - *offset = bloc; -} - -/* Send the prefix code for this node */ -static void send(node_t *node, node_t *child, byte *fout, int maxoffset) { - if (node->parent) { - send(node->parent, node, fout, maxoffset); - } - if (child) { - if (bloc >= maxoffset) { - bloc = maxoffset + 1; - return; - } - if (node->right == child) { - add_bit(1, fout); - } else { - add_bit(0, fout); - } - } -} - -/* Send a symbol */ -void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset) { - int i; - if (huff->loc[ch] == NULL) { - /* node_t hasn't been transmitted, send a NYT, then the symbol */ - Huff_transmit(huff, NYT, fout, maxoffset); - for (i = 7; i >= 0; i--) { - add_bit((char)((ch >> i) & 0x1), fout); - } - } else { - send(huff->loc[ch], NULL, fout, maxoffset); - } -} - -void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset) { - bloc = *offset; - send(huff->loc[ch], NULL, fout, maxoffset); - *offset = bloc; -} - -void Huff_Decompress(msg_t *mbuf, int offset) { - int ch, cch, i, j, size; - byte seq[65536]; - byte* buffer; - huff_t huff; - - size = mbuf->cursize - offset; - buffer = mbuf->data + offset; - - if ( size <= 0 ) { - return; - } - - Com_Memset(&huff, 0, sizeof(huff_t)); - // Initialize the tree & list with the NYT node - huff.tree = huff.lhead = huff.ltail = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]); - huff.tree->symbol = NYT; - huff.tree->weight = 0; - huff.lhead->next = huff.lhead->prev = NULL; - huff.tree->parent = huff.tree->left = huff.tree->right = NULL; - - cch = buffer[0]*256 + buffer[1]; - // don't overflow with bad messages - if ( cch > mbuf->maxsize - offset ) { - cch = mbuf->maxsize - offset; - } - bloc = 16; - - for ( j = 0; j < cch; j++ ) { - ch = 0; - // don't overflow reading from the messages - // FIXME: would it be better to have an overflow check in get_bit ? - if ( (bloc >> 3) > size ) { - seq[j] = 0; - break; - } - Huff_Receive(huff.tree, &ch, buffer); /* Get a character */ - if ( ch == NYT ) { /* We got a NYT, get the symbol associated with it */ - ch = 0; - for ( i = 0; i < 8; i++ ) { - ch = (ch<<1) + get_bit(buffer); - } - } - - seq[j] = ch; /* Write symbol */ - - Huff_addRef(&huff, (byte)ch); /* Increment node */ - } - mbuf->cursize = cch + offset; - Com_Memcpy(mbuf->data + offset, seq, cch); -} - -extern int oldsize; - -void Huff_Compress(msg_t *mbuf, int offset) { - int i, ch, size; - byte seq[65536]; - byte* buffer; - huff_t huff; - - size = mbuf->cursize - offset; - buffer = mbuf->data + offset; - - if (size<=0) { - return; - } - - Com_Memset(&huff, 0, sizeof(huff_t)); - // Add the NYT (not yet transmitted) node into the tree/list */ - huff.tree = huff.lhead = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]); - huff.tree->symbol = NYT; - huff.tree->weight = 0; - huff.lhead->next = huff.lhead->prev = NULL; - huff.tree->parent = huff.tree->left = huff.tree->right = NULL; - - seq[0] = (size>>8); - seq[1] = size&0xff; - - bloc = 16; - - for (i=0; icursize = (bloc>>3) + offset; - Com_Memcpy(mbuf->data+offset, seq, (bloc>>3)); -} - -void Huff_Init(huffman_t *huff) { - - Com_Memset(&huff->compressor, 0, sizeof(huff_t)); - Com_Memset(&huff->decompressor, 0, sizeof(huff_t)); - - // Initialize the tree & list with the NYT node - huff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] = &(huff->decompressor.nodeList[huff->decompressor.blocNode++]); - huff->decompressor.tree->symbol = NYT; - huff->decompressor.tree->weight = 0; - huff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL; - huff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL; - - // Add the NYT (not yet transmitted) node into the tree/list */ - huff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] = &(huff->compressor.nodeList[huff->compressor.blocNode++]); - huff->compressor.tree->symbol = NYT; - huff->compressor.tree->weight = 0; - huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL; - huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL; -} - diff --git a/code/qcommon/huffman.cpp b/code/qcommon/huffman.cpp index b552390b..761717a8 100644 --- a/code/qcommon/huffman.cpp +++ b/code/qcommon/huffman.cpp @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -int bloc = 0; +static int bloc = 0; void Huff_putBit( int bit, byte *fout, int *offset) { bloc = *offset; @@ -39,6 +39,16 @@ void Huff_putBit( int bit, byte *fout, int *offset) { *offset = bloc; } +int Huff_getBloc(void) +{ + return bloc; +} + +void Huff_setBloc(int _bloc) +{ + bloc = _bloc; +} + int Huff_getBit( byte *fin, int *offset) { int t; bloc = *offset; @@ -263,15 +273,20 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { } if (!node) { return 0; -// Com_Error(ERR_DROP, "Illegal tree!\n"); +// Com_Error(ERR_DROP, "Illegal tree!"); } return (*ch = node->symbol); } /* Get a symbol */ -void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { +void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset) { bloc = *offset; while (node && node->symbol == INTERNAL_NODE) { + if (bloc >= maxoffset) { + *ch = 0; + *offset = maxoffset + 1; + return; + } if (get_bit(fin)) { node = node->right; } else { @@ -281,18 +296,22 @@ void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { if (!node) { *ch = 0; return; -// Com_Error(ERR_DROP, "Illegal tree!\n"); +// Com_Error(ERR_DROP, "Illegal tree!"); } *ch = node->symbol; *offset = bloc; } /* Send the prefix code for this node */ -static void send(node_t *node, node_t *child, byte *fout) { +static void send(node_t *node, node_t *child, byte *fout, int maxoffset) { if (node->parent) { - send(node->parent, node, fout); + send(node->parent, node, fout, maxoffset); } if (child) { + if (bloc >= maxoffset) { + bloc = maxoffset + 1; + return; + } if (node->right == child) { add_bit(1, fout); } else { @@ -302,22 +321,22 @@ static void send(node_t *node, node_t *child, byte *fout) { } /* Send a symbol */ -void Huff_transmit (huff_t *huff, int ch, byte *fout) { +void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset) { int i; if (huff->loc[ch] == NULL) { /* node_t hasn't been transmitted, send a NYT, then the symbol */ - Huff_transmit(huff, NYT, fout); + Huff_transmit(huff, NYT, fout, maxoffset); for (i = 7; i >= 0; i--) { add_bit((char)((ch >> i) & 0x1), fout); } } else { - send(huff->loc[ch], NULL, fout); + send(huff->loc[ch], NULL, fout, maxoffset); } } -void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) { +void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset) { bloc = *offset; - send(huff->loc[ch], NULL, fout); + send(huff->loc[ch], NULL, fout, maxoffset); *offset = bloc; } @@ -354,7 +373,7 @@ void Huff_Decompress(msg_t *mbuf, int offset) { for ( j = 0; j < cch; j++ ) { ch = 0; // don't overflow reading from the messages - // FIXME: would it be better to have a overflow check in get_bit ? + // FIXME: would it be better to have an overflow check in get_bit ? if ( (bloc >> 3) > size ) { seq[j] = 0; break; @@ -385,7 +404,7 @@ void Huff_Compress(msg_t *mbuf, int offset) { huff_t huff; size = mbuf->cursize - offset; - buffer = mbuf->data+ + offset; + buffer = mbuf->data + offset; if (size<=0) { return; @@ -398,16 +417,15 @@ void Huff_Compress(msg_t *mbuf, int offset) { huff.tree->weight = 0; huff.lhead->next = huff.lhead->prev = NULL; huff.tree->parent = huff.tree->left = huff.tree->right = NULL; - huff.loc[NYT] = huff.tree; - seq[0] = ( byte )(size>>8); - seq[1] = ( byte )size&0xff; + seq[0] = (byte)(size>>8); + seq[1] = (byte)(size&0xff); bloc = 16; for (i=0; imaxsize - msg->cursize < 4 ) { - msg->overflowed = qtrue; + if ( msg->overflowed ) { return; } @@ -294,6 +292,10 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { if (bits&7) { int nbits; nbits = bits&7; + if ( msg->bit + nbits > msg->maxsize << 3 ) { + msg->overflowed = qtrue; + return; + } for(i=0;idata, &msg->bit); value = (value>>1); @@ -302,8 +304,13 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { } if (bits) { for(i=0;idata, &msg->bit); + Huff_offsetTransmit( &msgHuff.compressor, (value & 0xff), msg->data, &msg->bit, msg->maxsize << 3 ); value = (value>>8); + + if ( msg->bit > msg->maxsize << 3 ) { + msg->overflowed = qtrue; + return; + } } } msg->cursize = (msg->bit>>3)+1; @@ -316,6 +323,10 @@ int MSG_ReadBits( msg_t *msg, int bits ) { qboolean sgn; int i, nbits; + if ( msg->readcount > msg->cursize ) { + return 0; + } + value = 0; if ( bits < 0 ) { @@ -358,6 +369,10 @@ int MSG_ReadBits( msg_t *msg, int bits ) { nbits = 0; if (bits&7) { nbits = bits&7; + if (msg->bit + nbits > msg->cursize << 3) { + msg->readcount = msg->cursize + 1; + return 0; + } for(i=0;idata, &msg->bit)<data, &msg->bit); + Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit, msg->cursize<<3); value |= (get<<(i+nbits)); + + if (msg->bit > msg->cursize<<3) { + msg->readcount = msg->cursize + 1; + return 0; + } } } msg->readcount = (msg->bit>>3)+1; @@ -758,7 +778,7 @@ char *MSG_ReadString( msg_t *msg ) { l = 0; do { c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds - if (!c || c == -1) { + if ( c == -1 || c == 0 ) { break; } // translate all fmt spec to avoid crash bugs @@ -790,10 +810,6 @@ char *MSG_ReadBigString( msg_t *msg ) { if ( c == '%' ) { c = '.'; } - // don't allow higher ascii values - if ( c > 127 ) { - c = '.'; - } string[l] = (char)c; l++; @@ -811,18 +827,13 @@ char *MSG_ReadStringLine( msg_t *msg ) { l = 0; do { c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds - if (c <= 0 || c == '\n') { - //if (c == -1 || c == 0 || c == '\n') { //Q3 + if (c == -1 || c == 0 || c == '\n') { break; } // translate all fmt spec to avoid crash bugs if ( c == '%' ) { c = '.'; } - // don't allow higher ascii values - if ( c > 127 ) { - c = '.'; - } string[l] = c; l++; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 3dcd5a44..c990ad7b 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -1426,9 +1426,9 @@ void Huff_Decompress(msg_t *buf, int offset); void Huff_Init(huffman_t *huff); void Huff_addRef(huff_t* huff, byte ch); int Huff_Receive (node_t *node, int *ch, byte *fin); -void Huff_transmit (huff_t *huff, int ch, byte *fout); -void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset); -void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset); +void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset); +void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset); +void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset); void Huff_putBit( int bit, byte *fout, int *offset); int Huff_getBit( byte *fout, int *offset); From 1f4b7718e8e9a7f5d2e100de41da9ec333b301ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Tue, 20 Aug 2024 22:30:18 +1000 Subject: [PATCH 0625/2040] Refactoring gameExport_s::ReadLevel() and gameExport_s::WriteLevel() --- code/fgame/g_main.cpp | 12 ++++++------ code/fgame/g_public.h | 4 ++-- code/server/sv_ccmds.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index 46c1119b..6eed1b71 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -1215,7 +1215,7 @@ G_ArchiveLevel ================= */ -qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, int *savedCgameStateSize, qboolean autosave, qboolean loading) +qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, size_t *savedCgameStateSize, qboolean autosave, qboolean loading) { try { int i; @@ -1258,8 +1258,8 @@ qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, int *saved // later objects need to post events when reading the archive. L_ArchiveEvents(arc); } - - arc.ArchiveInteger(savedCgameStateSize); + num = (int)*savedCgameStateSize; + arc.ArchiveInteger(&num); if (!arc.Saving()) { if (*savedCgameStateSize) { *savedCgameState = (byte*)gi.Malloc(*savedCgameStateSize); @@ -1267,7 +1267,7 @@ qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, int *saved *savedCgameState = NULL; } } - arc.ArchiveRaw(*savedCgameState, *savedCgameStateSize); + arc.ArchiveRaw((byte*)savedCgameState, *savedCgameStateSize); if (arc.Saving()) { str s; @@ -1437,7 +1437,7 @@ G_WriteLevel ================= */ -void G_WriteLevel(const char *filename, qboolean autosave, byte** savedCgameState, int* savedCgameStateSize) +void G_WriteLevel(const char *filename, qboolean autosave, byte** savedCgameState, size_t* savedCgameStateSize) { game.autosaved = autosave; G_ArchiveLevel(filename, savedCgameState, savedCgameStateSize, autosave, qfalse); @@ -1459,7 +1459,7 @@ calling ReadLevel. No clients are connected yet. ================= */ -qboolean G_ReadLevel(const char *filename, byte** savedCgameState, int* savedCgameStateSize) +qboolean G_ReadLevel(const char *filename, byte** savedCgameState, size_t* savedCgameStateSize) { qboolean status; diff --git a/code/fgame/g_public.h b/code/fgame/g_public.h index b790b4bf..e460f195 100644 --- a/code/fgame/g_public.h +++ b/code/fgame/g_public.h @@ -520,8 +520,8 @@ typedef struct gameExport_s { // ReadLevel is called after the default map information has been // loaded with SpawnEntities, so any stored client spawn spots will // be used when the clients reconnect. - void (*WriteLevel)(const char *filename, qboolean autosave, byte** savedCgameState, int* savedCgameStateSize); - qboolean (*ReadLevel)(const char *filename, byte** savedCgameState, int* savedCgameStateSize); + void (*WriteLevel)(const char *filename, qboolean autosave, byte** savedCgameState, size_t* savedCgameStateSize); + qboolean (*ReadLevel)(const char *filename, byte** savedCgameState, size_t* savedCgameStateSize); qboolean (*LevelArchiveValid)(const char *filename); void (*ArchiveInteger)(int *i); diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 88dba1c2..4188b521 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1878,7 +1878,7 @@ qboolean SV_ArchiveLevelFile(qboolean loading, qboolean autosave) name = Com_GetArchiveFileName(svs.gameName, "sav"); if (loading) { - if (!ge->ReadLevel(name, &cls.savedCgameState, &cls.savedCgameStateSize)) { + if (!ge->ReadLevel(name, (byte**)&cls.savedCgameState, &cls.savedCgameStateSize)) { return qfalse; } @@ -1901,7 +1901,7 @@ qboolean SV_ArchiveLevelFile(qboolean loading, qboolean autosave) else { cls.savedCgameStateSize = cge->CG_SaveStateToBuffer(&cls.savedCgameState, svs.time); - ge->WriteLevel(name, autosave, &cls.savedCgameState, &cls.savedCgameStateSize); + ge->WriteLevel(name, autosave, (byte**)&cls.savedCgameState, &cls.savedCgameStateSize); Z_Free(cls.savedCgameState); cls.savedCgameState = NULL; } From 16e0dc17a88d8871c72cd78131de3e3078745ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Wed, 21 Aug 2024 00:13:04 +1000 Subject: [PATCH 0626/2040] Add implicit conversion from const-qualified pointer types to non-const-qualified var --- code/qcommon/cvar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/cvar.c b/code/qcommon/cvar.c index 0e79aef2..d0846a3f 100644 --- a/code/qcommon/cvar.c +++ b/code/qcommon/cvar.c @@ -1606,7 +1606,7 @@ void Cvar_CompleteCvarName( const char *args, int argNum ) if( argNum == 2 ) { // Skip " " - char *p = Com_SkipTokens( args, 1, " " ); + char *p = Com_SkipTokens((char *)args, 1, " " ); if( p > args ) Field_CompleteCommand( p, qfalse, qtrue ); From 3b2e4ff9c13e64dd4994acc6d76b7ff0d2682790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Wed, 21 Aug 2024 00:17:05 +1000 Subject: [PATCH 0627/2040] Revert to original code --- code/fgame/g_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index 6eed1b71..0fe66af0 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -1267,7 +1267,7 @@ qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, size_t *sa *savedCgameState = NULL; } } - arc.ArchiveRaw((byte*)savedCgameState, *savedCgameStateSize); + arc.ArchiveRaw(*savedCgameState, *savedCgameStateSize); if (arc.Saving()) { str s; From 13911b051a58ba9d84ef5c2081a9a223ffc1ca96 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:35:06 +0200 Subject: [PATCH 0628/2040] Use OpenAL by default --- CMakeLists.txt | 4 ++-- code/client/CMakeLists.txt | 16 +++++++++++++--- code/client/cl_main.cpp | 10 +++++----- code/client/new/snd_main_new.cpp | 2 +- code/client/snd_info.cpp | 8 ++------ code/client/snd_local.h | 2 +- code/client/snd_public.h | 2 +- code/sdl/CMakeLists.txt | 13 ++++++++++++- docs/compiling.md | 11 +++++++---- 9 files changed, 44 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac6ed6c8..5cdf0e0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,10 +105,10 @@ INSTALL(TARGETS omohaaded DESTINATION "./") if (NOT BUILD_NO_CLIENT) ## Client app - + + add_subdirectory("code/client") add_subdirectory("code/renderer") add_subdirectory("code/sdl") - add_subdirectory("code/client") #include("code/renderergl2/glsl/shaders.cmake") #file(GLOB_RECURSE SOURCES_RENDERER "code/sdl/*.c" "code/renderercommon/*.c" "code/renderergl2/*.c" "code/renderergl2/*.cpp") diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index e974e7af..ff7660c8 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.5) project(omohclient) +option(NO_OPENAL "Use older sound-system" FALSE) + add_subdirectory("../cgame" "./cgame") file(GLOB SOURCES_CLIENT "./*.c*") @@ -18,11 +20,12 @@ target_link_libraries(omohclient INTERFACE gcd) # Sound stuff target_compile_definitions(omohclient INTERFACE USE_CODEC_MP3) -if (USE_SOUND_NEW) - # Try to use OpenAL +if (NOT NO_OPENAL) + # Use OpenAL find_package(OpenAL REQUIRED) + if (OPENAL_FOUND) - target_compile_definitions(omohclient INTERFACE USE_OPENAL=1 USE_SOUND_NEW=1) + target_compile_definitions(omohclient INTERFACE USE_OPENAL=1 NO_MODERN_DMA=0) if (MSVC) target_include_directories(omohclient INTERFACE ${OPENAL_INCLUDE_DIR}/AL) else() @@ -35,6 +38,13 @@ if (USE_SOUND_NEW) file(GLOB SOURCES_CLIENT_SND "./snd_*_new.c*" "./snd_codec*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) else() + # + # Fallback to old DMA sound system + # + message(NOTICE "OpenAL was explicitly disabled - fallback to old SDL sound system") + target_compile_definitions(omohclient INTERFACE NO_MODERN_DMA=1) + set(NO_MODERN_DMA TRUE) + list(FILTER SOURCES_CLIENT EXCLUDE REGEX "./snd_([a-zA-Z0-9_]+)\.cpp$") file(GLOB_RECURSE SOURCES_CLIENT_SND "./new/*.c*") list(APPEND SOURCES_CLIENT ${SOURCES_CLIENT_SND}) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 825ea52c..a2e61c3a 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -769,7 +769,7 @@ void CL_ShutdownAll(qboolean shutdownRef) { CL_cURL_Shutdown(); #endif // clear sounds -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA S_DisableSounds(); #endif // shutdown CGame @@ -1560,7 +1560,7 @@ void CL_Vid_Restart_f( void ) { CL_StartHunkUsers(qfalse); -#if defined(USE_SOUND_NEW) && USE_SOUND_NEW +#if !defined(NO_MODERN_DMA) || !NO_MODERN_DMA s_bSoundPaused = true; S_LoadData(&save); #else @@ -1597,7 +1597,7 @@ handles will be invalid ================= */ void CL_Snd_Restart_f( void ) { -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA S_Shutdown(); S_Init(); CL_Vid_Restart_f(); @@ -3492,7 +3492,7 @@ void CL_Init( void ) { Cvar_Set( "cl_running", "1" ); -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA S_Init2(); #else S_Init(qtrue); @@ -3537,7 +3537,7 @@ void CL_Shutdown(const char* finalmsg, qboolean disconnect, qboolean quit) { if(disconnect) CL_Disconnect(); -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA S_Shutdown(); #else S_Shutdown(qtrue); diff --git a/code/client/new/snd_main_new.cpp b/code/client/new/snd_main_new.cpp index 66fa6f1f..58deebe1 100644 --- a/code/client/new/snd_main_new.cpp +++ b/code/client/new/snd_main_new.cpp @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../snd_local.h" #include "../client.h" -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA qboolean s_bSoundPaused = qfalse; diff --git a/code/client/snd_info.cpp b/code/client/snd_info.cpp index 6cbdc02b..6fa56996 100644 --- a/code/client/snd_info.cpp +++ b/code/client/snd_info.cpp @@ -20,10 +20,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#if USE_SOUND_NEW - -# include "snd_local.h" -# include "../qcommon/tiki.h" +#include "snd_local.h" +#include "../qcommon/tiki.h" void load_sfx_info() { @@ -95,5 +93,3 @@ void load_sfx_info() sfx_infos[0].name[0] = 0; } - -#endif diff --git a/code/client/snd_local.h b/code/client/snd_local.h index e0ec8609..04c6ba9f 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/qcommon.h" #include "snd_public.h" -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA #define PAINTBUFFER_SIZE 4096 // this is in samples diff --git a/code/client/snd_public.h b/code/client/snd_public.h index f348cdc9..596e066f 100644 --- a/code/client/snd_public.h +++ b/code/client/snd_public.h @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#if !defined(USE_SOUND_NEW) || !USE_SOUND_NEW +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA #ifdef __cplusplus extern "C" { diff --git a/code/sdl/CMakeLists.txt b/code/sdl/CMakeLists.txt index 27c9e804..db79ee2f 100644 --- a/code/sdl/CMakeLists.txt +++ b/code/sdl/CMakeLists.txt @@ -1,12 +1,23 @@ cmake_minimum_required(VERSION 3.5) project(omohsdl) -file(GLOB_RECURSE SOURCES_SDL "./*.c") +file(GLOB SOURCES_SDL +"./sdl_gamma.c" +"./sdl_glimp.c" +"./sdl_input.c" +) + +if (NO_MODERN_DMA) + list(APPEND SOURCES_SDL "./sdl_snd.c") +endif() add_library(omohsdl STATIC ${SOURCES_SDL}) target_compile_features(omohsdl PUBLIC c_variadic_macros) target_link_libraries(omohsdl PRIVATE qcommon qcommon_standalone) +if (NO_MODERN_DMA) + target_compile_definitions(omohsdl PRIVATE NO_MODERN_DMA=1) +endif() if(${CMAKE_VERSION} VERSION_GREATER "3.11") cmake_policy(SET CMP0074 NEW) diff --git a/docs/compiling.md b/docs/compiling.md index dd9c6f4f..393329bc 100644 --- a/docs/compiling.md +++ b/docs/compiling.md @@ -5,19 +5,21 @@ OpenMoHAA supports any architecture, thanks to the CMake build system and cross- The following tools are required for all platforms: - CMake >= 3.5 - Flex (>= 2.6.4) and Bison (>= 3.5.1) -- A C++11 compiler is also required. +- A C++11 compiler +- OpenAL SDK (can be found [here](https://github.com/kcat/openal-soft)) The installation directory can be set to the MOHAA directory. By default, the build will produce both the client and dedicated server versions. The client can be omitted from the build by appending `-DBUILD_NO_CLIENT=1` to the CMake command-line arguments. Using this parameter will result in only the server portion being built. -The experimental OpenAL-based sound system can be used by appending `-DUSE_SOUND_NEW=1` to the CMake command-line arguments. +OpenAL can be disabled by appending `-DNO_OPENAL=1` to the CMake command-line arguments. The old SDL-based sound system will be used instead, it lacks some features such as ambient sounds. ## Compiling for Linux These are the tools required on Linux : - Clang >= 3.3 or GCC >= 4.8.5 - libsdl2-dev +- libopenal-dev **clang-3.5** and **gcc-4.8.5** should work (tested on Ubuntu 16.04), but the latest version should be used. @@ -25,7 +27,7 @@ Ubuntu 20.04 is the minimum version required to fully compile the project succes 1 line install command with clang: ```sh -sudo apt-get install -y cmake ninja-build clang lld flex bison libsdl2-dev +sudo apt-get install -y cmake ninja-build clang lld flex bison libsdl2-dev libopenal-dev ``` Example with **CMake** and **ninja-build** installed: @@ -41,5 +43,6 @@ Other compilers can be specified by appending `-DCMAKE_C_COMPILER=/path/to/compi Visual Studio (2019 or 2022) is generally preferred. Flex and Bison can be downloaded from here: https://github.com/lexxmark/winflexbison/releases/tag/v2.5.25 +OpenAL can be downloaded from here: https://github.com/kcat/openal-soft/releases/tag/1.23.1 -Append `-DFLEX_EXECUTABLE=...\win_flex.exe -DBISON_EXECUTABLE=...\win_bison.exe` to the CMake command-line to use the package from the link above. +Append `-DFLEX_EXECUTABLE=...\win_flex.exe -DBISON_EXECUTABLE=...\win_bison.exe -DOPENAL_INCLUDE_DIR="path/to/oal/include" -DOPENAL_LIBRARY="path/to/oal"` to the CMake command-line to use the package from the link above. From f2b49f7ccb831ffafbf24d2e21de05dc6657e60f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:42:54 +0200 Subject: [PATCH 0629/2040] Fix wrong parameters --- code/null/null_snddma.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/code/null/null_snddma.c b/code/null/null_snddma.c index 28cfb1ec..8bd0c65b 100644 --- a/code/null/null_snddma.c +++ b/code/null/null_snddma.c @@ -50,17 +50,23 @@ void SNDDMA_Submit(void) void SNDDMA_Activate(void) { } -sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed ) -{ - return 0; -} - -void S_StartLocalSound( sfxHandle_t sfx, int channelNum ) { -} - void S_ClearSoundBuffer( void ) { } int S_IsSoundPlaying( int channel_number, const char *sfxName ){ return 0; } + +#if defined(NO_MODERN_DMA) && NO_MODERN_DMA +void S_StartLocalSound(sfxHandle_t sfx, int channelNum) { +} +sfxHandle_t S_RegisterSound(const char* sample, qboolean compressed) { + return 0; +} +#else +void S_StartLocalSound(const char* sound_name, qboolean force_load) { +} +sfxHandle_t S_RegisterSound(const char* name, int streamed, qboolean force_load) { + return 0; +} +#endif From faa50352e0a83ab69f3110092e90f601d55abf02 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:53:57 +0200 Subject: [PATCH 0630/2040] Remove explicit USE_SOUND_NEW as OpenAL is the default --- .github/workflows/build-cmake.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 417d4e8f..02e29a05 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -99,7 +99,7 @@ jobs: - name: Configure CMake working-directory: ${{github.workspace}} run: | - cmake -B ./build ${{ env.CMAKE_PARAM }} -DUSE_SOUND_NEW=1 ./source + cmake -B ./build ${{ env.CMAKE_PARAM }} ./source - name: Build working-directory: ${{github.workspace}} @@ -204,7 +204,7 @@ jobs: - name: Configure CMake working-directory: ${{github.workspace}} run: | - cmake -B ./build ${{ env.CMAKE_PARAM }} -DUSE_SOUND_NEW=1 ./source + cmake -B ./build ${{ env.CMAKE_PARAM }} ./source - name: Build working-directory: ${{github.workspace}} From d78de51bc23669a34b668c18b9b4ffa5d6ab5397 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:02:23 +0200 Subject: [PATCH 0631/2040] Bump version number --- code/qcommon/q_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/q_version.h b/code/qcommon/q_version.h index 743ea48c..13d220c3 100644 --- a/code/qcommon/q_version.h +++ b/code/qcommon/q_version.h @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // // These values are the only one that must be set for the version #define PRODUCT_VERSION_MAJOR 0 -#define PRODUCT_VERSION_MINOR 62 +#define PRODUCT_VERSION_MINOR 70 #define PRODUCT_VERSION_PATCH 0 #define PRODUCT_VERSION_SUFFIX "alpha" From 219dbbb5b731034a791cd717de54fcd430523331 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:39:14 +0200 Subject: [PATCH 0632/2040] Open the default device by passing in the default device name instead of NULL --- code/client/snd_openal_new.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 7b86034c..81157efc 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -268,7 +268,11 @@ static bool S_OPENAL_InitContext() dev = NULL; } - Com_Printf("OpenAL: Opening device %s...\n", dev ? dev : "{default}"); + if (!dev) { + dev = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + } + + Com_Printf("OpenAL: Opening device \"%s\"...\n", dev ? dev : "{default}"); al_device = qalcOpenDevice(dev); if (!al_device) { From 4839a2026b805c5f11b0253026168ed99133393b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:42:34 +0200 Subject: [PATCH 0633/2040] Fix string casting --- code/client/snd_openal_new.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 81157efc..9f0e862c 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -27,9 +27,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_codec.h" typedef struct { - char *funcname; - void **funcptr; - bool required; + const char *funcname; + void **funcptr; + bool required; } extensions_table_t; # define MAX_MUSIC_SONGS 16 @@ -282,11 +282,17 @@ static bool S_OPENAL_InitContext() } Com_Printf("OpenAL: Device opened successfully.\n"); - al_frequency = 22050; - if (s_khz->integer == 11) { + switch (s_khz->integer) { + case 11: al_frequency = 11025; - } else if (s_khz->integer == 44) { + break; + default: + case 22: + al_frequency = 22050; + break; + case 44: al_frequency = 44100; + break; } attrlist[0] = 256; @@ -362,7 +368,7 @@ static bool S_OPENAL_InitExtensions() *i->funcptr = qalGetProcAddress(i->funcname); if (!*i->funcptr) { - Com_Printf("...not found! [%s]\n", qalGetError()); + Com_Printf("...not found! %d [%s]\n", qalGetError(), qalGetString(qalGetError())); if (i->required) { S_OPENAL_NukeContext(); return false; From f67a7c66218eaab6089898254f55d3cc276de389 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 13:30:04 +0200 Subject: [PATCH 0634/2040] List available devices and use Generic Software if Generic Hardware is the default --- code/client/snd_openal_new.cpp | 69 ++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 9f0e862c..3367d75c 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -54,6 +54,7 @@ cvar_t *s_obstruction_cal_time; cvar_t *s_lastSoundTime; // Added in OPM cvar_t *s_openaldriver; +cvar_t *s_alAvailableDevices; static float reverb_table[] = { 0.5f, 0.25f, 0.417f, 0.653f, 0.208f, 0.5f, 0.403f, 0.5f, 0.5f, @@ -89,6 +90,9 @@ int music_loaded = 0; int music_numsongs = 0; int music_currentsong = 0; +static qboolean enumeration_ext = qfalse; +static qboolean enumeration_all_ext = qfalse; + song_t music_songs[MAX_MUSIC_SONGS]; openal_internal_t openal; static float s_fFadeStartTime; @@ -268,13 +272,72 @@ static bool S_OPENAL_InitContext() dev = NULL; } - if (!dev) { - dev = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); - } + + // Device enumeration support + enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"); + enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"); + + if(enumeration_ext || enumeration_all_ext) + { + char devicenames[16384] = ""; + const char *devicelist; +#ifdef _WIN32 + const char *defaultdevice; +#endif + int curlen; + + // get all available devices + the default device name. + if(enumeration_all_ext) + { + devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); +#ifdef _WIN32 + defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); +#endif + } + else + { + // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. + devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); +#ifdef _WIN32 + defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); +#endif + enumeration_ext = qtrue; + } + +#ifdef _WIN32 + // check whether the default device is generic hardware. If it is, change to + // Generic Software as that one works more reliably with various sound systems. + // If it's not, use OpenAL's default selection as we don't want to ignore + // native hardware acceleration. + if(!dev && defaultdevice && !strcmp(defaultdevice, "Generic Hardware")) + dev = "Generic Software"; +#endif + + // dump a list of available devices to a cvar for the user to see. + + if(devicelist) + { + while((curlen = strlen(devicelist))) + { + Q_strcat(devicenames, sizeof(devicenames), devicelist); + Q_strcat(devicenames, sizeof(devicenames), "\n"); + + devicelist += curlen + 1; + } + } + + s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); + Com_Printf("OpenAL: List of available devices:\n%s\n", devicenames); + } Com_Printf("OpenAL: Opening device \"%s\"...\n", dev ? dev : "{default}"); al_device = qalcOpenDevice(dev); + if (!al_device && dev) { + Com_Printf("Failed to open OpenAL device '%s', trying default.\n", dev); + al_device = qalcOpenDevice(NULL); + } + if (!al_device) { Com_Printf("OpenAL: Could not open device\n"); S_OPENAL_NukeContext(); From 037cb0f5cbdec50720c63fd51306fe51b61f466a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:18:20 +0200 Subject: [PATCH 0635/2040] Fix OpenAL64.dll name on Win32 and Win64 --- .github/workflows/build-cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 02e29a05..8c535def 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -183,7 +183,7 @@ jobs: cmake --build ./build --config ${{env.BUILD_TYPE}} cmake --install ./build --config ${{env.BUILD_TYPE}} # Unfortunately soft-oal produces a binary called OpenAL32 even in 64-bit - if ([Environment]::Is64BitOperatingSystem) { Rename-Item -Path '.\install\bin\OpenAL32.dll' -NewName 'OpenAL64.dll' } + if ("${{ matrix.architecture.config }}" -eq "x64") { Rename-Item -Path '.\install\bin\OpenAL32.dll' -NewName 'OpenAL64.dll' } - uses: actions/checkout@v4 with: From e46625a52cfa9e54be9182b814112b9a2870d36b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:38:45 +0200 Subject: [PATCH 0636/2040] Added more verbosity --- code/client/snd_openal_new.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 3367d75c..6c334afa 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -272,6 +272,7 @@ static bool S_OPENAL_InitContext() dev = NULL; } + Com_DPrintf("OpenAL: Context initialization\n"); // Device enumeration support enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"); @@ -289,6 +290,7 @@ static bool S_OPENAL_InitContext() // get all available devices + the default device name. if(enumeration_all_ext) { + Com_DPrintf("OpenAL: Fetching all devices\n"); devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); #ifdef _WIN32 defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); @@ -296,6 +298,7 @@ static bool S_OPENAL_InitContext() } else { + Com_DPrintf("OpenAL: Fetching current device\n"); // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); #ifdef _WIN32 @@ -304,6 +307,8 @@ static bool S_OPENAL_InitContext() enumeration_ext = qtrue; } + Com_DPrintf("OpenAL: Default playback device: \"%s\"\n", defaultdevice); + #ifdef _WIN32 // check whether the default device is generic hardware. If it is, change to // Generic Software as that one works more reliably with various sound systems. @@ -326,8 +331,9 @@ static bool S_OPENAL_InitContext() } } - s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); Com_Printf("OpenAL: List of available devices:\n%s\n", devicenames); + + s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); } Com_Printf("OpenAL: Opening device \"%s\"...\n", dev ? dev : "{default}"); From 5e60b89a0dddc292be3b0722bdbca5cee01c5f47 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:13:03 +0200 Subject: [PATCH 0637/2040] Fix linux compile error --- code/client/snd_openal_new.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 6c334afa..53c3bd24 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -307,7 +307,9 @@ static bool S_OPENAL_InitContext() enumeration_ext = qtrue; } +#ifdef _WIN32 Com_DPrintf("OpenAL: Default playback device: \"%s\"\n", defaultdevice); +#endif #ifdef _WIN32 // check whether the default device is generic hardware. If it is, change to From 9526a92fc1a188e9543ee562fcd47cfa15fb0039 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:35:44 +0200 Subject: [PATCH 0638/2040] Use same parameters as oal to build OpenAL --- .github/workflows/build-cmake.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 8c535def..620130f6 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -41,7 +41,8 @@ jobs: - name: Install required packages run: | - sudo apt update && sudo apt install -y flex bison libopenal-dev + sudo apt update && sudo apt install -y flex bison \ + libpulse-dev portaudio19-dev libasound2-dev libjack-dev libpipewire-0.3-dev qtbase5-dev libdbus-1-dev - name: Install required cross-platform packages (${{ matrix.architecture.triple }}) if: matrix.architecture.name != 'amd64' @@ -179,7 +180,11 @@ jobs: run: | cmake -B ./build -A ${{ matrix.architecture.config }} ` -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ` - -DCMAKE_INSTALL_PREFIX='${{github.workspace}}/thirdparties/soft-oal/install' + -DCMAKE_INSTALL_PREFIX='${{github.workspace}}/thirdparties/soft-oal/install' ` + -DALSOFT_BUILD_ROUTER=OFF ` + -DALSOFT_REQUIRE_WINMM=ON ` + -DALSOFT_REQUIRE_DSOUND=ON ` + -DALSOFT_REQUIRE_WASAPI=ON cmake --build ./build --config ${{env.BUILD_TYPE}} cmake --install ./build --config ${{env.BUILD_TYPE}} # Unfortunately soft-oal produces a binary called OpenAL32 even in 64-bit From f84ed6b794c2d892a29395204ef94b8c9178acd2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 11:48:50 +0200 Subject: [PATCH 0639/2040] Fix crash when loading from save, caused by incorrect client-game state size Closes #343 --- code/fgame/g_main.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/fgame/g_main.cpp b/code/fgame/g_main.cpp index 0fe66af0..79e7119d 100644 --- a/code/fgame/g_main.cpp +++ b/code/fgame/g_main.cpp @@ -1258,14 +1258,19 @@ qboolean G_ArchiveLevel(const char *filename, byte** savedCgameState, size_t *sa // later objects need to post events when reading the archive. L_ArchiveEvents(arc); } - num = (int)*savedCgameStateSize; - arc.ArchiveInteger(&num); + if (!arc.Saving()) { + arc.ArchiveInteger(&num); + *savedCgameStateSize = num; + if (*savedCgameStateSize) { *savedCgameState = (byte*)gi.Malloc(*savedCgameStateSize); } else { *savedCgameState = NULL; } + } else { + num = (int)*savedCgameStateSize; + arc.ArchiveInteger(&num); } arc.ArchiveRaw(*savedCgameState, *savedCgameStateSize); From a529b37f25bc6257d77b51c047baa8259e927a2f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:07:28 +0200 Subject: [PATCH 0640/2040] Show some AL errors on developer mode only --- code/client/snd_openal_new.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 53c3bd24..e092a493 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2965,7 +2965,7 @@ bool openal_channel::set_sfx(sfx_t *pSfx) qalDeleteBuffers(1, &pSfx->buffer); alDieIfError(); - Com_Printf("OpenAL: Failed to load MP3.\n"); + Com_DPrintf("OpenAL: Failed to load MP3.\n"); return false; } @@ -4237,7 +4237,7 @@ bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { qalDeleteBuffers(1, &pSfx->buffer); alDieIfError(); - Com_Printf("OpenAL: Failed to load MP3.\n"); + Com_DPrintf("OpenAL: Failed to load MP3.\n"); return false; } @@ -4251,7 +4251,7 @@ bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { pSfx->info.format = S_OPENAL_Format(stream->info.width, stream->info.channels); if (!pSfx->info.format) { - Com_Printf( + Com_DPrintf( "OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n", pSfx->info.channels, (int)(pSfx->info.width * 8.f), From 8c41576daa877096926771cf3c5eda8cb336e050 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:13:17 +0200 Subject: [PATCH 0641/2040] Remove assertion as sounds can be streamed at any time --- code/client/snd_openal_new.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index e092a493..899918a7 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -4223,8 +4223,6 @@ bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { int bytesRead; char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; - assert(!pSfx->buffer); - stop(); sampleLoopCount = 1; From 7bebb2adab4899d0cf380a207f822910f4f899f1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:51:47 +0200 Subject: [PATCH 0642/2040] Statically link the CRT runtime in soft-oal --- .github/workflows/build-cmake.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index 620130f6..fabd2315 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -175,6 +175,8 @@ jobs: path: 'thirdparties/soft-oal' ref: '1.23.1' + # soft-oal build + # Statically link the CRT runtime into OAL as a workaround to prevent crashes - name: Configure and install soft-oal working-directory: ${{github.workspace}}/thirdparties/soft-oal run: | @@ -184,7 +186,13 @@ jobs: -DALSOFT_BUILD_ROUTER=OFF ` -DALSOFT_REQUIRE_WINMM=ON ` -DALSOFT_REQUIRE_DSOUND=ON ` - -DALSOFT_REQUIRE_WASAPI=ON + -DALSOFT_REQUIRE_WASAPI=ON ` + -DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG" ` + -DCMAKE_CXX_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG" ` + -DCMAKE_C_FLAGS_MINSIZEREL="/MT /O2 /Ob2 /DNDEBUG" ` + -DCMAKE_CXX_FLAGS_MINSIZEREL="/MT /O1 /Ob1 /DNDEBUG" ` + -DCMAKE_C_FLAGS_RELWITHDEBINFO="/MT /Zi /O2 /Ob1 /DNDEBUG" ` + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="/MT /Zi /O2 /Ob1 /DNDEBUG" cmake --build ./build --config ${{env.BUILD_TYPE}} cmake --install ./build --config ${{env.BUILD_TYPE}} # Unfortunately soft-oal produces a binary called OpenAL32 even in 64-bit From 01a0173a2f70cd8c728d18b4e9b6c4d08eaad996 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:52:30 +0200 Subject: [PATCH 0643/2040] Take all branches into account for GitHub actions --- .github/workflows/build-cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-cmake.yml b/.github/workflows/build-cmake.yml index fabd2315..2279210c 100644 --- a/.github/workflows/build-cmake.yml +++ b/.github/workflows/build-cmake.yml @@ -3,7 +3,7 @@ name: Build on: push: branches: - - '*' + - '**' pull_request: workflow_call: From b5ffe756d680db0767aa2e030580cdb4a8d46d4f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:38:41 +0200 Subject: [PATCH 0644/2040] Fix buffers unnecessarily being unqueued after source has stopped --- code/client/snd_openal_new.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 899918a7..7ee25fd7 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -4469,7 +4469,6 @@ void openal_channel_two_d_stream::clear_stream() { qalSourceStop(source); qalSourcei(source, AL_BUFFER, 0); - qalSourceUnqueueBuffers(source, MAX_STREAM_BUFFERS, buffers); qalDeleteBuffers(1, buffers); if (streamHandle) { From 8832fbe55de683431ceb426ac692b586cbdc48e0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:02:10 +0200 Subject: [PATCH 0645/2040] Fix entities loopsound incorrectly having the streamed value at the end of the name, causing some sounds unable to load --- code/fgame/g_utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/fgame/g_utils.cpp b/code/fgame/g_utils.cpp index 8fca9c03..a603c31c 100644 --- a/code/fgame/g_utils.cpp +++ b/code/fgame/g_utils.cpp @@ -1197,6 +1197,7 @@ void G_ArchiveEdict(Archiver& arc, gentity_t *edict) arc.ArchiveString(&tempStr); if (tempStr.length()) { + tempStr[tempStr.length() - 1] = 0; edict->s.loopSound = gi.soundindex(tempStr.c_str(), true); } else { edict->s.loopSound = 0; From b2ef0fd6e364e053c82c882724707db06ebfe2ae Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:09:12 +0200 Subject: [PATCH 0646/2040] Swap the save game struct on big endian architectures --- code/client/cl_uiloadsave.cpp | 1 + code/qcommon/q_shared.c | 9 +++++++++ code/qcommon/q_shared.h | 4 +++- code/server/sv_ccmds.c | 3 +++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/code/client/cl_uiloadsave.cpp b/code/client/cl_uiloadsave.cpp index a0b8e566..25785048 100644 --- a/code/client/cl_uiloadsave.cpp +++ b/code/client/cl_uiloadsave.cpp @@ -155,6 +155,7 @@ void UIFAKKLoadGameClass::SetupFiles(void) FS_Read(&save, sizeof(savegamestruct_t), f); FS_FCloseFile(f); + Com_SwapSaveStruct(&save); if (save.version != SAVEGAME_STRUCT_VERSION) { // wrong save game version diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index b9d679a0..61b88ea1 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -2190,3 +2190,12 @@ int Com_IndexForGrowListElement(const growList_t * list, const void *element) } return -1; } + +void Com_SwapSaveStruct(savegamestruct_t* save) { + save->version = LittleLong(save->version); + save->time = LittleLong(save->time); + save->mapTime = LittleLong(save->mapTime); + + save->tm_loopcount = LittleLong(save->tm_loopcount); + save->tm_offset = LittleLong(save->tm_offset); +} diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index accd20d1..946867b8 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -1107,6 +1107,8 @@ int Com_AddToGrowList(growList_t * list, void *data); void *Com_GrowListElement(const growList_t * list, int index); int Com_IndexForGrowListElement(const growList_t * list, const void *element); +void Com_SwapSaveStruct(struct savegamestruct_s* save); + //============================================= @@ -1458,7 +1460,7 @@ typedef struct { #define SAVEGAME_STRUCT_VERSION 4 -typedef struct { +typedef struct savegamestruct_s { int version; int time; int mapTime; diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 4188b521..970b9635 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1887,6 +1887,7 @@ qboolean SV_ArchiveLevelFile(qboolean loading, qboolean autosave) if (f) { FS_Read(&save, sizeof(savegamestruct_t), f); + Com_SwapSaveStruct(&save); if (save.version != SAVEGAME_STRUCT_VERSION) { FS_FCloseFile(f); @@ -2007,6 +2008,7 @@ qboolean SV_ArchiveServerFile( qboolean loading, qboolean autosave ) save.tm_loopcount = 0; } + Com_SwapSaveStruct(&save); FS_Write( &save, sizeof( savegamestruct_t ), f ); S_Save( f ); CM_WritePortalState( f ); @@ -2026,6 +2028,7 @@ qboolean SV_ArchiveServerFile( qboolean loading, qboolean autosave ) } FS_Read(&save, sizeof(savegamestruct_t), f); + Com_SwapSaveStruct(&save); if (save.version != SAVEGAME_STRUCT_VERSION) { Com_Printf("Invalid or Old Server SaveGame Version\n"); From 53d5dd1e4033a7529bde07711b8af092b2bb6a4f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:25:16 +0200 Subject: [PATCH 0647/2040] Differentiate saves from mohaa, mohta and mohtt Fixes #339 where Spearhead and Breakthrough would also display saves from mohaa --- code/client/cl_uiloadsave.cpp | 4 ++++ code/qcommon/q_shared.c | 2 +- code/qcommon/q_shared.h | 10 +++++++++- code/server/sv_ccmds.c | 3 +++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/code/client/cl_uiloadsave.cpp b/code/client/cl_uiloadsave.cpp index 25785048..a48e0f72 100644 --- a/code/client/cl_uiloadsave.cpp +++ b/code/client/cl_uiloadsave.cpp @@ -162,6 +162,10 @@ void UIFAKKLoadGameClass::SetupFiles(void) continue; } + if (save.type != com_target_game->integer) { + continue; + } + gametime = (save.mapTime / 1000); date = save.time; diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 61b88ea1..90a8b290 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -2192,7 +2192,7 @@ int Com_IndexForGrowListElement(const growList_t * list, const void *element) } void Com_SwapSaveStruct(savegamestruct_t* save) { - save->version = LittleLong(save->version); + save->version = LittleShort(save->version); save->time = LittleLong(save->time); save->mapTime = LittleLong(save->mapTime); diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 946867b8..d286a7f0 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -1461,7 +1461,15 @@ typedef struct { #define SAVEGAME_STRUCT_VERSION 4 typedef struct savegamestruct_s { - int version; + //int version + // Modified in OPM + //=== + short version; + // The type matches com_target_game + byte type; + // Currently unused + byte flags; + //=== int time; int mapTime; char comment[ 64 ]; diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 970b9635..cb710e43 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1992,6 +1992,9 @@ qboolean SV_ArchiveServerFile( qboolean loading, qboolean autosave ) SV_SetConfigstring( CS_SAVENAME, "" ); save.version = SAVEGAME_STRUCT_VERSION; + save.type = com_target_game->integer; + save.flags = 0; + save.time = aclock; strncpy( save.mapName, svs.mapName, sizeof( save.mapName ) ); strncpy( save.saveName, svs.gameName, sizeof( save.saveName ) ); From e3936f52a23e85ad4d61d94ec1abd6abf8e68ef9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:35:13 +0200 Subject: [PATCH 0648/2040] Move Com_SwapSaveStruct to a better place --- code/qcommon/common.cpp | 9 +++++++++ code/qcommon/q_shared.c | 9 --------- code/qcommon/q_shared.h | 2 -- code/qcommon/qcommon.h | 1 + 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 5edc49db..464dbb3b 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -2403,6 +2403,15 @@ qboolean COM_IsMapValid(const char* name) { */ } +void Com_SwapSaveStruct(savegamestruct_t* save) { + save->version = LittleShort(save->version); + save->time = LittleLong(save->time); + save->mapTime = LittleLong(save->mapTime); + + save->tm_loopcount = LittleLong(save->tm_loopcount); + save->tm_offset = LittleLong(save->tm_offset); +} + //------------------------------------------------------------------------ diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 90a8b290..b9d679a0 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -2190,12 +2190,3 @@ int Com_IndexForGrowListElement(const growList_t * list, const void *element) } return -1; } - -void Com_SwapSaveStruct(savegamestruct_t* save) { - save->version = LittleShort(save->version); - save->time = LittleLong(save->time); - save->mapTime = LittleLong(save->mapTime); - - save->tm_loopcount = LittleLong(save->tm_loopcount); - save->tm_offset = LittleLong(save->tm_offset); -} diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index d286a7f0..63f6dd31 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -1107,8 +1107,6 @@ int Com_AddToGrowList(growList_t * list, void *data); void *Com_GrowListElement(const growList_t * list, int index); int Com_IndexForGrowListElement(const growList_t * list, const void *element); -void Com_SwapSaveStruct(struct savegamestruct_s* save); - //============================================= diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index c990ad7b..6baab452 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -1096,6 +1096,7 @@ const char *Com_GetArchiveFolder(); void Com_WipeSavegame( const char *savename ); qboolean Com_ShiftedStrStr(const char* shifted, const char* name, int offset); qboolean COM_IsMapValid(const char* name); +void Com_SwapSaveStruct(savegamestruct_t* save); /* From d6d40975e5f2ac4512cb8cdab818d0070f2f460b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:30:33 +0200 Subject: [PATCH 0649/2040] Add more file debug print --- code/fgame/g_utils.cpp | 60 +++++++++--------------------------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/code/fgame/g_utils.cpp b/code/fgame/g_utils.cpp index a603c31c..57eaf3c9 100644 --- a/code/fgame/g_utils.cpp +++ b/code/fgame/g_utils.cpp @@ -96,7 +96,6 @@ G_TouchTriggers ============ */ void G_TouchTriggers(Entity *ent) - { int i; int num; @@ -142,7 +141,6 @@ to force all entities it covers to immediately touch it ============ */ void G_TouchSolids(Entity *ent) - { int i; int num; @@ -171,7 +169,6 @@ void G_TouchSolids(Entity *ent) } void G_ShowTrace(trace_t *trace, const gentity_t *passent, const char *reason) - { str text; str pass; @@ -237,7 +234,6 @@ void G_ShowSightTrace(gentity_t *passent1, gentity_t *passent2, const char *reas } void G_CalcBoundsOfMove(Vector& start, Vector& end, Vector& mins, Vector& maxs, Vector *minbounds, Vector *maxbounds) - { Vector bmin; Vector bmax; @@ -378,7 +374,6 @@ trace_t G_Trace( const char *reason, qboolean tracedeep ) - { int entnum; trace_t trace; @@ -420,7 +415,6 @@ trace_t G_Trace( const char *reason, qboolean tracedeep ) - { gentity_t *ent; int entnum; @@ -466,7 +460,6 @@ void G_TraceEntities( int contentmask, qboolean bIncludeTriggers ) - { trace_t trace; vec3_t boxmins; @@ -544,7 +537,6 @@ Returns the distance to the nearest player from the given spot ================ */ float PlayersRangeFromSpot(Entity *spot) - { Entity *player; float bestplayerdistance; @@ -583,7 +575,6 @@ to other players ================ */ Entity *SelectRandomDeathmatchSpawnPoint(void) - { Entity *spot, *spot1, *spot2; int count = 0; @@ -642,7 +633,6 @@ SelectFarthestDeathmatchSpawnPoint ================ */ Entity *SelectFarthestDeathmatchSpawnPoint(void) - { Entity *bestspot; float bestdistance; @@ -672,7 +662,6 @@ Entity *SelectFarthestDeathmatchSpawnPoint(void) } Entity *SelectDeathmatchSpawnPoint(void) - { if (DM_FLAG(DF_SPAWN_FARTHEST)) { return SelectFarthestDeathmatchSpawnPoint(); @@ -693,7 +682,6 @@ is not a staircase. int c_yes, c_no; qboolean M_CheckBottom(Entity *ent) - { Vector mins, maxs, start, stop; trace_t trace; @@ -766,7 +754,6 @@ realcheck: } Entity *G_FindClass(Entity *ent, const char *classname) - { int entnum; gentity_t *from; @@ -790,7 +777,6 @@ Entity *G_FindClass(Entity *ent, const char *classname) } Entity *G_FindTarget(Entity *ent, const char *name) - { SimpleEntity *next; @@ -845,7 +831,6 @@ Entity *G_FindRandomTarget(const char *name) } Entity *G_NextEntity(Entity *ent) - { gentity_t *from; @@ -879,7 +864,6 @@ Entity *G_NextEntity(Entity *ent) // just constant angles. // Vector G_GetMovedir(float angle) - { if (angle == -1) { return Vector(0, 0, 1); @@ -927,7 +911,6 @@ of ent. Ent should be unlinked before calling this! ================= */ qboolean KillBox(Entity *ent) - { int i; int num; @@ -979,9 +962,8 @@ qboolean KillBox(Entity *ent) } qboolean IsNumeric(const char *str) - { - int len; + size_t len; int i; qboolean dot; @@ -1014,7 +996,6 @@ findradius (org, radius) ================= */ Entity *findradius(Entity *startent, Vector org, float rad) - { Vector eorg; gentity_t *from; @@ -1069,7 +1050,6 @@ findclientinradius (org, radius) ================= */ Entity *findclientsinradius(Entity *startent, Vector org, float rad) - { Vector eorg; gentity_t *ed; @@ -1104,7 +1084,6 @@ Entity *findclientsinradius(Entity *startent, Vector org, float rad) } Vector G_CalculateImpulse(Vector start, Vector end, float speed, float gravity) - { float traveltime, vertical_speed; Vector dir, xydir, velocity; @@ -1122,7 +1101,6 @@ Vector G_CalculateImpulse(Vector start, Vector end, float speed, float gravity) } Vector G_PredictPosition(Vector start, Vector target, Vector targetvelocity, float speed) - { Vector projected; float traveltime; @@ -1143,7 +1121,6 @@ G_ArchiveEdict ============== */ void G_ArchiveEdict(Archiver& arc, gentity_t *edict) - { int i; str tempStr; @@ -1332,7 +1309,6 @@ Sets the pos trajectory for a fixed position =============== */ void G_SetTrajectory(gentity_t *ent, vec3_t org) - { ent->s.pos.trTime = 0; VectorClear(ent->s.pos.trDelta); @@ -1348,7 +1324,6 @@ Sets the encoded constant light parameter for entities =============== */ void G_SetConstantLight(int *constantlight, float *red, float *green, float *blue, float *radius, int *lightStyle) - { int ir, ig, ib, iradius; @@ -1444,46 +1419,45 @@ void G_ProcessCacheInitCommands(dtiki_t *tiki) } void CacheResource(const char *stuff) - { AliasListNode_t *ret; qboolean streamed = qfalse; char filename[MAX_STRING_TOKENS]; + assert(stuff); if (!stuff) { return; } + if (gi.fsDebug->integer == 2) { + Com_Printf("server cache: %s\n", stuff); + } + if (!strchr(stuff, '.')) { // must be a global alias stuff = gi.GlobalAlias_FindRandom(stuff, &ret); if (!stuff) { - if (gi.fsDebug->integer) { + if (gi.fsDebug->integer == 2) { Com_Printf("alias not found\n"); } return; } streamed = ret->streamed; + if (gi.fsDebug->integer == 2) { + Com_Printf("=> %s\n", stuff); + } } strcpy(filename, stuff); gi.FS_CanonicalFilename(filename); - if (strstr(filename, ".wav")) { - gi.soundindex(filename, streamed); - } else if (strstr(filename, ".mp3")) { + if (strstr(filename, ".wav") || strstr(filename, ".mp3")) { gi.soundindex(filename, streamed); } else if (strstr(filename, ".tik")) { dtiki_t *tiki; - if (*stuff && strncmp("models/", stuff, 7)) { - sprintf(filename, "models/%s", stuff); - } else { - strcpy(filename, stuff); - } - - gi.FS_CanonicalFilename(filename); + Q_strncpyz(filename, CanonicalTikiName(stuff), sizeof(filename)); tiki = gi.TIKI_RegisterModel(filename); @@ -1791,7 +1765,6 @@ void CloneEntity(Entity *dest, Entity *src) } weaponhand_t WeaponHandNameToNum(str side) - { if (!side.length()) { gi.DPrintf("WeaponHandNameToNum : Weapon hand not specified\n"); @@ -1808,7 +1781,6 @@ weaponhand_t WeaponHandNameToNum(str side) } const char *WeaponHandNumToName(weaponhand_t hand) - { switch (hand) { case WEAPON_MAIN: @@ -1821,7 +1793,6 @@ const char *WeaponHandNumToName(weaponhand_t hand) } firemode_t WeaponModeNameToNum(str mode) - { if (!mode.length()) { gi.DPrintf("WeaponModeNameToNum : Weapon mode not specified\n"); @@ -1913,7 +1884,6 @@ str G_WeaponClassNumToName(int num) } void G_DebugTargets(Entity *e, str from) - { gi.DPrintf("DEBUGTARGETS:%s ", from.c_str()); @@ -1931,7 +1901,6 @@ void G_DebugTargets(Entity *e, str from) } void G_DebugDamage(float damage, Entity *victim, Entity *attacker, Entity *inflictor) - { gi.DPrintf( "Victim:%s Attacker:%s Inflictor:%s Damage:%f\n", @@ -1954,7 +1923,6 @@ void G_FadeOut(float delaytime) } void G_AutoFadeIn(void) - { level.m_fade_time_start = 1; level.m_fade_time = 1; @@ -1967,7 +1935,6 @@ void G_AutoFadeIn(void) } void G_ClearFade(void) - { level.m_fade_time = -1; level.m_fade_type = fadein; @@ -2030,7 +1997,6 @@ void G_PlayerDied(float delaytime) } void G_MissionFailed(void) - { // Make the music system play the failure music for this level ChangeMusic("failure", "normal", true); @@ -2044,14 +2010,12 @@ void G_MissionFailed(void) } void G_StartCinematic(void) - { level.cinematic = true; gi.cvar_set("sv_cinematic", "1"); } void G_StopCinematic(void) - { // clear out the skip thread level.cinematic = false; From 56775399d31c2bc3e1e1531fce57870967b55f6d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:38:42 +0200 Subject: [PATCH 0650/2040] Fix 3D sounds not being attached to an entity when specified --- code/client/snd_openal_new.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 7ee25fd7..559a939b 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1522,6 +1522,7 @@ void S_OPENAL_StartSound( pChannel->iFlags |= CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = 0; } else { + pChannel->iFlags &= ~CHANNEL_FLAG_NO_ENTITY; pChannel->iEntNum = iEntNum; if (vOrigin) { VectorCopy(vOrigin, pChannel->vOrigin); From 6506577787baac22a2269580c025d17a044b38f7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 00:16:46 +0200 Subject: [PATCH 0651/2040] Add shader flags with tcMod rotate This fixes vehicle wheels rotating forever. Wheels now rotate consistently depending on the vehicle speed --- code/renderer/tr_shader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index 50797274..8c0d8edb 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -685,6 +685,7 @@ static void ParseTexMod( char *_text, shaderStage_t *stage, int cntBundle ) } tmi->type = TMOD_ROTATE; + shader.flags |= 2; } else if (!Q_stricmp(token, "offset")) { token = COM_ParseExt(text, qfalse); From 32b0b2dfac35b8fce92cbfa0d5b383fe51ea7ba1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 00:38:06 +0200 Subject: [PATCH 0652/2040] Fix camera angles changing too much when switching between linked turrets --- code/fgame/vehicleturret.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/fgame/vehicleturret.cpp b/code/fgame/vehicleturret.cpp index a100b02b..c2c2071a 100644 --- a/code/fgame/vehicleturret.cpp +++ b/code/fgame/vehicleturret.cpp @@ -2041,7 +2041,7 @@ void VehicleTurretGunTandem::RemoteControl(usercmd_t *ucmd, Sentient *owner) vNewCmdAng = Vector(SHORT2ANGLE(ucmd->angles[0]), SHORT2ANGLE(ucmd->angles[1]), SHORT2ANGLE(ucmd->angles[2])); - if (vNewCmdAng[0] || vNewCmdAng[1] || vNewCmdAng[2]) { + if (m_vUserLastCmdAng[0] || m_vUserLastCmdAng[1] || m_vUserLastCmdAng[2]) { m_vUserViewAng[0] += AngleSubtract(vNewCmdAng[0], m_vUserLastCmdAng[0]); m_vUserViewAng[1] += AngleSubtract(vNewCmdAng[1], m_vUserLastCmdAng[1]); m_vUserViewAng[2] += AngleSubtract(vNewCmdAng[2], m_vUserLastCmdAng[2]); @@ -2062,7 +2062,7 @@ void VehicleTurretGunTandem::RemoteControlSecondary(usercmd_t *ucmd, Sentient *o vNewCmdAng = Vector(SHORT2ANGLE(ucmd->angles[0]), SHORT2ANGLE(ucmd->angles[1]), SHORT2ANGLE(ucmd->angles[2])); - if (vNewCmdAng[0] || vNewCmdAng[1] || vNewCmdAng[2]) { + if (m_vUserLastCmdAng[0] || m_vUserLastCmdAng[1] || m_vUserLastCmdAng[2]) { m_vUserViewAng[0] += AngleSubtract(vNewCmdAng[0], m_vUserLastCmdAng[0]); m_vUserViewAng[1] += AngleSubtract(vNewCmdAng[1], m_vUserLastCmdAng[1]); m_vUserViewAng[2] += AngleSubtract(vNewCmdAng[2], m_vUserLastCmdAng[2]); From 1c8b4a1922a17bd2eaa9b59806d0dcaee5c9988c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 01:03:36 +0200 Subject: [PATCH 0653/2040] Update the documentation to reflect the current state of the project --- README.md | 10 +++++----- docs/features.md | 2 +- docs/features_implementation.md | 22 ++++++++++++---------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 10317740..cf18a7e5 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ The main goal of OpenMoHAA is to ensure the future and continuity of **Medal of ## Current state +### Single-player + +The entire single-player campaign can be played from start to end. There may be occasional bugs though; if you encounter any, please create a GitHub issue describing them. + ### Multiplayer The Multiplayer part is almost fully stable. @@ -34,13 +38,9 @@ Server admins can use OpenMoHAA to [host](docs/getting_started_installation.md#s All game modes including `Tug-of-War` from Medal of Honor: Spearhead, and `Liberation` from Medal of Honor: Breakthrough are implemented and are working as intended. Mods like `Freeze-Tag` are working as well. -### Single-player - -The `training` map can be played from start to end. The single-player campaign is not fully functional, but at least AI can breathe, talk, run, and shoot. - ## Features -- [What's working and what's not](docs/features_implementation.md) +- [What's working](docs/features_implementation.md) - [New features](docs/features.md) - [Scripting commands](https://htmlpreview.github.io/?https://github.com/openmoh/openmohaa/blob/main/docs/features_g_allclasses.html) diff --git a/docs/features.md b/docs/features.md index 707af024..8c1f3a49 100644 --- a/docs/features.md +++ b/docs/features.md @@ -8,7 +8,7 @@ A lot of bugs and exploits from MOH:AA were fixed in OpenMoHAA (BOF exploit, gre - Features from ioquake3 - IPv6 support (from ioquake3) -- Features from SH 2.15 and BT 2.40 +- Features from MOH: Spearhead 2.15 and MOH: Breakthrough 2.40 ### Server-side diff --git a/docs/features_implementation.md b/docs/features_implementation.md index f013c171..3895a2c1 100644 --- a/docs/features_implementation.md +++ b/docs/features_implementation.md @@ -2,24 +2,26 @@ ## Server -The server version can be built successfully, but some features are not functional. For example, the Actor system is almost fully implemented, but it is not yet stable. This means that Actor may not work as expected and could cause crashes. - -Overall, the server and the fgame components are almost fully implemented, but they may not be completely stable. There could be some minor bugs (and rare crashes), but the game should be playable. +The server version can be built successfully. The server and the fgame components are fully implemented, the single-player campaign can be played from start to end in MOH:AA, MOH:SH and MOH:BT. However there could be some minor bugs (and rare crashes), but overall, the game should be playable. ## Client -The client version of OpenMoHAA has undergone partial implementation, with the cgame module being nearly completed. Credits to the SDK of **Heavy Metal: F.A.K.K. 2** both the cgame and fgame modules. +The client version of OpenMoHAA is also fully implemented with a few bugs remaining, and with the cgame module being nearly completed. Credits to the SDK of **Heavy Metal: F.A.K.K. 2** both the cgame and fgame modules. + +OpenMoHAA is using OpenAL for the audio. The current operational status for each component is as follow: | Component | Full | Almost | Half | Early | Bad | Not working | Comment | |-------------------------|------|--------|------|-------|-----|-------------|-------------------------------------------------------------------| -| Audio | | | | | x | | Very basic implementation from Quake III | -| CG Module | | x | | | | | Missing FX, Marks and decals | +| Audio | x | | | | | | Full implementation using OpenAL, there may still be some bugs | +| CG Module | | x | | | | | Need more fixes for FX, marks and decals | | Client | x | | | | | | | | Collision | x | | | | | | | | Model/TIKI/Skeletor | x | | | | | | | -| Renderer | | x | | | | | Missing ghost, marks, sphere lights, sky portal, sun flare, swipe | -| Server | | x | | | | | Probably a few bugs remaining | -| Server module (fgame) | | x | | | | | Actor, and few gameplay bugs | -| UI | | x | | | | | A few bugs to fix | +| Renderer | x | x | | | | | Missing ghost, sun flare, swipe, some lighting bugs | +| Server | x | | | | | | | +| Server module (fgame) | x | | | | | | There might still be some AI/gameplay bugs | +| UI | x | | | | | | | + +Full = code is fully working, however it doesn't mean it's bug-free. From 3b94904ea83486c23d49fe723daf1168d01d2829 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 12:01:37 +0200 Subject: [PATCH 0654/2040] Update getting started --- docs/getting_started_running.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/getting_started_running.md b/docs/getting_started_running.md index 33c1a070..1edcb433 100644 --- a/docs/getting_started_running.md +++ b/docs/getting_started_running.md @@ -2,13 +2,15 @@ ## Game selection +**Medal of Honor: Allied Assault** is the default game, but expansions are also supported. + **Medal of Honor: Allied Assault Spearhead** and **Medal of Honor: Allied Assault Breakthrough** are supported in OpenMoHAA using the `com_target_game` variable. To play an expansion, append the following command-line arguments to the executable: -- `+set com_target_game 1` for Spearhead (mohaas/mohta) -- `+set com_target_game 2` for Breakthrough (mohaab/mohtt) +- `+set com_target_game 1` for Spearhead (mohaas/mohta, mainta) +- `+set com_target_game 2` for Breakthrough (mohaab/mohtt, maintt) On Windows, you can create a shortcut to OpenMoHAA with these command-line arguments. -The default value of `com_target_game` is 0 for the base game (main). +The default value of `com_target_game` is 0 for the base game (mohaa, main). With `com_target_game`, OpenMoHAA will support the network protocol accordingly. From 54ceff51077c28d75f69162c77563e1c7e06a71d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 14:25:25 +0200 Subject: [PATCH 0655/2040] Process the value of `s_speaker_type` --- code/client/snd_openal_new.cpp | 46 ++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 559a939b..15cec24b 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -26,6 +26,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../server/server.h" #include "snd_codec.h" +#if defined(_MSC_VER) || defined(__APPLE__) +# include +#else +# include +#endif + typedef struct { const char *funcname; void **funcptr; @@ -261,7 +267,7 @@ S_OPENAL_InitContext static bool S_OPENAL_InitContext() { const char *dev; - int attrlist[6]; + int attrlist[8]; dev = NULL; if (s_openaldevice) { @@ -366,12 +372,35 @@ static bool S_OPENAL_InitContext() break; } - attrlist[0] = 256; + attrlist[0] = ALC_FREQUENCY; attrlist[1] = al_frequency; - attrlist[2] = 258; - attrlist[3] = 0; - attrlist[4] = 0; - attrlist[5] = 0; + attrlist[2] = ALC_SYNC; + attrlist[3] = qfalse; + + attrlist[4] = ALC_OUTPUT_MODE_SOFT; + + switch (s_speaker_type->integer) { + // Two speakers + default: + case 0: + attrlist[5] = ALC_STEREO_SOFT; + break; + // Headphones + case 1: + attrlist[5] = ALC_STEREO_HRTF_SOFT; + break; + // Surround + case 2: + attrlist[5] = ALC_SURROUND_5_1_SOFT; + break; + // Quad speakers + case 3: + attrlist[5] = ALC_QUAD_SOFT; + break; + } + + attrlist[6] = 0; + attrlist[7] = 0; Com_Printf("OpenAL: Creating AL context...\n"); al_context_id = qalcCreateContext(al_device, attrlist); @@ -2465,8 +2494,9 @@ void S_OPENAL_Update() if (s_speaker_type->modified) { if (s_speaker_type->integer) { - Com_Printf("FIXME: Allow different speaker types in OpenAL code.\n"); - Cvar_Set("s_speaker_type", "0"); + //Com_Printf("FIXME: Allow different speaker types in OpenAL code.\n"); + //Cvar_Set("s_speaker_type", "0"); + Cbuf_AddText("snd_restart\n"); } s_speaker_type->modified = false; } From c70c5781946dd216bc3a2b12fa1399822458e384 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 14:51:21 +0200 Subject: [PATCH 0656/2040] Ignore ALC_OUTPUT_MODE_SOFT if unavailable --- code/client/snd_openal_new.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 15cec24b..fa7014b6 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -269,6 +269,8 @@ static bool S_OPENAL_InitContext() const char *dev; int attrlist[8]; + Com_DPrintf("OpenAL: Context initialization\n"); + dev = NULL; if (s_openaldevice) { dev = s_openaldevice->string; @@ -278,8 +280,6 @@ static bool S_OPENAL_InitContext() dev = NULL; } - Com_DPrintf("OpenAL: Context initialization\n"); - // Device enumeration support enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"); enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"); @@ -296,7 +296,6 @@ static bool S_OPENAL_InitContext() // get all available devices + the default device name. if(enumeration_all_ext) { - Com_DPrintf("OpenAL: Fetching all devices\n"); devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); #ifdef _WIN32 defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); @@ -304,7 +303,6 @@ static bool S_OPENAL_InitContext() } else { - Com_DPrintf("OpenAL: Fetching current device\n"); // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); #ifdef _WIN32 @@ -377,6 +375,7 @@ static bool S_OPENAL_InitContext() attrlist[2] = ALC_SYNC; attrlist[3] = qfalse; +#ifdef ALC_SOFT_output_mode attrlist[4] = ALC_OUTPUT_MODE_SOFT; switch (s_speaker_type->integer) { @@ -398,6 +397,13 @@ static bool S_OPENAL_InitContext() attrlist[5] = ALC_QUAD_SOFT; break; } +#else +# pragma message("OpenAL: ALC_OUTPUT_MODE_SOFT unavailable") + + Com_Printf("OpenAL: ALC_OUTPUT_MODE_SOFT is unavailable. The speaker type will be ignored, fallback to normal stereo.\n"); + attrlist[4] = 0; + attrlist[5] = 0; +#endif attrlist[6] = 0; attrlist[7] = 0; From d64e88451fe563dc2e26c7a0432ea1e23693898c Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 15:08:42 +0200 Subject: [PATCH 0657/2040] Fix compiler warnings Note that in Dismiss(), checking for `this` is not necessary (original code was generated by the compiler) --- code/uilib/uinotepad.cpp | 2 +- code/uilib/uipopupmenu.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/code/uilib/uinotepad.cpp b/code/uilib/uinotepad.cpp index 556b6b6f..c3c821d2 100644 --- a/code/uilib/uinotepad.cpp +++ b/code/uilib/uinotepad.cpp @@ -143,7 +143,7 @@ static ctrlevent_s controlEvents[CTRL_EVENT_COUNT] = { {'c', &EV_Notepad_Copy }, {'x', &EV_Notepad_Cut }, {'v', &EV_Notepad_Paste }, - {NULL, NULL }, + {0, NULL }, }; bool UI_LoadNotepadFile(const char *filename) diff --git a/code/uilib/uipopupmenu.cpp b/code/uilib/uipopupmenu.cpp index 59e378f4..afcefc63 100644 --- a/code/uilib/uipopupmenu.cpp +++ b/code/uilib/uipopupmenu.cpp @@ -468,13 +468,9 @@ void UIPopupMenu::Dismiss { // navigate to the topmost menu - if (m_parentMenu) - { + if (m_parentMenu) { m_parentMenu->Dismiss(); - } - else if (this) - { - // this is the topmost menu, self-destruct + } else { delete this; } } From 8188d46ee7f98df5c1787f178802242911ba6034 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 15:10:12 +0200 Subject: [PATCH 0658/2040] Fix SetLittleLong() writing past end of `bytes` buffer (even though the union was still 4-bytes because of the integer) --- code/client/snd_mem_new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_mem_new.cpp b/code/client/snd_mem_new.cpp index 374a97f1..8d98346b 100644 --- a/code/client/snd_mem_new.cpp +++ b/code/client/snd_mem_new.cpp @@ -117,7 +117,7 @@ void SetLittleLong(int i) { union { int value; - byte bytes[2]; + byte bytes[4]; } val; val.value = i; From b457a84ed9b3d05afd8ff5239425351d786bcae6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 16:39:29 +0200 Subject: [PATCH 0659/2040] Fix `AL_DISTANCE_MODEL` value type, it must be an integer --- code/client/snd_openal_new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index fa7014b6..68cc9b2a 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2873,7 +2873,7 @@ void openal_channel::set_3d() alDieIfError(); qalSourcef(source, AL_GAIN, S_GetBaseVolume()); alDieIfError(); - qalSourcef(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + qalSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); alDieIfError(); // // Added in OPM From 5134aed352c6da8b8dcc216ce8ba5bcfdf0b00f7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 17:35:02 +0200 Subject: [PATCH 0660/2040] Mark the functions as inline to optimize function calls --- code/renderer/tr_model.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index c8cd21e9..48d8778f 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -946,7 +946,7 @@ void R_AddSkelSurfaces( trRefEntity_t *ent ) { SkelVertGetNormal ============= */ -static void SkelVertGetNormal( skeletorVertex_t *vert, skelBoneCache_t *bone, vec3_t out ) { +inline static void SkelVertGetNormal( skeletorVertex_t *vert, skelBoneCache_t *bone, vec3_t out ) { out[ 0 ] = vert->normal[ 0 ] * bone->matrix[ 0 ][ 0 ] + vert->normal[ 1 ] * bone->matrix[ 1 ][ 0 ] + vert->normal[ 2 ] * bone->matrix[ 2 ][ 0 ]; @@ -965,7 +965,7 @@ static void SkelVertGetNormal( skeletorVertex_t *vert, skelBoneCache_t *bone, ve SkelMorphGetXyz ============= */ -static void SkelMorphGetXyz( skeletorMorph_t *morph, int *morphcache, vec3_t out ) { +inline static void SkelMorphGetXyz( skeletorMorph_t *morph, int *morphcache, vec3_t out ) { VectorMA(out, *morphcache, morph->offset, out); } @@ -974,7 +974,7 @@ static void SkelMorphGetXyz( skeletorMorph_t *morph, int *morphcache, vec3_t out SkelWeightGetXyz ============= */ -static void SkelWeightGetXyz( skelWeight_t *weight, skelBoneCache_t *bone, vec3_t out ) { +inline static void SkelWeightGetXyz( skelWeight_t *weight, skelBoneCache_t *bone, vec3_t out ) { out[ 0 ] += ( ( weight->offset[ 0 ] * bone->matrix[ 0 ][ 0 ] + weight->offset[ 1 ] * bone->matrix[ 1 ][ 0 ] + weight->offset[ 2 ] * bone->matrix[ 2 ][ 0 ] ) + @@ -996,7 +996,7 @@ static void SkelWeightGetXyz( skelWeight_t *weight, skelBoneCache_t *bone, vec3_ SkelWeightMorphGetXyz ============= */ -static void SkelWeightMorphGetXyz( skelWeight_t *weight, skelBoneCache_t *bone, vec3_t totalmorph, vec3_t out ) { +inline static void SkelWeightMorphGetXyz( skelWeight_t *weight, skelBoneCache_t *bone, vec3_t totalmorph, vec3_t out ) { vec3_t point; VectorAdd( totalmorph, weight->offset, point ); From 00f27ac02d72e1d8be71bb3968993f9a2a198943 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 17:35:35 +0200 Subject: [PATCH 0661/2040] Fix improper sound distance values --- code/client/snd_openal_new.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 68cc9b2a..78e91522 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1501,9 +1501,6 @@ void S_OPENAL_StartSound( pChannel->iEntChannel = iEntChannel; pChannel->iFlags &= ~(CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER); state = pChannel->get_state(); - // Fixed in OPM - // Setup the channel for 3D - pChannel->set_3d(); if (pChannel->iEntNum == iEntNum && (state == AL_PLAYING || state == AL_PAUSED) && pChannel->pSfx == pSfx) { bOnlyUpdate = true; @@ -1530,6 +1527,10 @@ void S_OPENAL_StartSound( pChannel->fVolume = S_GetBaseVolume() * fVolume; pChannel->set_gain(pChannel->fVolume); + // Fixed in OPM + // Setup the channel for 3D + pChannel->set_3d(); + if (s_show_sounds->integer > 0) { Com_DPrintf( "%d (#%i) - %s (vol %f, mindist %f, maxdist %f)\n", @@ -2869,11 +2870,11 @@ void openal_channel::set_3d() alDieIfError(); qalSourcei(source, AL_LOOPING, false); alDieIfError(); - qalSourcef(source, AL_ROLLOFF_FACTOR, 0.5f); + qalSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alDieIfError(); qalSourcef(source, AL_GAIN, S_GetBaseVolume()); alDieIfError(); - qalSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + qalSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE_CLAMPED); alDieIfError(); // // Added in OPM From bf2626f80413b29e819f350217a4150afce07b52 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 17:53:13 +0200 Subject: [PATCH 0662/2040] Set the pitch before playing the sound --- code/client/snd_openal_new.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 78e91522..881bfb96 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1595,9 +1595,14 @@ void S_OPENAL_StartSound( } if (!bOnlyUpdate && S_OPENAL_ShouldStart(pChannel->vOrigin, pChannel->fMinDist, pChannel->fMaxDist)) { + // Fixed in OPM + // Make sure to set the pitch before playing the sound + pChannel->iBaseRate = pSfx->info.rate; + pChannel->set_sample_playback_rate(pChannel->iBaseRate * pChannel->fNewPitchMult); + pChannel->fNewPitchMult = 0; + pChannel->play(); pChannel->iEndTime = cl.serverTime + (int)pChannel->pSfx->time_length + 250; - pChannel->iBaseRate = pChannel->sample_playback_rate(); pChannel->iStartTime = cl.serverTime; } } From d399ffd609105c08e667956db6d752012b74abc1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 18:06:14 +0200 Subject: [PATCH 0663/2040] Set the correct sound velocity --- code/client/snd_openal_new.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 881bfb96..9d006b05 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -38,7 +38,7 @@ typedef struct { bool required; } extensions_table_t; -# define MAX_MUSIC_SONGS 16 +#define MAX_MUSIC_SONGS 16 static int s_iNextLoopingWarning = 0; static int s_iReverbType = 0; @@ -46,6 +46,7 @@ static float s_fReverbLevel = 0; static bool s_bReverbChanged = false; static bool s_bFading = false; static float s_fFadeVolume = 1.f; +static float s_fVelocityScale = 0.005f; static constexpr float s_fVolumeGain = 1.f; // = 84.f; @@ -1914,6 +1915,7 @@ static int S_OPENAL_Start3DLoopSound( } pChan3D->set_position(vLoopOrigin[0], vLoopOrigin[1], vLoopOrigin[2]); + VectorScale(pLoopSound->vVelocity, s_fVelocityScale, pLoopSound->vVelocity); pChan3D->set_velocity(pLoopSound->vVelocity[0], pLoopSound->vVelocity[1], pLoopSound->vVelocity[2]); pChan3D->pSfx = pLoopSound->pSfx; pChan3D->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; @@ -2252,6 +2254,8 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi // // Velocity // + VectorCopy(s_entity[iEntNum].velocity, alvec); + VectorScale(alvec, s_fVelocityScale, alvec); qalListenerfv(AL_VELOCITY, alvec); alDieIfError(); @@ -2377,6 +2381,7 @@ void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxi pChannel->set_position(vOrigin[0], vOrigin[1], vOrigin[2]); VectorCopy(s_entity[pChannel->iEntNum].velocity, vEntVelocity); VectorCopy(vEntVelocity, vVelocity); + VectorScale(vVelocity, s_fVelocityScale, vVelocity); pChannel->set_velocity(vVelocity[0], vVelocity[1], vVelocity[2]); } } From 322ca2b42e4f7505567a3cc18ea50d0026fc7723 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 18:49:36 +0200 Subject: [PATCH 0664/2040] Fix the loop protection not working when multiple scripts are executed This fix will apply the protection globally --- code/script/scriptvm.cpp | 76 +++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/code/script/scriptvm.cpp b/code/script/scriptvm.cpp index 6b614acd..981d5dd3 100644 --- a/code/script/scriptvm.cpp +++ b/code/script/scriptvm.cpp @@ -420,7 +420,7 @@ void ScriptVM::error(const char *format, ...) vsprintf(buffer, format, va); va_end(va); - glbs.Printf("----------------------------------------------------------\n%s\n", buffer); + gi.Printf("----------------------------------------------------------\n%s\n", buffer); m_ReturnValue.setStringValue("$.INTERRUPTED"); } @@ -1040,9 +1040,6 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) state = STATE_RUNNING; - Director.cmdTime = glbs.Milliseconds(); - Director.cmdCount = 0; - while (state == STATE_RUNNING) { if (g_scripttrace->integer && CanScriptTracePrint()) { switch (g_scripttrace->integer) { @@ -1059,33 +1056,7 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) m_PrevCodePos = m_CodePos; - Director.cmdCount++; - try { - if (Director.cmdCount > 9999 && glbs.Milliseconds() - Director.cmdTime > Director.maxTime) { - if (level.m_LoopProtection) { - Director.cmdTime = glbs.Milliseconds(); - - GetScript()->PrintSourcePos(m_CodePos, true); - gi.DPrintf2("\n"); - - state = STATE_EXECUTION; - - if (level.m_LoopDrop) { - ScriptException::next_abort = -1; - } - - ScriptError("Command overflow. Possible infinite loop in thread.\n"); - } - - VM_DPrintf("Update of script position - This is not an error.\n"); - VM_DPrintf("=================================================\n"); - m_ScriptClass->GetScript()->PrintSourcePos(opcode, true); - VM_DPrintf("=================================================\n"); - - Director.cmdCount = 0; - } - if (!m_VMStack.m_bMarkStack) { /* assert(pTop >= localStack && pTop < localStack + localStackSize); @@ -1832,12 +1803,51 @@ void ScriptVM::Execute(ScriptVariable *data, int dataSize, str label) default: assert(!"Invalid opcode"); if (*opcode < OP_MAX) { - glbs.DPrintf("unknown opcode %d ('%s')\n", *opcode, OpcodeName(*opcode)); + gi.DPrintf("unknown opcode %d ('%s')\n", *opcode, OpcodeName(*opcode)); } else { - glbs.DPrintf("unknown opcode %d\n", *opcode); + gi.DPrintf("unknown opcode %d\n", *opcode); } break; } + + Director.cmdCount++; + + if (Director.cmdCount >= 15000) { + if (!Director.cmdTime) { + Director.cmdTime = gi.Milliseconds(); + Director.cmdCount = 0; + continue; + } + + if (gi.Milliseconds() - Director.cmdTime < Director.maxTime) { + Director.cmdCount = 0; + continue; + } + + // The maximum execution time was reached + if (level.m_LoopProtection) { + Director.cmdTime = gi.Milliseconds(); + + GetScript()->PrintSourcePos(m_CodePos, true); + gi.DPrintf2("\n"); + + state = STATE_EXECUTION; + + if (level.m_LoopDrop) { + ScriptException::next_abort = -1; + } + + ScriptError("Command overflow. Possible infinite loop in thread.\n"); + break; + } + + VM_DPrintf("Update of script position - This is not an error.\n"); + VM_DPrintf("=================================================\n"); + m_ScriptClass->GetScript()->PrintSourcePos(opcode, true); + VM_DPrintf("=================================================\n"); + + Director.cmdCount = 0; + } } catch (ScriptException& exc) { HandleScriptException(exc); } @@ -1877,7 +1887,7 @@ void ScriptVM::HandleScriptException(ScriptException& exc) if (m_ScriptClass) { m_ScriptClass->GetScript()->PrintSourcePos(m_PrevCodePos, true); } else { - glbs.DPrintf("unknown source pos"); + gi.DPrintf("unknown source pos"); } if (exc.bAbort) { From 91b80a8e2186c67292f79153fcbac6124af2ff40 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 19:19:38 +0200 Subject: [PATCH 0665/2040] Fix the sound system not restarting when modifying the speaker type to 0 --- code/client/snd_openal_new.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 9d006b05..baeaa744 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -2510,11 +2510,7 @@ void S_OPENAL_Update() } if (s_speaker_type->modified) { - if (s_speaker_type->integer) { - //Com_Printf("FIXME: Allow different speaker types in OpenAL code.\n"); - //Cvar_Set("s_speaker_type", "0"); - Cbuf_AddText("snd_restart\n"); - } + Cbuf_AddText("snd_restart\n"); s_speaker_type->modified = false; } From e021289d363d48b1c584b6404efd564fad1550b2 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 24 Aug 2024 19:22:57 +0200 Subject: [PATCH 0666/2040] Fix the turret setting incorrect angles --- code/fgame/weapturret.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index 96685089..a5900401 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -1306,7 +1306,7 @@ void TurretGun::P_UserAim(usercmd_t *ucmd) vNewCmdAng = Vector(SHORT2ANGLE(ucmd->angles[0]), SHORT2ANGLE(ucmd->angles[1]), SHORT2ANGLE(ucmd->angles[2])); - if (vNewCmdAng[0] || vNewCmdAng[1] || vNewCmdAng[2]) { + if (m_vUserLastCmdAng[0] || m_vUserLastCmdAng[1] || m_vUserLastCmdAng[2]) { m_vUserViewAng[0] += AngleSubtract(vNewCmdAng[0], m_vUserLastCmdAng[0]); m_vUserViewAng[1] += AngleSubtract(vNewCmdAng[1], m_vUserLastCmdAng[1]); m_vUserViewAng[2] += AngleSubtract(vNewCmdAng[2], m_vUserLastCmdAng[2]); From 022181fcfdcf95b5c35e525d67a61bc08a9dc9d3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Aug 2024 16:49:24 +0200 Subject: [PATCH 0667/2040] Remove processed buffers after half of the queued buffers has been processed --- code/client/snd_openal_new.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index baeaa744..508b62f1 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -4372,10 +4372,12 @@ void openal_channel_two_d_stream::update() qalGetSourcei(source, AL_BUFFERS_QUEUED, &numQueuedBuffers); alDieIfError(); - // Unqueue processed buffers - while (numProcessedBuffers-- > 0) { - ALuint tmpBuffer; - qalSourceUnqueueBuffers(source, 1, &tmpBuffer); + // Remove processed buffers after half of the queued buffers has been processed + if (numProcessedBuffers >= numQueuedBuffers / 2) { + while (numProcessedBuffers-- > 0) { + ALuint tmpBuffer; + qalSourceUnqueueBuffers(source, 1, &tmpBuffer); + } } if (numQueuedBuffers >= MAX_STREAM_BUFFERS) { From e70cdfb8989755de9c6d6dcaf11b31584951c5db Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Aug 2024 22:00:55 +0200 Subject: [PATCH 0668/2040] Improve code readability --- code/server/sv_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 0faebf3a..145e3548 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -943,9 +943,9 @@ void SV_ServerLoaded( void ) { sv.state = SS_GAME; sv.timeResidual = 0; svs.startTime = svs.time - svs.mapTime; - if( svs.time - svs.mapTime < 0 ) + if( svs.startTime < 0 ) { - svs.time -= svs.time - svs.mapTime; + svs.time -= svs.startTime; svs.startTime = 0; } From ac22b1cfbf3d6072f974c180a5d63dc09c433507 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Aug 2024 22:04:29 +0200 Subject: [PATCH 0669/2040] Use an higher fragment size when sending a message to the loopback --- code/qcommon/net_chan.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/qcommon/net_chan.c b/code/qcommon/net_chan.c index 7376a01e..63a9ccf8 100644 --- a/code/qcommon/net_chan.c +++ b/code/qcommon/net_chan.c @@ -46,10 +46,10 @@ to the new value before sending out any replies. */ +#define MAX_PACKETLEN 10000 // max size of a network packet +#define MAX_REMOTE_PACKETLEN 1400 // max size of a network packet -#define MAX_PACKETLEN 1400 // max size of a network packet - -#define FRAGMENT_SIZE (MAX_PACKETLEN - 100) +#define FRAGMENT_SIZE (((chan->remoteAddress.type == NA_LOOPBACK) ? MAX_PACKETLEN : MAX_REMOTE_PACKETLEN) - 100) #define PACKET_HEADER 10 // two ints and a short #define FRAGMENT_BIT (1<<31) @@ -198,7 +198,7 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) { size_t fragmentLength; // write the packet header - MSG_InitOOB (&send, send_buf, sizeof(send_buf)); // <-- only do the oob here + MSG_InitOOB (&send, send_buf, chan->remoteAddress.type == NA_LOOPBACK ? MAX_PACKETLEN : MAX_REMOTE_PACKETLEN); // <-- only do the oob here MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT ); @@ -250,8 +250,8 @@ A 0 length will still generate a packet. ================ */ void Netchan_Transmit( netchan_t *chan, size_t length, const byte *data ) { - msg_t send; - byte send_buf[MAX_PACKETLEN]; + msg_t send; + byte send_buf[MAX_PACKETLEN]; if ( length > MAX_MSGLEN ) { Com_Error( ERR_DROP, "Netchan_Transmit: length = %zu", length ); @@ -271,7 +271,7 @@ void Netchan_Transmit( netchan_t *chan, size_t length, const byte *data ) { } // write the packet header - MSG_InitOOB (&send, send_buf, sizeof(send_buf)); + MSG_InitOOB (&send, send_buf, chan->remoteAddress.type == NA_LOOPBACK ? MAX_PACKETLEN : MAX_REMOTE_PACKETLEN); MSG_WriteLong( &send, chan->outgoingSequence ); chan->outgoingSequence++; From 07f13d1ae97e081f91782b9dd9614ff49b0fe54a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:45:18 +0200 Subject: [PATCH 0670/2040] Force the soundtrack to be sent again --- code/fgame/g_utils.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/fgame/g_utils.cpp b/code/fgame/g_utils.cpp index 57eaf3c9..1a3ae238 100644 --- a/code/fgame/g_utils.cpp +++ b/code/fgame/g_utils.cpp @@ -1528,7 +1528,12 @@ void ChangeSoundtrack(const char *soundtrack) level.saved_soundtrack = level.current_soundtrack; level.current_soundtrack = soundtrack; + // Force the soundtrack to be sent again by setting it to empty first + // so it gets sent to clients again especially when loading + // from a saved game + gi.setConfigstring(CS_MUSIC, ""); gi.setConfigstring(CS_MUSIC, soundtrack); + gi.DPrintf("soundtrack switched to %s.\n", soundtrack); } From 702318489272d12fcc8b1bcb9f6c5dee4ca46746 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 00:11:51 +0200 Subject: [PATCH 0671/2040] Fix subdivisions endianness See #332 --- code/renderer/tr_bsp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 39d3338e..f469330e 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -726,6 +726,7 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { int lightmapNum; vec3_t bounds[2]; vec3_t tmpVec; + float subdivisions; static surfaceType_t skipData = SF_SKIP; lightmapNum = LittleLong( ds->lightmapNum ); @@ -764,8 +765,9 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { } // pre-tesseleate - if (ds->subdivisions) { - grid = R_SubdividePatchToGrid(width, height, ds->subdivisions * (r_subdivisions->value / 10.0), points); + subdivisions = LittleFloat(ds->subdivisions); + if (subdivisions) { + grid = R_SubdividePatchToGrid(width, height, subdivisions * (r_subdivisions->value / 10.0), points); } else if (surf->shader->subdivisions) { grid = R_SubdividePatchToGrid(width, height, surf->shader->subdivisions * (r_subdivisions->value / 10.0), points); } else { From 6ab654264b6aafe3b9f588afa30e30ea97f657eb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 00:45:25 +0200 Subject: [PATCH 0672/2040] Cleaned up Entity::ProcessSoundEvent() --- code/fgame/entity.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 57af734b..703daf22 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -3310,7 +3310,7 @@ void Entity::ProcessSoundEvent(Event *ev, qboolean checkSubtitle) { str sound_name; str wait; - int waitTillDone = 0; + bool waitTillDone = false; float volume; int channel = 0; @@ -3330,30 +3330,24 @@ void Entity::ProcessSoundEvent(Event *ev, qboolean checkSubtitle) wait = ev->GetString(2); } - if (Q_stricmp(wait.c_str(), "wait")) { - if (!Q_stricmp(wait.c_str(), "volume")) { - if (ev->NumArgs() != 3) { - ScriptError("Entity::Sound: volume not followed by a float"); - } - - volume = ev->GetFloat(3); - } - } else { - waitTillDone = 1; + if (!Q_stricmp(wait.c_str(), "wait")) { + waitTillDone = true; if (ev->NumArgs() == 3) { volume = ev->GetFloat(3); } + } else if (!Q_stricmp(wait.c_str(), "volume")) { + if (ev->NumArgs() != 3) { + ScriptError("Entity::Sound: volume not followed by a float"); + } + + volume = ev->GetFloat(3); } if (volume == DEFAULT_VOL) { - if (wait.length()) { - channel = atoi(wait.c_str()); - } - - Sound(sound_name, channel, volume, 0, NULL, 0, 0, waitTillDone, checkSubtitle, -1.0f); + Sound(sound_name, CHAN_AUTO, volume, 0, NULL, 0, 0, waitTillDone, checkSubtitle, -1.0f); } else { - Sound(sound_name, -1.0f, volume, -1.0f, NULL, -1.0f, 1, waitTillDone, checkSubtitle, -1.0f); + Sound(sound_name, -1, volume, -1.0f, NULL, -1.0f, 1, waitTillDone, checkSubtitle, -1.0f); } } From 93e7561cb302df8dfa4baadf406099ccec2adbc8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:05:58 +0200 Subject: [PATCH 0673/2040] Fix Actor::EventSoundDone() using the wrong parameter for the sfxName, causing the SoundDone event to be sent immediately --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 65054c3f..14f0707c 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -10589,7 +10589,7 @@ void Actor::EventSoundDone(Event *ev) str sfxName; channelNum = ev->GetInteger(1); - sfxName = ev->GetString(1); + sfxName = ev->GetString(2); if (gi.S_IsSoundPlaying(channelNum, sfxName)) { Event event(EV_SoundDone); From 0b1a20dcff035eac9f1903a1e3b1c04868e5b0c8 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:06:02 +0200 Subject: [PATCH 0674/2040] Properly save and restore sound position, also fix loopsounds not playing properly --- code/client/snd_openal_new.cpp | 681 +++++++++++++++++++++++---------- code/client/snd_openal_new.h | 109 +++--- 2 files changed, 540 insertions(+), 250 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 508b62f1..684314f7 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -27,15 +27,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_codec.h" #if defined(_MSC_VER) || defined(__APPLE__) -# include +# include #else -# include +# include #endif typedef struct { - const char *funcname; - void **funcptr; - bool required; + const char *funcname; + void **funcptr; + bool required; } extensions_table_t; #define MAX_MUSIC_SONGS 16 @@ -97,7 +97,7 @@ int music_loaded = 0; int music_numsongs = 0; int music_currentsong = 0; -static qboolean enumeration_ext = qfalse; +static qboolean enumeration_ext = qfalse; static qboolean enumeration_all_ext = qfalse; song_t music_songs[MAX_MUSIC_SONGS]; @@ -111,23 +111,23 @@ static void S_OPENAL_StopMP3(); static void S_OPENAL_Pitch(); static int S_OPENAL_SpatializeStereoSound(const vec3_t listener_origin, const vec3_t listener_left, const vec3_t origin); -static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); -static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx); +static void S_OPENAL_reverb(int iChannel, int iReverbType, float fReverbLevel); +static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t *pSfx); static ALuint S_OPENAL_Format(int width, int channels); -# define alDieIfError() __alDieIfError(__FILE__, __LINE__) +#define alDieIfError() __alDieIfError(__FILE__, __LINE__) -# if defined(_WIN64) -# define ALDRIVER_DEFAULT "OpenAL64.dll" -# elif defined(_WIN32) -# define ALDRIVER_DEFAULT "OpenAL32.dll" -# elif defined(__APPLE__) -# define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" -# elif defined(__OpenBSD__) -# define ALDRIVER_DEFAULT "libopenal.so" -# else -# define ALDRIVER_DEFAULT "libopenal.so.1" -# endif +#if defined(_WIN64) +# define ALDRIVER_DEFAULT "OpenAL64.dll" +#elif defined(_WIN32) +# define ALDRIVER_DEFAULT "OpenAL32.dll" +#elif defined(__APPLE__) +# define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" +#elif defined(__OpenBSD__) +# define ALDRIVER_DEFAULT "libopenal.so" +#else +# define ALDRIVER_DEFAULT "libopenal.so.1" +#endif /* ============== @@ -281,67 +281,62 @@ static bool S_OPENAL_InitContext() dev = NULL; } - // Device enumeration support - enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"); - enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"); + // Device enumeration support + enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"); + enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"); - if(enumeration_ext || enumeration_all_ext) - { - char devicenames[16384] = ""; - const char *devicelist; + if (enumeration_ext || enumeration_all_ext) { + char devicenames[16384] = ""; + const char *devicelist; #ifdef _WIN32 - const char *defaultdevice; + const char *defaultdevice; #endif - int curlen; + int curlen; - // get all available devices + the default device name. - if(enumeration_all_ext) - { - devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + // get all available devices + the default device name. + if (enumeration_all_ext) { + devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); #ifdef _WIN32 - defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); #endif - } - else - { - // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. - devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); + } else { + // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. + devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); #ifdef _WIN32 - defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); #endif - enumeration_ext = qtrue; - } + enumeration_ext = qtrue; + } #ifdef _WIN32 Com_DPrintf("OpenAL: Default playback device: \"%s\"\n", defaultdevice); #endif #ifdef _WIN32 - // check whether the default device is generic hardware. If it is, change to - // Generic Software as that one works more reliably with various sound systems. - // If it's not, use OpenAL's default selection as we don't want to ignore - // native hardware acceleration. - if(!dev && defaultdevice && !strcmp(defaultdevice, "Generic Hardware")) - dev = "Generic Software"; + // check whether the default device is generic hardware. If it is, change to + // Generic Software as that one works more reliably with various sound systems. + // If it's not, use OpenAL's default selection as we don't want to ignore + // native hardware acceleration. + if (!dev && defaultdevice && !strcmp(defaultdevice, "Generic Hardware")) { + dev = "Generic Software"; + } #endif - // dump a list of available devices to a cvar for the user to see. + // dump a list of available devices to a cvar for the user to see. - if(devicelist) - { - while((curlen = strlen(devicelist))) - { - Q_strcat(devicenames, sizeof(devicenames), devicelist); - Q_strcat(devicenames, sizeof(devicenames), "\n"); + if (devicelist) { + while ((curlen = strlen(devicelist))) { + Q_strcat(devicenames, sizeof(devicenames), devicelist); + Q_strcat(devicenames, sizeof(devicenames), "\n"); - devicelist += curlen + 1; - } - } + devicelist += curlen + 1; + } + } Com_Printf("OpenAL: List of available devices:\n%s\n", devicenames); - s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); - } + s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); + } Com_Printf("OpenAL: Opening device \"%s\"...\n", dev ? dev : "{default}"); @@ -376,6 +371,8 @@ static bool S_OPENAL_InitContext() attrlist[2] = ALC_SYNC; attrlist[3] = qfalse; + s_speaker_type->modified = false; + #ifdef ALC_SOFT_output_mode attrlist[4] = ALC_OUTPUT_MODE_SOFT; @@ -399,9 +396,11 @@ static bool S_OPENAL_InitContext() break; } #else -# pragma message("OpenAL: ALC_OUTPUT_MODE_SOFT unavailable") +# pragma message("OpenAL: ALC_OUTPUT_MODE_SOFT unavailable") - Com_Printf("OpenAL: ALC_OUTPUT_MODE_SOFT is unavailable. The speaker type will be ignored, fallback to normal stereo.\n"); + Com_Printf( + "OpenAL: ALC_OUTPUT_MODE_SOFT is unavailable. The speaker type will be ignored, fallback to normal stereo.\n" + ); attrlist[4] = 0; attrlist[5] = 0; #endif @@ -497,7 +496,7 @@ S_OPENAL_InitChannel */ static bool S_OPENAL_InitChannel(int idx, openal_channel *chan) { - openal.channel[idx] = chan; + openal.channel[idx] = chan; VectorClear(chan->vOrigin); chan->fVolume = 1.0; chan->fNewPitchMult = 0.0; @@ -842,9 +841,9 @@ S_OPENAL_LoadMP3 */ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) { - char path[MAX_QPATH]; + char path[MAX_QPATH]; snd_info_t info; - ALuint format; + ALuint format; chan->stop(); @@ -857,7 +856,7 @@ static bool S_OPENAL_LoadMP3(const char *_path, openal_channel *chan) FS_CorrectCase(path); // Try to load - chan->bufferdata = (ALubyte*)S_CodecLoad(path, &info); + chan->bufferdata = (ALubyte *)S_CodecLoad(path, &info); if (!chan->bufferdata) { return false; } @@ -1199,7 +1198,7 @@ static int S_OPENAL_PickChannelBase(int iEntNum, int iEntChannel, int iFirstChan } if (!bStoppedChannel) { - for(i = iLastChannel + 1; i < MAX_OPENAL_POSITION_CHANNELS; i++) { + for (i = iLastChannel + 1; i < MAX_OPENAL_POSITION_CHANNELS; i++) { pChannel = openal.channel[i]; if (!pChannel || pChannel->is_free()) { continue; @@ -1501,7 +1500,7 @@ void S_OPENAL_StartSound( pChannel->fNewPitchMult = fPitch; pChannel->iEntChannel = iEntChannel; pChannel->iFlags &= ~(CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_LOCAL_LISTENER); - state = pChannel->get_state(); + state = pChannel->sample_status(); if (pChannel->iEntNum == iEntNum && (state == AL_PLAYING || state == AL_PAUSED) && pChannel->pSfx == pSfx) { bOnlyUpdate = true; @@ -1631,7 +1630,7 @@ void S_OPENAL_AddLoopingSound( iFreeLoopSound = -1; pSfx = &s_knownSfx[sfxHandle]; - if (!pSfx) { + if (!pSfx || !pSfx->length) { return; } @@ -1662,7 +1661,7 @@ void S_OPENAL_AddLoopingSound( return; } - pLoopSound = &openal.loop_sounds[iFreeLoopSound]; + pLoopSound = &openal.loop_sounds[iFreeLoopSound]; VectorCopy(vOrigin, pLoopSound->vOrigin); VectorCopy(vVelocity, pLoopSound->vVelocity); pLoopSound->pSfx = pSfx; @@ -1820,7 +1819,7 @@ static int S_OPENAL_Start2DLoopSound( ) { int iChannel; - int iSoundOFfset; + int iSoundOffset; openal_channel *pChannel; if (pLoopSound->pSfx->iFlags & SFX_FLAG_STREAMED) { @@ -1857,12 +1856,10 @@ static int S_OPENAL_Start2DLoopSound( pChannel->iFlags |= CHANNEL_FLAG_PAUSED | CHANNEL_FLAG_NO_ENTITY; pChannel->iBaseRate = pChannel->sample_playback_rate(); VectorCopy(vLoopOrigin, pChannel->vOrigin); - pChannel->set_sample_offset( - (int)(pLoopSound->pSfx->info.width * pLoopSound->pSfx->info.rate - * (float)(cls.realtime - pLoopSound->iStartTime) / 1000.0) - % pLoopSound->pSfx->length - ); + iSoundOffset = (int)(pLoopSound->pSfx->info.width * pLoopSound->pSfx->info.rate + * (float)(cls.realtime - pLoopSound->iStartTime) / 1000.0); + pChannel->set_sample_offset(iSoundOffset % pLoopSound->pSfx->length); pChannel->set_sample_loop_count(0); pChannel->fVolume = fVolumeToPlay; pChannel->set_gain(fVolumeToPlay); @@ -1907,6 +1904,8 @@ static int S_OPENAL_Start3DLoopSound( pChan3D->force_free(); pChan3D->iEntNum = 0; pChan3D->iEntChannel = 0; + pChan3D->fMinDist = fMinDistance; + pChan3D->fMaxDist = fMaxDistance; pChan3D->set_3d(); if (!pChan3D->set_sfx(pLoopSound->pSfx)) { @@ -2185,7 +2184,8 @@ void S_OPENAL_AddLoopSounds(const vec3_t vTempAxis) Com_DPrintf("%d (#%i) - started loop - %s\n", cl.serverTime, pLoopSound->iChannel, pLoopSound->pSfx->name); } - if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) + if (pLoopSound->pSfx->iFlags & (SFX_FLAG_NO_OFFSET) + || pLoopSound->pSfx->iFlags & (SFX_FLAG_STREAMED | SFX_FLAG_MP3) || (pLoopSound->iFlags & LOOPSOUND_FLAG_NO_PAN)) { iChannel = S_OPENAL_Start2DLoopSound( pLoopSound, fVolume, S_GetBaseVolume() * s_fVolumeGain * fTotalVolume, fMinDistance, vLoopOrigin @@ -2549,7 +2549,7 @@ void S_OPENAL_Update() S_OPENAL_GetMusicFilename ============== */ -const char* S_OPENAL_GetMusicFilename() +const char *S_OPENAL_GetMusicFilename() { return openal.tm_filename; } @@ -2594,11 +2594,15 @@ qboolean S_IsSoundPlaying(int channel_number, const char *sfxName) return false; } - if (!pChannel->pSfx || pChannel->pSfx == (sfx_t *)-16) { + if (!pChannel->pSfx) { return false; } - return !strcmp(sfxName, pChannel->pSfx->name); + if (strcmp(sfxName, pChannel->pSfx->name)) { + return false; + } + + return true; } /* @@ -2710,7 +2714,7 @@ static void S_LoadBase(channelbasesavegame_t *pBase, openal_channel *pChannel, b return; } - handle = S_RegisterSound(pBase->sfx.szName, (pBase->sfx.iFlags & SFX_FLAG_DEFAULT_SOUND), false); + handle = S_RegisterSound(pBase->sfx.szName, (pBase->sfx.iFlags & SFX_FLAG_STREAMED), false); pChannel->iBaseRate = pBase->iBaseRate; pChannel->iStartTime = pBase->iStartTime; @@ -2928,21 +2932,6 @@ void openal_channel::stop() alDieIfError(); } -/* -============== -openal_channel::get_state -============== -*/ -ALint openal_channel::get_state() -{ - ALint retval; - - qalGetSourcei(source, AL_SOURCE_STATE, &retval); - alDieIfError(); - - return retval; -} - /* ============== openal_channel::is_free @@ -2950,7 +2939,7 @@ openal_channel::is_free */ bool openal_channel::is_free() { - ALint state = get_state(); + ALint state = sample_status(); return state == AL_INITIAL || state == AL_STOPPED; } @@ -2962,7 +2951,7 @@ openal_channel::is_paused */ bool openal_channel::is_paused() { - ALint state = get_state(); + ALint state = sample_status(); return state == AL_PAUSED; } @@ -2974,7 +2963,7 @@ openal_channel::is_playing */ bool openal_channel::is_playing() { - ALint state = get_state(); + ALint state = sample_status(); return state == AL_PLAYING; } @@ -2999,6 +2988,8 @@ bool openal_channel::set_sfx(sfx_t *pSfx) { ALint freq = 0; + assert(pSfx->length); + this->pSfx = pSfx; if (!pSfx->buffer || !qalIsBuffer(pSfx->buffer)) { if (pSfx->iFlags & SFX_FLAG_MP3) { @@ -3015,27 +3006,13 @@ bool openal_channel::set_sfx(sfx_t *pSfx) alDieIfError(); } else { - ALenum fmt = 0; - - if (pSfx->info.channels == 1) { - if (pSfx->info.width == 1) { - fmt = AL_FORMAT_MONO8; - } else if (pSfx->info.width == 2) { - fmt = AL_FORMAT_MONO16; - } - } else if (pSfx->info.channels == 2) { - if (pSfx->info.width == 1) { - fmt = AL_FORMAT_STEREO8; - } else if (pSfx->info.width == 2) { - fmt = AL_FORMAT_STEREO16; - } - } + ALenum fmt = S_OPENAL_Format(pSfx->info.width, pSfx->info.channels); if (!fmt) { Com_Printf( "OpenAL: Bad Wave file (%d channels, %d bits) [%s].\n", pSfx->info.channels, - (int)(pSfx->info.width * 8.f), + (int)(pSfx->info.width * 8), pSfx->name ); return false; @@ -3044,13 +3021,7 @@ bool openal_channel::set_sfx(sfx_t *pSfx) qalGenBuffers(1, &pSfx->buffer); alDieIfError(); - qalBufferData( - pSfx->buffer, - fmt, - &pSfx->data[pSfx->info.dataofs], - pSfx->info.samples * pSfx->info.width, - pSfx->info.rate - ); + qalBufferData(pSfx->buffer, fmt, &pSfx->data[pSfx->info.dataofs], pSfx->info.datasize, pSfx->info.rate); alDieIfError(); } } @@ -3117,7 +3088,7 @@ openal_channel::set_sample_pan */ void openal_channel::set_sample_pan(S32 pan) { - const float panning = (pan - 64) / 127.f; + const float panning = (pan - 64) / 127.f; const ALfloat sourcePosition[3] = {panning, 0, sqrtf(1.f - Square(panning))}; qalSourcef(source, AL_ROLLOFF_FACTOR, 0); @@ -3130,7 +3101,8 @@ void openal_channel::set_sample_pan(S32 pan) openal_channel::set_sample_playback_rate ============== */ -void openal_channel::set_sample_playback_rate(S32 rate) { +void openal_channel::set_sample_playback_rate(S32 rate) +{ // Fixed in OPM // Set the pitch in OpenAL qalSourcef(source, AL_PITCH, rate / (float)iBaseRate); @@ -3145,13 +3117,25 @@ openal_channel::sample_playback_rate S32 openal_channel::sample_playback_rate() { float pitch = 1; - ALint freq = 0; + ALint freq = 0; // Fixed in OPM // The sample rate varies according to the pitch qalGetSourcef(source, AL_PITCH, &pitch); alDieIfError(); + return buffer_frequency() * pitch; +} + +/* +============== +openal_channel::buffer_frequency +============== +*/ +U32 openal_channel::buffer_frequency() const +{ + ALint freq = 0; + if (buffer) { qalGetBufferi(buffer, AL_FREQUENCY, &freq); alDieIfError(); @@ -3162,7 +3146,7 @@ S32 openal_channel::sample_playback_rate() freq = 22050; } - return freq * pitch; + return freq; } /* @@ -3172,6 +3156,8 @@ openal_channel::sample_volume */ S32 openal_channel::sample_volume() { + // FIXME: unimplemented + // Default volume is 100, range 0..=127 STUB_DESC("sample_volume"); return 127; } @@ -3198,12 +3184,11 @@ openal_channel::sample_ms_offset */ U32 openal_channel::sample_ms_offset() { - float offset = 0; + if (!is_playing()) { + return 0; + } - qalGetSourcef(source, AL_SAMPLE_OFFSET, &offset); - alDieIfError(); - - return offset * 1000.f; + return sample_offset() * 1000 / sample_playback_rate(); } /* @@ -3247,8 +3232,7 @@ openal_channel::set_sample_ms_offset */ void openal_channel::set_sample_ms_offset(U32 offset) { - qalSourcef(source, AL_SEC_OFFSET, offset / 1000.f); - alDieIfError(); + set_sample_offset(offset * sample_playback_rate() / 1000); } /* @@ -3292,6 +3276,7 @@ openal_channel::set_sample_loop_block */ void openal_channel::set_sample_loop_block(S32 start_offset, S32 end_offset) { + // FIXME: unimplemented STUB_DESC("sample_loop_block"); } @@ -3302,8 +3287,12 @@ openal_channel::sample_status */ U32 openal_channel::sample_status() { - STUB_DESC("sample_status"); - return 127; + ALint retval; + + qalGetSourcei(source, AL_SOURCE_STATE, &retval); + alDieIfError(); + + return retval; } /* @@ -4007,7 +3996,7 @@ void S_TriggeredMusic_SetupHandle(const char *pszName, int iLoopCount, int iOffs const char *pszRealName; float fVolume = 1.0; AliasListNode_t *pSoundAlias = NULL; - void *stream = NULL; + void *stream = NULL; if (!s_bSoundStarted) { return; @@ -4102,7 +4091,7 @@ void S_TriggeredMusic_Stop() // Fixed in OPM // Make sure to clear the triggered music in case snd_restart is called openal.tm_filename[0] = 0; - openal.tm_loopcount = 0; + openal.tm_loopcount = 0; } /* @@ -4136,7 +4125,9 @@ void S_TriggeredMusic_Unpause() openal.chan_trig_music.play(); } - openal.chan_trig_music.set_gain(S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * s_fVolumeGain); + openal.chan_trig_music.set_gain( + S_GetBaseVolume() * (openal.chan_trig_music.fVolume * s_musicVolume->value) * s_fVolumeGain + ); } /* @@ -4156,6 +4147,7 @@ S_StopMovieAudio */ void S_StopMovieAudio() { + // FIXME: unimplemented STUB_DESC("sound stuff."); } @@ -4166,6 +4158,7 @@ S_SetupMovieAudio */ void S_SetupMovieAudio(const char *pszMovieName) { + // FIXME: unimplemented STUB_DESC("sound stuff"); } @@ -4176,6 +4169,7 @@ S_CurrentMoviePosition */ int S_CurrentMoviePosition() { + // FIXME: unimplemented STUB_DESC("sound stuff"); return 0; } @@ -4212,7 +4206,7 @@ static ALuint S_OPENAL_Format(int width, int channels) S_OPENAL_LoadMP3_Codec ============== */ -static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx) +static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t *pSfx) { void *data; snd_info_t info; @@ -4248,11 +4242,18 @@ static bool S_OPENAL_LoadMP3_Codec(const char *_path, sfx_t* pSfx) return true; } -void openal_channel::update() -{ - -} +/* +============== +openal_channel::update +============== +*/ +void openal_channel::update() {} +/* +============== +openal_channel_two_d_stream::stop +============== +*/ void openal_channel_two_d_stream::stop() { openal_channel::stop(); @@ -4260,12 +4261,17 @@ void openal_channel_two_d_stream::stop() clear_stream(); } -bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { - ALint freq = 0; - snd_stream_t* stream; - int bytesToRead = 0; - int bytesRead; - char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; +/* +============== +openal_channel_two_d_stream::set_sfx +============== +*/ +bool openal_channel_two_d_stream::set_sfx(sfx_t *pSfx) +{ + snd_stream_t *stream; + unsigned int bytesToRead, bytesRead; + ALint freq = 0; + char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; stop(); @@ -4276,20 +4282,17 @@ bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { streamHandle = S_CodecLoad(pSfx->name, NULL); if (!streamHandle) { - qalDeleteBuffers(1, &pSfx->buffer); - alDieIfError(); - Com_DPrintf("OpenAL: Failed to load MP3.\n"); return false; } - stream = (snd_stream_t*)streamHandle; + stream = (snd_stream_t *)streamHandle; pSfx->info.channels = stream->info.channels; - pSfx->info.dataofs = stream->info.dataofs; + pSfx->info.dataofs = stream->info.dataofs; pSfx->info.datasize = stream->info.size; - pSfx->info.rate = stream->info.rate; - pSfx->info.samples = stream->info.samples; - pSfx->info.width = stream->info.width; + pSfx->info.rate = stream->info.rate; + pSfx->info.samples = stream->info.samples; + pSfx->info.width = stream->info.width; pSfx->info.format = S_OPENAL_Format(stream->info.width, stream->info.channels); if (!pSfx->info.format) { @@ -4304,12 +4307,16 @@ bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { return false; } + qalSourceStop(source); + alDieIfError(); + qalGenBuffers(MAX_STREAM_BUFFERS, buffers); alDieIfError(); // Read a smaller sample - bytesToRead = Q_min(stream->info.width * stream->info.channels * (MAX_BUFFER_SAMPLES / 2), sizeof(rawData)); - bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + bytesToRead = Q_min(MAX_BUFFER_SAMPLES * stream->info.width * stream->info.channels, sizeof(rawData)); + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + streamNextOffset = bytesRead; if (!bytesRead) { // Valid stream but no data? S_CodecCloseStream(stream); @@ -4322,47 +4329,70 @@ bool openal_channel_two_d_stream::set_sfx(sfx_t* pSfx) { qalSourceQueueBuffers(source, 1, &buffers[currentBuf]); alDieIfError(); - qalSourceStop(source); - alDieIfError(); - - iBaseRate = stream->info.rate; + iBaseRate = stream->info.rate; currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; - streaming = true; + streaming = true; return true; } +/* +============== +openal_channel_two_d_stream::set_sample_loop_count +============== +*/ void openal_channel_two_d_stream::set_sample_loop_count(S32 count) { sampleLoopCount = count; - sampleLooped = 0; + sampleLooped = 0; } -openal_channel_two_d_stream::openal_channel_two_d_stream() { +/* +============== +openal_channel_two_d_stream::openal_channel_two_d_stream +============== +*/ +openal_channel_two_d_stream::openal_channel_two_d_stream() +{ int i; streamHandle = NULL; for (i = 0; i < MAX_STREAM_BUFFERS; i++) { buffers[i] = 0; } - currentBuf = 0; - sampleLoopCount = 0; - sampleLooped = 0; - streaming = false; + currentBuf = 0; + sampleLoopCount = 0; + sampleLooped = 0; + streamNextOffset = 0; + streaming = false; } +/* +============== +openal_channel_two_d_stream::openal_channel_two_d_stream +============== +*/ +openal_channel_two_d_stream::~openal_channel_two_d_stream() +{ + clear_stream(); +} + +/* +============== +openal_channel_two_d_stream::update +============== +*/ void openal_channel_two_d_stream::update() { - snd_stream_t* stream = (snd_stream_t*)streamHandle; - int bytesToRead, bytesRead; - ALuint format; - ALint numProcessedBuffers = 0; - ALint numQueuedBuffers = 0; - ALint state = get_state(); + snd_stream_t *stream = (snd_stream_t *)streamHandle; + unsigned int bytesToRead, bytesRead; + ALuint format; + ALint numProcessedBuffers = 0, numQueuedBuffers = 0; + ALint state = sample_status(); // 2 channels with a width of 2 char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; - if (!streaming) { + if (!streaming || is_paused()) { return; } @@ -4373,7 +4403,7 @@ void openal_channel_two_d_stream::update() alDieIfError(); // Remove processed buffers after half of the queued buffers has been processed - if (numProcessedBuffers >= numQueuedBuffers / 2) { + if (numProcessedBuffers >= Q_max(numQueuedBuffers / 2, 1)) { while (numProcessedBuffers-- > 0) { ALuint tmpBuffer; qalSourceUnqueueBuffers(source, 1, &tmpBuffer); @@ -4392,11 +4422,12 @@ void openal_channel_two_d_stream::update() return; } - bytesToRead = Q_min(stream->info.width * stream->info.channels * MAX_BUFFER_SAMPLES, sizeof(rawData)); + bytesToRead = Q_min(MAX_BUFFER_SAMPLES * stream->info.width * stream->info.channels, sizeof(rawData)); format = S_OPENAL_Format(stream->info.width, stream->info.channels); bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + streamNextOffset += bytesRead; if (!bytesRead) { S_CodecCloseStream(stream); @@ -4407,18 +4438,23 @@ void openal_channel_two_d_stream::update() return; } + // + // Looped, start again from the beginning + // streamHandle = S_CodecLoad(this->fileName, NULL); if (!streamHandle) { clear_stream(); return; } - stream = (snd_stream_t*)streamHandle; + stream = (snd_stream_t *)streamHandle; // // Re-read the format, we never know... // format = S_OPENAL_Format(stream->info.width, stream->info.channels); - bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + streamNextOffset = bytesRead; if (!bytesRead) { S_CodecCloseStream(stream); streamHandle = NULL; @@ -4442,16 +4478,185 @@ void openal_channel_two_d_stream::update() currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; } -bool openal_channel_two_d_stream::queue_stream(const char* fileName) { - - ALint freq = 0; - ALuint format = 0; - snd_stream_t* stream; - int bytesToRead = 0; - int bytesRead; - ALuint old = 0; - int i; - char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; +/* +============== +openal_channel_two_d_stream::sample_offset +============== +*/ +U32 openal_channel_two_d_stream::sample_offset() +{ + snd_stream_t *stream = (snd_stream_t *)streamHandle; + ALint playerByteOffset = 0; + ALint numProcessedBuffers = 0; + ALint numQueuedBuffers = 0; + unsigned int totalQueueLength = 0; + unsigned int bytesPerSample = 0; + ALint bits = 0, channels = 0; + + if (!streaming) { + // no stream + return 0; + } + + // Get the byte offset in the queue + qalGetSourcei(source, AL_BYTE_OFFSET, &playerByteOffset); + alDieIfError(); + + totalQueueLength = getQueueLength(); + + assert(playerByteOffset < totalQueueLength); + assert(streamNextOffset >= totalQueueLength); + + bytesPerSample = getBytesPerSample(); + + return (streamNextOffset - totalQueueLength + playerByteOffset) / bytesPerSample; +} + +/* +============== +openal_channel_two_d_stream::buffer_frequency +============== +*/ +U32 openal_channel_two_d_stream::buffer_frequency() const +{ + unsigned int bufferId; + ALint freq = 0; + + bufferId = (currentBuf - 1) % MAX_STREAM_BUFFERS; + qalGetBufferi(buffers[bufferId], AL_FREQUENCY, &freq); + alDieIfError(); + + return freq; +} + +/* +============== +openal_channel_two_d_stream::set_sample_offset +============== +*/ +void openal_channel_two_d_stream::set_sample_offset(U32 offset) +{ + snd_stream_t *stream; + unsigned int bytesToRead, bytesRead; + unsigned int byteOffset; + unsigned int bytesPerSample; + unsigned int streamPosition; + ALuint format; + ALint numQueuedBuffers; + bool bWasPlaying; + char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; + + if (!streaming) { + return; + } + + stream = (snd_stream_t *)streamHandle; + streamPosition = getCurrentStreamPosition(); + bytesPerSample = getBytesPerSample(); + byteOffset = offset * bytesPerSample; + + if (byteOffset >= streamPosition && byteOffset < streamNextOffset) { + // + // Sample is in the currently streamed data + // + qalSourcei(source, AL_BYTE_OFFSET, byteOffset - streamPosition); + alDieIfError(); + + return; + } + + bWasPlaying = is_playing(); + + if (byteOffset < streamPosition) { + // + // New offset is before the current offset, + // reload the stream from the beginning + // + if (stream) { + S_CodecCloseStream(stream); + streamHandle = NULL; + } + } + + if (!streamHandle) { + streamHandle = S_CodecLoad(this->fileName, NULL); + if (!streamHandle) { + clear_stream(); + return; + } + + stream = (snd_stream_t *)streamHandle; + streamNextOffset = 0; + } + + while (streamNextOffset <= byteOffset) { + streamPosition = streamNextOffset; + + bytesToRead = Q_min(MAX_BUFFER_SAMPLES * stream->info.width * stream->info.channels, sizeof(rawData)); + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + if (!bytesRead) { + clear_stream(); + return; + } + + streamNextOffset += bytesRead; + } + + // + // Stop the sound and remove all buffers from the queue + // + qalSourceStop(source); + alDieIfError(); + + // + // Remove all buffers from the queue + // + numQueuedBuffers = 0; + qalGetSourcei(source, AL_BUFFERS_QUEUED, &numQueuedBuffers); + alDieIfError(); + + while (numQueuedBuffers--) { + ALuint b; + qalSourceUnqueueBuffers(source, 1, &b); + alDieIfError(); + } + + format = S_OPENAL_Format(stream->info.width, stream->info.channels); + + qalBufferData(buffers[currentBuf], format, rawData, bytesRead, stream->info.rate); + alDieIfError(); + + qalSourceQueueBuffers(source, 1, &buffers[currentBuf]); + alDieIfError(); + currentBuf = (currentBuf + 1) % MAX_STREAM_BUFFERS; + + // + // Now set the source offset + // + qalSourcei(source, AL_BYTE_OFFSET, byteOffset - streamPosition); + alDieIfError(); + + if (bWasPlaying) { + // + // The sound was stopped when re-streaming + // + play(); + } +} + +/* +============== +openal_channel_two_d_stream::queue_stream +============== +*/ +bool openal_channel_two_d_stream::queue_stream(const char *fileName) +{ + snd_stream_t *stream; + unsigned int bytesToRead, bytesRead; + ALint freq = 0; + ALuint format = 0; + ALuint old = 0; + char rawData[MAX_BUFFER_SAMPLES * 2 * 2]; // Store the filename so it can be looped later Q_strncpyz(this->fileName, fileName, sizeof(this->fileName)); @@ -4466,10 +4671,10 @@ bool openal_channel_two_d_stream::queue_stream(const char* fileName) { if (!streamHandle) { return false; } - stream = (snd_stream_t*)streamHandle; + stream = (snd_stream_t *)streamHandle; iStartTime = cl.serverTime; - iEndTime = (int)(cl.serverTime + (stream->info.samples / stream->info.rate * 1000.f)); + iEndTime = (int)(cl.serverTime + (stream->info.samples / stream->info.rate * 1000.f)); format = S_OPENAL_Format(stream->info.width, stream->info.channels); if (!format) { @@ -4488,13 +4693,15 @@ bool openal_channel_two_d_stream::queue_stream(const char* fileName) { alDieIfError(); // Read a smaller sample - bytesToRead = Q_min(stream->info.width * stream->info.channels * (MAX_BUFFER_SAMPLES / 2), sizeof(rawData)); - bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); + bytesToRead = Q_min(MAX_BUFFER_SAMPLES * stream->info.width * stream->info.channels, sizeof(rawData)); + bytesRead = S_CodecReadStream(stream, bytesToRead, rawData); if (!bytesRead) { // Valid stream but no data? return true; } + streamNextOffset = bytesRead; + qalBufferData(buffers[currentBuf], format, rawData, bytesRead, stream->info.rate); alDieIfError(); @@ -4508,23 +4715,93 @@ bool openal_channel_two_d_stream::queue_stream(const char* fileName) { return true; } -void openal_channel_two_d_stream::clear_stream() { +/* +============== +openal_channel_two_d_stream::clear_stream +============== +*/ +void openal_channel_two_d_stream::clear_stream() +{ if (!streaming) { return; } qalSourceStop(source); qalSourcei(source, AL_BUFFER, 0); - qalDeleteBuffers(1, buffers); + qalDeleteBuffers(MAX_STREAM_BUFFERS, buffers); if (streamHandle) { - S_CodecCloseStream((snd_stream_t*)streamHandle); + S_CodecCloseStream((snd_stream_t *)streamHandle); } - fileName[0] = 0; + fileName[0] = 0; streamHandle = NULL; - currentBuf = 0; - streaming = false; - sampleLooped = 0; + currentBuf = 0; + streamNextOffset = 0; + streaming = false; + sampleLooped = 0; +} + +/* +============== +openal_channel_two_d_stream::getQueueLength + +Return the total length of all buffers being streamed. +============== +*/ +unsigned int openal_channel_two_d_stream::getQueueLength() const +{ + ALint numQueuedBuffers = 0; + unsigned int totalQueueLength = 0; + unsigned int bufferId; + unsigned int i; + + qalGetSourcei(source, AL_BUFFERS_QUEUED, &numQueuedBuffers); + alDieIfError(); + + for (i = 0; i < numQueuedBuffers; i++) { + ALint bufferSize = 0; + + bufferId = (currentBuf - i - 1) % MAX_STREAM_BUFFERS; + qalGetBufferi(buffers[bufferId], AL_SIZE, &bufferSize); + + totalQueueLength += bufferSize; + } + + return totalQueueLength; +} + +/* +============== +openal_channel_two_d_stream::getCurrentStreamPosition + +Return the current position in the sound being streamed. +============== +*/ +unsigned int openal_channel_two_d_stream::getCurrentStreamPosition() const +{ + return streamNextOffset - getQueueLength(); +} + +/* +============== +openal_channel_two_d_stream::getBytesPerSample + +Return the number of bytes per sample. +It assumes that all pending buffers have the same channels and bits. +============== +*/ +unsigned int openal_channel_two_d_stream::getBytesPerSample() const +{ + unsigned int bufferId; + ALint bits = 0, channels = 0; + + bufferId = (currentBuf - 1) % MAX_STREAM_BUFFERS; + qalGetBufferi(buffers[bufferId], AL_BITS, &bits); + alDieIfError(); + qalGetBufferi(buffers[bufferId], AL_CHANNELS, &channels); + alDieIfError(); + + return bits * channels / 8; } diff --git a/code/client/snd_openal_new.h b/code/client/snd_openal_new.h index 26f63a32..db1af9d3 100644 --- a/code/client/snd_openal_new.h +++ b/code/client/snd_openal_new.h @@ -45,8 +45,8 @@ typedef unsigned int U32; #define OPENAL_CHANNEL_TRIGGER_MUSIC_ID (OPENAL_CHANNEL_MP3_ID + 1) #define OPENAL_CHANNEL_MOVIE_ID (OPENAL_CHANNEL_TRIGGER_MUSIC_ID + 1) -#define MAX_STREAM_BUFFERS 16 -#define MAX_BUFFER_SAMPLES 16384 +#define MAX_STREAM_BUFFERS 16 +#define MAX_BUFFER_SAMPLES 16384 typedef enum { FADE_NONE, @@ -105,13 +105,12 @@ struct openal_channel { ALubyte *bufferdata; public: - void play(); + void play(); virtual void stop(); - void pause(); + void pause(); void set_no_3d(); void set_3d(); - ALint get_state(); void set_gain(float gain); void set_velocity(float v0, float v1, float v2); @@ -121,7 +120,7 @@ public: bool is_paused(); bool is_playing(); - void force_free(); + void force_free(); virtual bool set_sfx(sfx_t *pSfx); void start_sample(); @@ -133,47 +132,61 @@ public: void set_sample_playback_rate(S32 pan); S32 sample_playback_rate(); - S32 sample_volume(); - U32 sample_offset(); - U32 sample_ms_offset(); - U32 sample_loop_count(); - void set_sample_offset(U32 offset); - void set_sample_ms_offset(U32 offset); + S32 sample_volume(); + virtual U32 sample_offset(); + U32 sample_ms_offset(); + U32 sample_loop_count(); + virtual void set_sample_offset(U32 offset); + void set_sample_ms_offset(U32 offset); virtual void set_sample_loop_count(S32 count); - void set_sample_loop_block(S32 start_offset, S32 end_offset); + void set_sample_loop_block(S32 start_offset, S32 end_offset); U32 sample_status(); public: virtual void update(); + + virtual U32 buffer_frequency() const; }; struct openal_channel_two_d_stream : public openal_channel { private: - char fileName[64]; - void *streamHandle; + char fileName[64]; + void *streamHandle; unsigned int buffers[MAX_STREAM_BUFFERS]; unsigned int currentBuf; - int sampleLoopCount; - int sampleLooped; - bool streaming; + unsigned int sampleLoopCount; + unsigned int sampleLooped; + unsigned int streamNextOffset; + bool streaming; public: openal_channel_two_d_stream(); + ~openal_channel_two_d_stream(); void stop() override; - bool set_sfx(sfx_t* pSfx) override; + bool set_sfx(sfx_t *pSfx) override; void set_sample_loop_count(S32 count) override; void update() override; - bool queue_stream(const char* fileName); + U32 sample_offset() override; + void set_sample_offset(U32 offset) override; + + bool queue_stream(const char *fileName); + +protected: + U32 buffer_frequency() const override; private: void clear_stream(); + + unsigned int getQueueLength() const; + unsigned int getCurrentStreamPosition() const; + unsigned int getBytesPerSample() const; }; struct openal_internal_t { - openal_channel chan_3D[MAX_OPENAL_CHANNELS_3D]; - openal_channel chan_2D[MAX_OPENAL_CHANNELS_2D]; + openal_channel chan_3D[MAX_OPENAL_CHANNELS_3D]; + openal_channel chan_2D[MAX_OPENAL_CHANNELS_2D]; openal_channel_two_d_stream chan_2D_stream[MAX_OPENAL_CHANNELS_2D_STREAM]; openal_channel_two_d_stream chan_song[MAX_OPENAL_SONGS]; openal_channel_two_d_stream chan_mp3; @@ -196,39 +209,39 @@ struct openal_internal_t { extern "C" { #endif -qboolean S_OPENAL_Init(); -void S_OPENAL_Shutdown(); -void S_OPENAL_StartSound( + qboolean S_OPENAL_Init(); + void S_OPENAL_Shutdown(); + void S_OPENAL_StartSound( + const vec3_t vOrigin, + int iEntNum, + int iEntChannel, + sfxHandle_t sfxHandle, + float fVolume, + float fMinDist, + float fPitch, + float fMaxDist, + qboolean bStreamed + ); + void S_OPENAL_AddLoopingSound( const vec3_t vOrigin, - int iEntNum, - int iEntChannel, + const vec3_t vVelocity, sfxHandle_t sfxHandle, float fVolume, float fMinDist, - float fPitch, float fMaxDist, - qboolean bStreamed + float fPitch, + int iFlags ); -void S_OPENAL_AddLoopingSound( - const vec3_t vOrigin, - const vec3_t vVelocity, - sfxHandle_t sfxHandle, - float fVolume, - float fMinDist, - float fMaxDist, - float fPitch, - int iFlags -); -void S_OPENAL_ClearLoopingSounds(); -void S_OPENAL_StopSound(int iEntNum, int iEntChannel); -void S_OPENAL_StopAllSounds(qboolean bStopMusic); -void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxis[3]); -void S_OPENAL_SetReverb(int iType, float fLevel); -void S_OPENAL_Update(); + void S_OPENAL_ClearLoopingSounds(); + void S_OPENAL_StopSound(int iEntNum, int iEntChannel); + void S_OPENAL_StopAllSounds(qboolean bStopMusic); + void S_OPENAL_Respatialize(int iEntNum, const vec3_t vHeadPos, const vec3_t vAxis[3]); + void S_OPENAL_SetReverb(int iType, float fLevel); + void S_OPENAL_Update(); -const char* S_OPENAL_GetMusicFilename(); -int S_OPENAL_GetMusicLoopCount(); -unsigned int S_OPENAL_GetMusicOffset(); + const char *S_OPENAL_GetMusicFilename(); + int S_OPENAL_GetMusicLoopCount(); + unsigned int S_OPENAL_GetMusicOffset(); #ifdef __cplusplus } From 194e898d907c8453324c6fed37fd92243b96b313 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:22:40 +0200 Subject: [PATCH 0675/2040] Ignore bad SFX for 3D loop sounds --- code/client/snd_openal_new.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 684314f7..8558682d 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1894,6 +1894,10 @@ static int S_OPENAL_Start3DLoopSound( return -1; } + if (!pLoopSound->pSfx->data || !pLoopSound->pSfx->length) { + return -1; + } + iChannel = S_OPENAL_PickChannel3D(0, 0); if (iChannel < 0) { Com_DPrintf("Could not find a free channel\n"); From a150c1b18bbcfb31ec6df477ceb0f42b8afe7376 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 18:18:20 +0200 Subject: [PATCH 0676/2040] Fix animation delta repeating when getting delta of the same frame This fixes actors moving too much and strangely --- code/skeletor/skeletor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 62aca4fe..c155285a 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -121,7 +121,9 @@ SkelVec3 skelAnimDataGameHeader_s::GetDeltaOverTime(float time1, float time2) delta.z += m_frame[frameNum2 % numFrames].delta.z * s; } else { s = s - (1.0 - d); - delta = m_frame[frameNum2 % numFrames].delta; + delta.x = m_frame[frameNum2 % numFrames].delta.x * s; + delta.y = m_frame[frameNum2 % numFrames].delta.y * s; + delta.z = m_frame[frameNum2 % numFrames].delta.z * s; } if (delta.x > -0.001f && delta.x < 0.001f) { From 444ce284ae015493c59f73c4cb144bdace5c880a Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 18:55:10 +0200 Subject: [PATCH 0677/2040] Spawn a trigger field even if the TOGGLE flag is set This fixes Actors not being able to open doors --- code/fgame/doors.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/fgame/doors.cpp b/code/fgame/doors.cpp index 144c7d29..92a2a090 100644 --- a/code/fgame/doors.cpp +++ b/code/fgame/doors.cpp @@ -1095,10 +1095,7 @@ void Door::LinkDoors(Event *ev) return; } - // Don't spawn trigger field when set to toggle - if (!(spawnflags & DOOR_TOGGLE)) { - SpawnTriggerField(cmins, cmaxs); - } + SpawnTriggerField(cmins, cmaxs); } void Door::SetTime(Event *ev) From 06d2eaf4098cf826b1b8793186b40d4c63e552bb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:04:49 +0200 Subject: [PATCH 0678/2040] Fix doors opening and closing indefinitely by actors --- code/fgame/doors.cpp | 68 ++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/code/fgame/doors.cpp b/code/fgame/doors.cpp index 92a2a090..ddb4bb61 100644 --- a/code/fgame/doors.cpp +++ b/code/fgame/doors.cpp @@ -843,6 +843,8 @@ void Door::DoorBlocked(Event *ev) void Door::FieldTouched(Event *ev) { Entity *other; + Actor* otherActor; + float dist; other = ev->GetEntity(1); @@ -850,41 +852,45 @@ void Door::FieldTouched(Event *ev) return; } - if (other->IsSubclassOfActor()) { - Actor* otherActor = static_cast(other); - float dist; - - otherActor->m_Path.ForceShortLookahead(); - - if (state == STATE_OPENING) { - otherActor->m_maxspeed = speed * 64; - } - - if ((state != STATE_OPEN) && !(spawnflags & DOOR_AUTO_OPEN) && !other->isSubclassOf(Actor)) { + if (!other->IsSubclassOfActor()) { + if ((spawnflags & DOOR_TOGGLE) || (state != STATE_OPEN && !(spawnflags & DOOR_AUTO_OPEN))) { return; } - dist = VectorLength2D(other->velocity) * 0.25f; - if (other->absmin[0] > absmax[0] + dist) { - return; - } - if (other->absmin[1] > absmax[1] + dist) { - return; - } - if (other->absmin[2] > absmax[2]) { - return; - } + TryOpen(ev); + return; + } - if (other->absmax[0] < absmin[0] - dist) { - return; - } - if (other->absmax[1] < absmin[1] - dist) { - return; - } - if (other->absmax[2] < absmin[2]) { - return; - } - } else if ((state != STATE_OPEN) && !(spawnflags & DOOR_AUTO_OPEN) && !other->isSubclassOf(Actor)) { + otherActor = static_cast(other); + + otherActor->m_Path.ForceShortLookahead(); + + if (state == STATE_OPENING) { + otherActor->m_maxspeed = speed * 64; + } + + if (((spawnflags & DOOR_TOGGLE) || (state != STATE_OPEN && !(spawnflags & DOOR_AUTO_OPEN))) && (state == STATE_OPEN || state == STATE_OPENING)) { + return; + } + + dist = VectorLength2D(other->velocity) * 0.25f; + if (other->absmin[0] > absmax[0] + dist) { + return; + } + if (other->absmin[1] > absmax[1] + dist) { + return; + } + if (other->absmin[2] > absmax[2]) { + return; + } + + if (other->absmax[0] < absmin[0] - dist) { + return; + } + if (other->absmax[1] < absmin[1] - dist) { + return; + } + if (other->absmax[2] < absmin[2]) { return; } From 9413eb0d5881d38e44215349f424a82a3a9b2402 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:58:10 +0200 Subject: [PATCH 0679/2040] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..28615490 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**qconsole.log** +If applicable, add the `qconsole.log` file. On Windows, it can be found in **%APPDATA%\...\qconsole.log** and on Linux, it can be found on the home directory **~/.openmohaa/.../qconsole.log** + +**Desktop (please complete the following information):** + - OS: [e.g. Debian] + - OS Version [e.g 12] + - OpenMoHAA Version: [e.g `0.70.0-alpha+0.0b1a20dcf win_msvc64-x86_64-debug`] + +**Additional context** +Add any other context about the problem here. From 37db2e8accb1db020993db613bfd886c6556ee80 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:04:30 +0200 Subject: [PATCH 0680/2040] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 28615490..c7193bb6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,16 +20,20 @@ Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** +**Screenshots (OPTIONAL)** If applicable, add screenshots to help explain your problem. -**qconsole.log** -If applicable, add the `qconsole.log` file. On Windows, it can be found in **%APPDATA%\...\qconsole.log** and on Linux, it can be found on the home directory **~/.openmohaa/.../qconsole.log** +**Logs** +- If applicable, add the `qconsole.log` file. On Windows, it can be found in **%APPDATA%\...\qconsole.log** and on Linux, it can be found on the home directory **~/.openmohaa/.../qconsole.log**. +- If there is no `qconsole.log`, paste the output of the console window. -**Desktop (please complete the following information):** +**Version information (please complete the following information):** - OS: [e.g. Debian] - OS Version [e.g 12] - OpenMoHAA Version: [e.g `0.70.0-alpha+0.0b1a20dcf win_msvc64-x86_64-debug`] -**Additional context** +**Dump (OPTIONAL)** +You can include a core dump generated by the OS (`.dmp` file). If you compiled OpenMoHAA yourself, also add all output openmohaa binaries (except libopenal and libSDL). + +**Additional context (OPTIONAL)** Add any other context about the problem here. From fde4d8d54fa5a521f4e38a1927bbe2efb20035b3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:11:14 +0200 Subject: [PATCH 0681/2040] Update README and bug report --- .github/ISSUE_TEMPLATE/bug_report.md | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c7193bb6..1027042a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,13 +24,13 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Logs** -- If applicable, add the `qconsole.log` file. On Windows, it can be found in **%APPDATA%\...\qconsole.log** and on Linux, it can be found on the home directory **~/.openmohaa/.../qconsole.log**. -- If there is no `qconsole.log`, paste the output of the console window. +- Paste the output of the console window in a text file, and attach the text file. +- If applicable (`logfile` set to 2), attach the `qconsole.log` file. On Windows, it can be found in **%APPDATA%\...\qconsole.log** and on Linux, it can be found on the home directory **~/.openmohaa/.../qconsole.log**. **Version information (please complete the following information):** - - OS: [e.g. Debian] - - OS Version [e.g 12] - - OpenMoHAA Version: [e.g `0.70.0-alpha+0.0b1a20dcf win_msvc64-x86_64-debug`] + - OS: [e.g. `Debian`] + - OS Version [e.g `12`] + - OpenMoHAA Version: [e.g `0.70.0-alpha+0.0b1a20dcf win_msvc64-x86_64-debug`, can be found below **Common Initialization** in the console, or by typing `version`] **Dump (OPTIONAL)** You can include a core dump generated by the OS (`.dmp` file). If you compiled OpenMoHAA yourself, also add all output openmohaa binaries (except libopenal and libSDL). diff --git a/README.md b/README.md index cf18a7e5..ba789e5b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The main goal of OpenMoHAA is to ensure the future and continuity of **Medal of ### Single-player -The entire single-player campaign can be played from start to end. There may be occasional bugs though; if you encounter any, please create a GitHub issue describing them. +The entire single-player campaign can be played from start to end. There may be occasional bugs though; if you encounter any, please create a new [GitHub issue](https://github.com/openmoh/openmohaa/issues) describing them. ### Multiplayer From ccb1465e170966107e8d8f0715a515e9c7c4d2fb Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 23:05:43 +0200 Subject: [PATCH 0682/2040] Use a raw pointer instead of the str object Original game checks for the NUL character using the line buffer (`c_str()`) directly instead of the str object's operator[], as this would cause an assertion failure because the str's length ignore the NUL character --- code/uilib/uimledit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/uilib/uimledit.cpp b/code/uilib/uimledit.cpp index 668286ef..825dfcfb 100644 --- a/code/uilib/uimledit.cpp +++ b/code/uilib/uimledit.cpp @@ -359,13 +359,13 @@ void UIMultiLineEdit::PointToSelectionPoint(const UIPoint2D& p, selectionpoint_t return; } - str& line = LineFromLineNumber(clickedLine, true); - for (i = 0; line[i] && totalWidth < p.x; i++) { + const char *line = LineFromLineNumber(clickedLine, true).c_str(); + for (i = 0; i < line[i] && totalWidth < p.x; i++) { lastWidth = m_font->getCharWidth(line[i]); totalWidth += lastWidth; } - if (line[i] && i) { + if (i < line[i] && i) { lastWidth *= 0.5f; if (totalWidth - lastWidth >= p.x) { i--; From ad88215b85d20f808cf8b89c50c51694ed0a754f Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 23:42:31 +0200 Subject: [PATCH 0683/2040] Cleaned up actor_runandshoot.cpp --- code/fgame/actor_runandshoot.cpp | 65 +++++++++----------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/code/fgame/actor_runandshoot.cpp b/code/fgame/actor_runandshoot.cpp index 13088e82..1939dbb2 100644 --- a/code/fgame/actor_runandshoot.cpp +++ b/code/fgame/actor_runandshoot.cpp @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // actor_runandshoot.cpp +// +// Added in 2.30 +// #include "actor.h" @@ -37,9 +40,10 @@ void Actor::InitRunAndShoot(GlobalFuncs_t *func) void Actor::Begin_RunAndShoot(void) { - m_State = ACTOR_STATE_RUN_AND_SHOOT_RUN; if (m_patrolCurrentNode) { m_State = ACTOR_STATE_RUN_AND_SHOOT_RUNNING; + } else { + m_State = ACTOR_STATE_RUN_AND_SHOOT_RUN; } } @@ -143,62 +147,29 @@ bool Actor::RunAndShoot_MoveToPatrolCurrentNode(void) if (MoveOnPathWithSquad()) { if (m_Enemy) { - m_eNextAnimMode = ANIM_MODE_PATH; - m_csNextAnimString = STRING_ANIM_RUNTO_INOPEN_SCR; - m_bNextForceStart = false; - - Vector delta; - Vector lookDir; - - delta = mTargetPos - EyePosition(); - lookDir = delta; - lookDir[2] += 16; - SetDesiredLookDir(lookDir); - - m_DesiredGunDir[0] = 360 - delta.toPitch(); - m_DesiredGunDir[1] = delta.toYaw(); - m_DesiredGunDir[2] = 0; - SetDesiredYaw(m_DesiredGunDir[1]); + DesiredAnimation(ANIM_MODE_PATH, STRING_ANIM_RUNTO_INOPEN_SCR); + AimAtTargetPos(); } else { - m_eNextAnimMode = ANIM_MODE_PATH; - m_csNextAnimString = STRING_ANIM_CROUCH_RUN_SCR; - m_bNextForceStart = false; + DesiredAnimation(ANIM_MODE_PATH, STRING_ANIM_CROUCH_RUN_SCR); FaceMotion(); } } else if (m_Enemy) { - Vector delta; - Vector lookDir; - - delta = mTargetPos - EyePosition(); - lookDir = delta; - lookDir[2] += 16; - SetDesiredLookDir(lookDir); - - m_DesiredGunDir[0] = 360 - delta.toPitch(); - m_DesiredGunDir[1] = delta.toYaw(); - m_DesiredGunDir[2] = 0; - SetDesiredYaw(m_DesiredGunDir[1]); + AimAtTargetPos(); Anim_Attack(); } else { Anim_Stand(); IdleLook(); } - if (!m_fMoveDoneRadiusSquared) { - return false; + if (m_fMoveDoneRadiusSquared) { + if (PathComplete()) { + return true; + } + + if (m_Path.HasCompleteLookahead() && !m_patrolCurrentNode->Next()) { + return VectorLength2DSquared(PathDelta()) <= m_fMoveDoneRadiusSquared; + } } - if (PathComplete()) { - return true; - } - - if (!m_Path.HasCompleteLookahead() || m_patrolCurrentNode->Next()) { - return false; - } - - if (VectorLength2DSquared(PathDelta()) > m_fMoveDoneRadiusSquared) { - return false; - } - - return true; + return false; } From 0b3aad5ad201a9d74c7596d312e65fe5ac8afe87 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Mon, 26 Aug 2024 23:55:45 +0200 Subject: [PATCH 0684/2040] Fix entnum comparison (must be greater than or equal to the squadmate's entnum) --- code/fgame/actor.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 14f0707c..b9235942 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -3630,7 +3630,8 @@ void Actor::SafeSetOrigin(vec3_t newOrigin) if (!m_bNoPlayerCollision) { Player *p = (Player *)G_GetEntity(0); - // Solidity check added in 2.30 + // Added in 2.30 + // Solidity check. // If the Actor is already nonsolid the player won't get stuck if (p && IsTouching(p) && getSolidType() != SOLID_NOT) { Com_Printf("(entnum %d, radnum %d) is going not solid to not get stuck in the player\n", entnum, radnum); @@ -3895,7 +3896,8 @@ bool Actor::CanShoot(Entity *ent) Vector vGunPos; if (FriendlyInLineOfFire(ent)) { - // This check was added in 2.0 + // Added in 2.0 + // Check if a friend is in sight bCanShoot = false; } else if (ent->IsSubclassOfSentient()) { Sentient *sen = static_cast(ent); @@ -4975,7 +4977,7 @@ void Actor::HandlePain(Event *ev) //FIXME: macro SetCuriousAnimHint(7); - // m_bIsCurious check: Added in 2.30 + // Added in 2.30 the m_bIsCurous check if (m_bEnableEnemy && m_ThinkStates[THINKLEVEL_IDLE] == THINKSTATE_IDLE && m_bIsCurious) { SetEnemyPos(attacker->origin); m_pszDebugState = "from_pain"; @@ -5967,7 +5969,7 @@ bool Actor::MoveOnPathWithSquad(void) } if (DotProduct2D(pvMyDir, pvHisDir) >= 0 - && (entnum == pActorSquadMate->entnum || DotProduct2D(pvHisDir, vDelta) >= 0)) { + && (entnum >= pActorSquadMate->entnum || DotProduct2D(pvHisDir, vDelta) >= 0)) { m_iSquadStandTime = level.inttime; return false; } @@ -6325,7 +6327,9 @@ void Actor::Init(void) InitWeaponless(&GlobalFuncs[THINK_WEAPONLESS]); InitNoClip(&GlobalFuncs[THINK_NOCLIP]); InitDead(&GlobalFuncs[THINK_DEAD]); + // Added in 2.0 InitBadPlace(&GlobalFuncs[THINK_BADPLACE]); + // Added in 2.30 InitRunAndShoot(&GlobalFuncs[THINK_RUN_AND_SHOOT]); AddWaitTill(STRING_VISIBLE); From 7f7d797fce9303a7a6b7e868c4b52d23f212a1f6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 27 Aug 2024 00:34:31 +0200 Subject: [PATCH 0685/2040] Fix vehicles getting blocked by sentients dying --- code/fgame/vehicle.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/fgame/vehicle.cpp b/code/fgame/vehicle.cpp index d8a7efb6..6c583114 100644 --- a/code/fgame/vehicle.cpp +++ b/code/fgame/vehicle.cpp @@ -4396,7 +4396,15 @@ void Vehicle::MoveVehicle(void) ); } - break; + // Added in OPM + // Skip the entity if the sentient is dead. + // This is a workaround against sentients getting in path of vehicles + // and thus blocking them temporarily while dying. + // For example in e1l1, the first tank would get stuck, because sometimes + // there are too many actors moving in the path of the vehicle + if (!bHitPerson || !tr.ent->entity->IsDead()) { + break; + } } pSkippedEntities[iNumSkippedEntities] = tr.ent->entity; From 8b5074b6acf3a95aaa5d7dc6ba5fde10d1d6c00d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 27 Aug 2024 01:01:34 +0200 Subject: [PATCH 0686/2040] Fix Dot/Texcoords calc This caused some shaders such as headlights beam on the opeltruck being weirdly rendered --- code/renderer/tr_shade_calc.c | 78 ++++++++++++----------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index 792e38db..21e5c306 100644 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -946,21 +946,16 @@ void RB_CalcRGBFromDot(unsigned char* colors, float alphaMin, float alphaMax) vec3_t viewInModel; for (i = 0; i < tess.numVertexes; i++, colors += 4) { - union { - float f; - int i; - } u; + float f; VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); VectorNormalizeFast(viewInModel); - u.f = DotProduct(tess.normal[i], viewInModel); - u.f *= u.f; - u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; - u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + f = Square(DotProduct(tess.normal[i], viewInModel)); + f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; + f = f - Q_max((int)(f - 255), 0); - u.i &= ~(u.i >> 31); - colors[0] = colors[1] = colors[2] = u.i; + colors[0] = colors[1] = colors[2] = (unsigned char)Q_max(f, 0); } } @@ -971,26 +966,18 @@ void RB_CalcRGBFromOneMinusDot(unsigned char* colors, float alphaMin, float alph { int i; vec3_t viewInModel; - float dot; for (i = 0; i < tess.numVertexes; i++, colors += 4) { - union { - float f; - int i; - } u; + float f; VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); VectorNormalizeFast(viewInModel); - dot = DotProduct(tess.normal[i], viewInModel); - dot *= dot; + f = 1.0 - Square(DotProduct(tess.normal[i], viewInModel)); + f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; + f = f - Q_max((int)(f - 255), 0); - u.f = 1.0 - dot; - u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; - u.f = u.f - (long double)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); - - u.i &= ~(u.i >> 31); - colors[0] = colors[1] = colors[2] = u.i; + colors[0] = colors[1] = colors[2] = (unsigned char)Q_max(f, 0); } } @@ -1015,21 +1002,16 @@ void RB_CalcAlphaFromDot(unsigned char* colors, float alphaMin, float alphaMax) vec3_t viewInModel; for (i = 0; i < tess.numVertexes; i++, colors += 4) { - union { - float f; - int i; - } u; + float f; VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); VectorNormalizeFast(viewInModel); - u.f = DotProduct(tess.normal[i], viewInModel); - u.f *= u.f; - u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; - u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); + f = Square(DotProduct(tess.normal[i], viewInModel)); + f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; + f = f - Q_max((int)(f - 255), 0); - u.i &= ~(u.i >> 31); - colors[0] = colors[1] = colors[2] = u.i; + colors[0] = colors[1] = colors[2] = (unsigned char)Q_max(f, 0); } } @@ -1058,26 +1040,18 @@ void RB_CalcAlphaFromOneMinusDot(unsigned char* colors, float alphaMin, float al { int i; vec3_t viewInModel; - float dot; for (i = 0; i < tess.numVertexes; i++, colors += 4) { - union { - float f; - int i; - } u; + float f; VectorSubtract(backEnd.ori.viewOrigin, tess.xyz[i], viewInModel); VectorNormalizeFast(viewInModel); - dot = DotProduct(tess.normal[i], viewInModel); - dot *= dot; + f = 1.0 - Square(DotProduct(tess.normal[i], viewInModel)); + f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; + f = f - Q_max((int)(f - 255), 0); - u.f = 1.0 - dot; - u.f = ((alphaMax - alphaMin) * u.f + alphaMin) * 255.0; - u.f = u.f - (float)(~((int)(u.f - 255.0) >> 31) & (int)(u.f - 255.0)); - - u.i &= ~(u.i >> 31); - colors[0] = colors[1] = colors[2] = u.i; + colors[0] = colors[1] = colors[2] = (unsigned char)Q_max(f, 0); } } @@ -1093,10 +1067,10 @@ void RB_CalcAlphaFromTexCoords(unsigned char* colors, float alphaMin, float alph f = sWeight * tess.texCoords[i][0][0] + tWeight * tess.texCoords[i][0][1]; f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; - f = f - (float)(~((int)(f - (float)(byte)alphaCap) >> 31) & (int)(f - (float)(byte)alphaCap)); - f = (float)((~((int)(f - (float)(byte)alphaMinCap) >> 31) & (int)(f - (float)(byte)alphaMinCap)) + (byte)alphaMinCap); + f = f - Q_max((int)(f - alphaCap), 0); + f = alphaMinCap + Q_max((int)(f - alphaMinCap), 0); - colors[3] = f; + colors[3] = (unsigned char)f; } } @@ -1112,10 +1086,10 @@ void RB_CalcRGBFromTexCoords(unsigned char* colors, float alphaMin, float alphaM f = sWeight * tess.texCoords[i][0][0] + tWeight * tess.texCoords[i][0][1]; f = ((alphaMax - alphaMin) * f + alphaMin) * 255.0; - f = f - (float)(~((int)(f - (float)(byte)alphaCap) >> 31) & (int)(f - (float)(byte)alphaCap)); - f = (float)((~((int)(f - (float)(byte)alphaMinCap) >> 31) & (int)(f - (float)(byte)alphaMinCap)) + (byte)alphaMinCap); + f = f - Q_max((int)(f - alphaCap), 0); + f = alphaMinCap + Q_max((int)(f - alphaMinCap), 0); - colors[0] = colors[1] = colors[2] = f; + colors[0] = colors[1] = colors[2] = (unsigned char)f; } } From 6b21f7e92e8574079f1270fb304ac6a049ddbb93 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 27 Aug 2024 01:29:01 +0200 Subject: [PATCH 0687/2040] Fix the turret firedelay behavior on mohaa base --- code/fgame/weapturret.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index a5900401..9eeb52d8 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -1246,6 +1246,18 @@ void TurretGun::AI_DoFiring() float minBurstTime, maxBurstTime; float minBurstDelay, maxBurstDelay; + if (g_target_game == target_game_e::TG_MOH) { + // + // Removed in 2.0 + // The fire delay is always constant on 1.11 and below + // + if (ReadyToFire(FIRE_PRIMARY)) { + Fire(FIRE_PRIMARY); + } + + return; + } + minBurstTime = m_fMinBurstTime; maxBurstTime = m_fMaxBurstTime; minBurstDelay = m_fMinBurstDelay; @@ -1936,6 +1948,17 @@ void TurretGun::StopWeaponAnim(void) float TurretGun::FireDelay(firemode_t mode) { + if (g_target_game == target_game_e::TG_MOH) { + // + // Removed in 2.0 + // + // On 1.11 and below, the firedelay for players is always 0.06. + // Some maps like m1l1 sets the turret firedelay higher for AI + if (owner && owner->IsSubclassOfPlayer()) { + return 0.06f; + } + } + return fire_delay[FIRE_PRIMARY]; } From 1f71bb714d88cf326c45ac46400436bd806b9519 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:45:50 +0200 Subject: [PATCH 0688/2040] Fix sounds unexpectedly getting marked as streamed when they are not This fixes #345 where a crash occurred because of a NULL buffer, as streamed sounds don't have a memory buffer --- code/fgame/g_utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/fgame/g_utils.cpp b/code/fgame/g_utils.cpp index 1a3ae238..bb4e30bc 100644 --- a/code/fgame/g_utils.cpp +++ b/code/fgame/g_utils.cpp @@ -1174,8 +1174,9 @@ void G_ArchiveEdict(Archiver& arc, gentity_t *edict) arc.ArchiveString(&tempStr); if (tempStr.length()) { + qboolean streamed = tempStr[tempStr.length() - 1] != '0'; tempStr[tempStr.length() - 1] = 0; - edict->s.loopSound = gi.soundindex(tempStr.c_str(), true); + edict->s.loopSound = gi.soundindex(tempStr.c_str(), streamed); } else { edict->s.loopSound = 0; } From 2b9d31fe7f52018cc4374a5c551bd4ffe76628e9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:24:31 +0200 Subject: [PATCH 0689/2040] Normalize angles to fix interpolation issues on client See #342 --- code/fgame/player.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/fgame/player.cpp b/code/fgame/player.cpp index c0c689b0..9ac3b032 100644 --- a/code/fgame/player.cpp +++ b/code/fgame/player.cpp @@ -7734,6 +7734,10 @@ void Player::SetViewAngles(Vector newViewangles) client->ps.delta_angles[2] = ANGLE2SHORT(newViewangles.z - client->cmd_angles[2]); v_angle = newViewangles; + // Fixed in OPM + // Normalize angles to the range (-180, +180) + // so interpolation is done properly client-side + v_angle.EulerNormalize(); // get the pitch and roll from our leg angles newViewangles.x = angles.x; From c7d1f42edbbf719166eb0eb362af3b0362c0d07d Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Aug 2024 00:40:57 +0200 Subject: [PATCH 0690/2040] Use centroid when broadcasting new AI event --- code/fgame/entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/entity.cpp b/code/fgame/entity.cpp index 703daf22..daa608f8 100644 --- a/code/fgame/entity.cpp +++ b/code/fgame/entity.cpp @@ -4135,7 +4135,7 @@ void Entity::BroadcastAIEvent(int iType, float rad) return; } - G_BroadcastAIEvent(this, origin, iType, rad); + G_BroadcastAIEvent(this, centroid, iType, rad); } void Entity::BroadcastAIEvent(Event *ev) From 7a0a671f183463b95549949fd06a36b81b57be50 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Wed, 28 Aug 2024 00:41:53 +0200 Subject: [PATCH 0691/2040] Use the correct value when comparing the sound awareness multiplied by the range factor --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index b9235942..8a96b3ac 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -8861,7 +8861,7 @@ void Actor::CuriousSound(int iType, vec3_t sound_origin, float fDistSquared, flo } } - if ((fRangeFactor * m_fSoundAwareness) < (rand() / 327.67f)) { + if ((fRangeFactor * m_fSoundAwareness) < (rand() / (0x7fffffff / 100.0))) { return; } From 89133bf05d87df75d264d24ccf83e806cd321f39 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:29:11 +0200 Subject: [PATCH 0692/2040] Fix looping sounds not stopped when stopping all sounds This fixes an issue where some random looping sound (like footsteps) would be heard after restarting or when loading a saved game --- code/client/snd_openal_new.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 8558682d..900bb402 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -1796,6 +1796,8 @@ void S_OPENAL_StopAllSounds(qboolean bStopMusic) return; } + S_OPENAL_StopLoopingSounds(); + for (i = 0; i < MAX_OPENAL_POSITION_CHANNELS; i++) { openal_channel *pChannel = openal.channel[i]; if (pChannel) { From 014767741241f25e84d9a73f2912b67288c06b03 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:37:05 +0200 Subject: [PATCH 0693/2040] Calculate sr/cr only if right or up is specified --- code/qcommon/q_math.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index f81c121c..d5c102af 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -2069,9 +2069,6 @@ void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up angle = angles[ PITCH ] * ( M_PI * 2 / 360 ); sp = sin( angle ); cp = cos( angle ); - angle = angles[ ROLL ] * ( M_PI * 2 / 360 ); - sr = sin( angle ); - cr = cos( angle ); if( forward ) { @@ -2079,18 +2076,25 @@ void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up forward[ 1 ] = cp*sy; forward[ 2 ] = -sp; } - if( right ) - { - right[ 0 ] = ( -1 * sr*sp*cy + -1 * cr*-sy ); - right[ 1 ] = ( -1 * sr*sp*sy + -1 * cr*cy ); - right[ 2 ] = -1 * sr*cp; - } - if( up ) - { - up[ 0 ] = ( cr*sp*cy + -sr*-sy ); - up[ 1 ] = ( cr*sp*sy + -sr*cy ); - up[ 2 ] = cr*cp; - } + if ( right || up ) + { + angle = angles[ ROLL ] * ( M_PI * 2 / 360 ); + sr = sin( angle ); + cr = cos( angle ); + + if ( right ) + { + right[ 0 ] = ( -1 * sr * sp * cy + -1 * cr * -sy ); + right[ 1 ] = ( -1 * sr * sp * sy + -1 * cr * cy ); + right[ 2 ] = -1 * sr * cp; + } + if ( up ) + { + up[ 0 ] = ( cr * sp * cy + -sr * -sy ); + up[ 1 ] = ( cr * sp * sy + -sr * cy ); + up[ 2 ] = cr * cp; + } + } } void AngleVectorsLeft( const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up ) From 68f2635c0688be3abbe26874bc80ae9103326dfd Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:31:46 +0200 Subject: [PATCH 0694/2040] Should be DotProduct2D --- code/fgame/actor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 8a96b3ac..250f5679 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -2955,6 +2955,7 @@ Actor::Actor() // // Added in OPM + // The variable isn't set in original // m_bSilent = false; } @@ -3225,7 +3226,7 @@ void Actor::GetMoveInfo(mmove_t *mm) DoFailSafeMove(node->point); } - } else if (DotProduct(mm->velocity, velocity) < -0.7f && level.inttime >= m_Path.Time() + 1000) { + } else if (DotProduct2D(mm->velocity, velocity) < -0.7f && level.inttime >= m_Path.Time() + 1000) { m_Path.ReFindPath(origin, this); } break; From 2fe4e85543d8f5a3f202583157b889a19d8467f0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:39:45 +0200 Subject: [PATCH 0695/2040] Fix path goal end anim script never reaching The end anim script should be executed below a certain speed (1/4 below normal speed). This fixes a bug in e3l4 where the game would never continue past the first bunker. The actor would get stuck after collecting supplies for the first bunker at the beginning because it stopped too far away from the target origin --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 250f5679..3d240375 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -5482,7 +5482,7 @@ void Actor::MovePathGoal(float fMoveSpeed) m_eAnimMode = ANIM_MODE_NORMAL; } } - } else if (fDeltaSquareLen < fMoveSpeed * Square(0.5f)) { + } else if (fDeltaSquareLen < Square(fMoveSpeed * 0.5 * 0.5)) { fTimeToGo = 0.5f; m_fPathGoalTime = level.time + fTimeToGo; if (m_csPathGoalEndAnimScript == STRING_EMPTY) { From 99fcec9f26b4adf816af790f0fd13f8ef4b93abe Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 30 Aug 2024 18:56:01 +0200 Subject: [PATCH 0696/2040] Initialize bStartedGame --- code/server/sv_ccmds.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index cb710e43..f7d7e582 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -2122,6 +2122,8 @@ void SV_Loadgame_f( void ) return; } + bStartedGame = qfalse; + if( !ge ) { SV_InitGameProgs(); From 2239efa43987ebc9d5f77065b9a9c57ae92a3cc3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Fri, 30 Aug 2024 19:13:04 +0200 Subject: [PATCH 0697/2040] Fix sample_offset() returning a wrong value with looping sounds The returned offset will now be the correct when the stream has been re-read from the beginning due to the sound looping --- code/client/snd_openal_new.cpp | 59 +++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/code/client/snd_openal_new.cpp b/code/client/snd_openal_new.cpp index 900bb402..abb47697 100644 --- a/code/client/snd_openal_new.cpp +++ b/code/client/snd_openal_new.cpp @@ -4497,6 +4497,7 @@ U32 openal_channel_two_d_stream::sample_offset() ALint numQueuedBuffers = 0; unsigned int totalQueueLength = 0; unsigned int bytesPerSample = 0; + unsigned int offset = 0; ALint bits = 0, channels = 0; if (!streaming) { @@ -4509,13 +4510,30 @@ U32 openal_channel_two_d_stream::sample_offset() alDieIfError(); totalQueueLength = getQueueLength(); - - assert(playerByteOffset < totalQueueLength); - assert(streamNextOffset >= totalQueueLength); - bytesPerSample = getBytesPerSample(); - return (streamNextOffset - totalQueueLength + playerByteOffset) / bytesPerSample; + assert(playerByteOffset < totalQueueLength); + assert(streamNextOffset >= totalQueueLength || stream); + + if (streamNextOffset >= totalQueueLength) { + offset = streamNextOffset - totalQueueLength + playerByteOffset; + } else if (stream) { + // it probably means the sound is looped and will restart from the beginning + if (streamNextOffset + playerByteOffset <= totalQueueLength) { + // near the end of the stream + offset = stream->info.size + streamNextOffset - totalQueueLength + playerByteOffset; + } else { + // it is past end of stream + // so, start from the beginning of the stream + offset = streamNextOffset + playerByteOffset - totalQueueLength; + } + + assert(offset < stream->info.size); + } else { + offset = totalQueueLength - streamNextOffset + playerByteOffset; + } + + return offset / bytesPerSample; } /* @@ -4573,12 +4591,20 @@ void openal_channel_two_d_stream::set_sample_offset(U32 offset) bWasPlaying = is_playing(); - if (byteOffset < streamPosition) { - // - // New offset is before the current offset, - // reload the stream from the beginning - // - if (stream) { + if (stream) { + if (byteOffset < streamPosition) { + // + // New offset is before the current offset, + // reload the stream from the beginning + // + S_CodecCloseStream(stream); + streamHandle = NULL; + } else if (byteOffset >= stream->info.size) { + // + // This shouldn't happen unless the file is different + // from the one used while saving + // + byteOffset %= stream->info.size; S_CodecCloseStream(stream); streamHandle = NULL; } @@ -4787,7 +4813,16 @@ Return the current position in the sound being streamed. */ unsigned int openal_channel_two_d_stream::getCurrentStreamPosition() const { - return streamNextOffset - getQueueLength(); + unsigned int queueLength = getQueueLength(); + + if (streamNextOffset >= queueLength) { + return streamNextOffset - queueLength; + } else if (streamHandle) { + snd_stream_t* stream = (snd_stream_t*)streamHandle; + return (stream->info.size + streamNextOffset - queueLength) % stream->info.size; + } else { + return queueLength - streamNextOffset; + } } /* From e59a24ded3fd49730bbea854bcc2a1b0c1af7eb9 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:17:37 +0200 Subject: [PATCH 0698/2040] Fix actors enemy not being able to be set if enemy switch is disabled --- code/fgame/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor.cpp b/code/fgame/actor.cpp index 3d240375..0bb67474 100644 --- a/code/fgame/actor.cpp +++ b/code/fgame/actor.cpp @@ -6418,7 +6418,7 @@ void Actor::UpdateEnemyInternal(void) m_PotentialEnemies.CheckEnemies(this); - if (m_Enemy != m_PotentialEnemies.GetCurrentEnemy() && (m_bEnemySwitch || m_Enemy)) { + if (m_Enemy != m_PotentialEnemies.GetCurrentEnemy() && (m_bEnemySwitch || !m_Enemy)) { SetEnemy(m_PotentialEnemies.GetCurrentEnemy(), false); } From 6071b5303c550c65f699bf068f5e45e963fa7f76 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:18:28 +0200 Subject: [PATCH 0699/2040] Remove useless NET_Sleep and make sure frameMsec doesn't go below 1 --- code/server/sv_main.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 95c73afc..82dd29b3 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -69,10 +69,6 @@ cvar_t *sv_gamename; cvar_t *sv_location; cvar_t *sv_debug_gamespy; cvar_t *sv_gamespy; - -// FIXME: use another global network ? -//cvar_t *sv_debug_gamepsy; -//cvar_t *sv_gamespy; cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491) #ifndef STANDALONE cvar_t *sv_strictAuth; @@ -815,17 +811,17 @@ void SV_Frame( int msec ) { if ( sv_fps->integer < 1 ) { Cvar_Set( "sv_fps", "20" ); } - - frameMsec = 1000 / sv_fps->integer; - sv.timeResidual += msec; - - if ( com_dedicated->integer && sv.timeResidual < frameMsec ) { - // NET_Sleep will give the OS time slices until either get a packet - // or time enough for a server frame has gone by - NET_Sleep( frameMsec - sv.timeResidual ); - return; + + frameMsec = 1000 / sv_fps->integer * com_timescale->value; + // don't let it scale below 1ms + if(frameMsec < 1) + { + Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f)); + frameMsec = 1; } + sv.timeResidual += msec; + // if time is about to hit the 32nd bit, kick all clients // and clear sv.time, rather // than checking for negative time wraparound everywhere. From 915269e017566be60de6711608cd02496be9a8ee Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:24:59 +0200 Subject: [PATCH 0700/2040] Fix the actor stuck targeting an enemy with really low threat (behind walls, not visible) This fixes the actor being stuck aiming even if the player is near them --- code/fgame/actorenemy.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/code/fgame/actorenemy.cpp b/code/fgame/actorenemy.cpp index f99020b4..34c828c2 100644 --- a/code/fgame/actorenemy.cpp +++ b/code/fgame/actorenemy.cpp @@ -421,14 +421,13 @@ void ActorEnemySet::CheckEnemies(Actor *pSelf) fRangeSquared = 1e37f; if (m_fCurrentVisibility >= 0.999f) { - iThreat = 0; - for (i = 1; i <= m_Enemies.NumObjects(); i++) { pActorEnemy = &m_Enemies.ObjectAt(i); pActorEnemy->UpdateThreat(pSelf); + iThreat = pActorEnemy->GetThreat(); - if (m_iCurrentThreat >= pActorEnemy->GetThreat()) { - if (m_iCheckCount != pActorEnemy->GetThreat()) { + if (m_iCurrentThreat >= iThreat) { + if (m_iCheckCount != iThreat) { continue; } @@ -437,12 +436,10 @@ void ActorEnemySet::CheckEnemies(Actor *pSelf) } } - iThreat = pActorEnemy->GetThreat(); - m_pCurrentEnemy = pActorEnemy->GetEnemy(); - fRangeSquared = pActorEnemy->m_fCurrentRangeSquared; + m_iCurrentThreat = pActorEnemy->GetThreat(); + m_pCurrentEnemy = pActorEnemy->GetEnemy(); + fRangeSquared = pActorEnemy->m_fCurrentRangeSquared; } - - m_iCurrentThreat = iThreat; } if ((!m_pCurrentEnemy || !m_pCurrentEnemy->m_bIsDisguised) && m_iCurrentThreat <= 0) { From be655e2b9c4d5722c8f0c945dff696bcb18bf111 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:38:50 +0200 Subject: [PATCH 0701/2040] Fix the height of huddraw elements not being archived properly A wrong variable was specified --- code/server/sv_ccmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index f7d7e582..fc4c9fd4 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1653,7 +1653,7 @@ void SV_ArchiveHudDrawElements( qboolean loading ) ge->ArchiveInteger( &cls.HudDrawElements[ i ].iX ); ge->ArchiveInteger( &cls.HudDrawElements[ i ].iY ); ge->ArchiveInteger( &cls.HudDrawElements[ i ].iWidth ); - ge->ArchiveInteger( &cls.HudDrawElements[ i ].iVerticalAlign ); + ge->ArchiveInteger( &cls.HudDrawElements[ i ].iHeight ); ge->ArchiveFloat( &cls.HudDrawElements[ i ].vColor[ 0 ] ); ge->ArchiveFloat( &cls.HudDrawElements[ i ].vColor[ 1 ] ); ge->ArchiveFloat( &cls.HudDrawElements[ i ].vColor[ 2 ] ); From b7288ba3f43efc184c351926f88a2f29c27883c7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:50:10 +0200 Subject: [PATCH 0702/2040] Don't affect the frameMsec with timescale as it causes issues with physics (like vehicles) --- code/server/sv_main.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 82dd29b3..a97f9f9b 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -812,13 +812,7 @@ void SV_Frame( int msec ) { Cvar_Set( "sv_fps", "20" ); } - frameMsec = 1000 / sv_fps->integer * com_timescale->value; - // don't let it scale below 1ms - if(frameMsec < 1) - { - Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f)); - frameMsec = 1; - } + frameMsec = 1000 / sv_fps->integer; sv.timeResidual += msec; From 1911f04079a90b074faf277890c825ea9b46333b Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:22:28 +0200 Subject: [PATCH 0703/2040] Fix strange AI turret target angles The turret sometimes turned extremely fast or ignored the max yaw offset --- code/fgame/weapturret.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/code/fgame/weapturret.cpp b/code/fgame/weapturret.cpp index 9eeb52d8..378731aa 100644 --- a/code/fgame/weapturret.cpp +++ b/code/fgame/weapturret.cpp @@ -648,14 +648,12 @@ void TurretGun::AI_SetTargetAngles(vec3_t vTargAngles, float speed) vTargAngles[1] = m_fStartYaw + m_fMaxYawOffset; } else if (fDiff < -m_fMaxYawOffset) { vTargAngles[1] = m_fStartYaw - m_fMaxYawOffset; - } else { - vTargAngles[1] = m_fStartYaw + fDiff; } fYawDiff = AngleSubtract(vTargAngles[1], angles[1]); fPitchDiff = AngleSubtract(vTargAngles[0], angles[0]); - if (fabs(fPitchDiff) == 0) { + if (speed == 0) { fTurnYawSpeed = m_fTurnSpeed * level.frametime; fTurnPitchSpeed = m_fAIPitchSpeed * level.frametime; } else { @@ -686,10 +684,10 @@ void TurretGun::AI_SetTargetAngles(vec3_t vTargAngles, float speed) if (fabs(fYawDiff) < fTurnYawSpeed) { angles[1] = vTargAngles[1]; - } else if (fPitchDiff > 0) { - angles[1] += fYawDiff; + } else if (fYawDiff > 0) { + angles[1] += fTurnYawSpeed; } else { - angles[1] -= fYawDiff; + angles[1] -= fTurnYawSpeed; } setAngles(angles); From 70fcc70348e9965f63aed2a765714771e0d00589 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:34:10 +0200 Subject: [PATCH 0704/2040] Fix AI turret placement The AI was too much off from the turret --- code/fgame/actor_machinegunner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/fgame/actor_machinegunner.cpp b/code/fgame/actor_machinegunner.cpp index 30e075a1..5f42bcb6 100644 --- a/code/fgame/actor_machinegunner.cpp +++ b/code/fgame/actor_machinegunner.cpp @@ -157,7 +157,7 @@ void Actor::ThinkHoldGun_TurretGun(void) } } - VectorScale2D(orientation[0], m_fCrouchWeight * -9.3f + 23.4f, offset); + VectorScale2D(orientation[0], -(m_fCrouchWeight * -9.3f + 23.4f), offset); VectorAdd2D(newOrigin, offset, newOrigin); VectorScale2D(orientation[1], m_fCrouchWeight * 2.6f + 10.3f, offset); VectorAdd2D(newOrigin, offset, newOrigin); @@ -167,7 +167,7 @@ void Actor::ThinkHoldGun_TurretGun(void) m_fCrouchWeight = 1.0; } - VectorScale2D(orientation[0], m_fCrouchWeight * -3.f + 23.4f, offset); + VectorScale2D(orientation[0], -(m_fCrouchWeight * -3.f + 23.4f), offset); VectorAdd2D(newOrigin, offset, newOrigin); VectorScale2D(orientation[1], m_fCrouchWeight * -1.6f + 10.3f, offset); VectorAdd2D(newOrigin, offset, newOrigin); @@ -182,6 +182,8 @@ void Actor::ThinkHoldGun_TurretGun(void) UpdateAimMotion(); UpdateAnim(); + newOrigin[2] += 18; + end[0] = newOrigin[0]; end[1] = newOrigin[1]; end[2] = newOrigin[2] - 94; From 81866d96e09405e13b16a6b2911013ecd775b1ca Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:57:28 +0200 Subject: [PATCH 0705/2040] Make flesh impacts properly work --- code/cgame/cg_parsemsg.cpp | 30 ++++++++++++++++++++++++++++-- code/fgame/weaputils.cpp | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/code/cgame/cg_parsemsg.cpp b/code/cgame/cg_parsemsg.cpp index 9d7ebfe6..2455c73c 100644 --- a/code/cgame/cg_parsemsg.cpp +++ b/code/cgame/cg_parsemsg.cpp @@ -987,14 +987,16 @@ void CG_AddBulletImpacts() if (flesh_impact_count) { if (flesh_impact_count > 1) { fImpSndDistRA = 9999.0; + fImpSndDistRB = 9999.0; iImpSndIndexRA = 0; + iImpSndIndexRB = 0; for (i = 0; i < flesh_impact_count; i++) { - VectorSubtract(wall_impact_pos[i], cg.SoundOrg, vTmp); + VectorSubtract(flesh_impact_pos[i], cg.SoundOrg, vTmp); iHeadDist = VectorLength(vTmp); if (DotProduct(vTmp, cg.SoundAxis[1]) > 0.f) { - if (iHeadDist < fImpSndDistRA) { + if (iHeadDist < fImpSndDistRB) { fImpSndDistRA = iHeadDist; iImpSndIndexRA = i; } @@ -1003,6 +1005,30 @@ void CG_AddBulletImpacts() iImpSndIndexRA = i; } } + + if (fImpSndDistRA < 9999) { + sfxManager.MakeEffect_Normal( + flesh_impact_large[iImpSndIndexRA] ? SFX_BHIT_HUMAN_UNIFORM_HARD : SFX_BHIT_HUMAN_UNIFORM_LITE, + flesh_impact_pos[iImpSndIndexRA], + flesh_impact_norm[iImpSndIndexRA] + ); + } + + if (fImpSndDistRB < 9999) { + sfxManager.MakeEffect_Normal( + flesh_impact_large[iImpSndIndexRB] ? SFX_BHIT_HUMAN_UNIFORM_HARD : SFX_BHIT_HUMAN_UNIFORM_LITE, + flesh_impact_pos[iImpSndIndexRB], + flesh_impact_norm[iImpSndIndexRB] + ); + } + } else { + for (i = 0; i < flesh_impact_count; i++) { + sfxManager.MakeEffect_Normal( + flesh_impact_large[i] ? SFX_BHIT_HUMAN_UNIFORM_HARD : SFX_BHIT_HUMAN_UNIFORM_LITE, + flesh_impact_pos[i], + flesh_impact_norm[i] + ); + } } flesh_impact_count = 0; diff --git a/code/fgame/weaputils.cpp b/code/fgame/weaputils.cpp index 640104e5..51d52891 100644 --- a/code/fgame/weaputils.cpp +++ b/code/fgame/weaputils.cpp @@ -2321,7 +2321,7 @@ float BulletAttack( gi.MSG_WriteDir(trace.plane.normal); gi.MSG_WriteBits(bulletlarge, bulletbits); gi.MSG_EndCGM(); - } else if (trace.location >= 0 && ent->IsSubclassOfPlayer()) { + } else if (trace.location >= 0 && ent->IsSubclassOfSentient()) { gi.SetBroadcastVisible(vTmpEnd, NULL); gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_8)); gi.MSG_WriteCoord(vTmpEnd[0]); From 9de71e35295e9baa2a132c1c55e9912f2653c127 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 18:05:44 +0200 Subject: [PATCH 0706/2040] Correctly check if the AI either can see or can shoot to find the enemy The AI would get stuck trying to cover otherwise --- code/fgame/actor_cover.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/fgame/actor_cover.cpp b/code/fgame/actor_cover.cpp index 456f2efc..8350849b 100644 --- a/code/fgame/actor_cover.cpp +++ b/code/fgame/actor_cover.cpp @@ -380,7 +380,7 @@ void Actor::State_Cover_Hide(void) return; } - if (bCanShoot || bCanShoot) { + if (bCanSee || bCanShoot) { m_pCoverNode->Relinquish(); m_pCoverNode->MarkTemporarilyBad(); m_pCoverNode = NULL; From 11f5870a8b519305aa660da1f453478f9899ebd0 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 20:45:05 +0200 Subject: [PATCH 0707/2040] Add ioq3 server fixes and improvement - Add a rate limit to protect against DoS attacks - Better IPv6 support --- code/qcommon/msg.cpp | 12 + code/qcommon/q_shared.h | 2 + code/qcommon/qcommon.h | 9 +- code/server/server.h | 223 ++++++++------- code/server/sv_client.c | 566 ++++++++++++++++++++++++++------------ code/server/sv_init.c | 55 ++-- code/server/sv_main.c | 424 +++++++++++++++++++++------- code/server/sv_net_chan.c | 16 +- code/server/sv_snapshot.c | 74 ++++- code/server/sv_world.c | 12 +- 10 files changed, 966 insertions(+), 427 deletions(-) diff --git a/code/qcommon/msg.cpp b/code/qcommon/msg.cpp index a5f46991..bb04cba3 100644 --- a/code/qcommon/msg.cpp +++ b/code/qcommon/msg.cpp @@ -875,6 +875,18 @@ void MSG_ReadData( msg_t *msg, void *data, int len ) { } } +// a string hasher which gives the same hash value even if the +// string is later modified via the legacy MSG read/write code +int MSG_HashKey(const char *string, int maxlen) { + int register hash, i; + + hash = 0; + for (i = 0; i < maxlen && string[i] != '\0'; i++) { + hash += string[i] * (119 + i); + } + hash = (hash ^ (hash >> 10) ^ (hash >> 20)); + return hash; +} /* ============================================================================= diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 63f6dd31..cb601125 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -79,6 +79,8 @@ extern "C" { #define CLIENT_WINDOW_TITLE PRODUCT_NAME #define CLIENT_WINDOW_MIN_TITLE PRODUCT_NAME + +#define MAX_MASTER_SERVERS 5 // number of supported master servers #define DEMOEXT "dm_" // standard demo extension diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 6baab452..fb7db583 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -87,6 +87,7 @@ void MSG_WriteBigString (msg_t *sb, const char *s); void MSG_WriteScrambledString(msg_t* sb, const char* s); void MSG_WriteScrambledBigString(msg_t* sb, const char* s); void MSG_WriteAngle16 (msg_t *sb, float f); +int MSG_HashKey(const char *string, int maxlen); void MSG_WriteEntityNum(msg_t* sb, short number); void MSG_BeginReading (msg_t *sb); @@ -202,8 +203,8 @@ NET #define MAX_RELIABLE_COMMANDS 512 // max string commands buffered for restransmit typedef enum { - NA_BOT, NA_BAD, // an address lookup failed + NA_BOT, NA_LOOPBACK, NA_BROADCAST, NA_IP, @@ -373,7 +374,11 @@ enum clc_ops_e { clc_move, // [[usercmd_t] clc_moveNoDelta, // [[usercmd_t] clc_clientCommand, // [string] message - clc_EOF + clc_EOF, + +// new commands, supported only by ioquake3 protocol but not legacy + clc_voipSpeex, // not wrapped in USE_VOIP, so this value is reserved. + clc_voipOpus, // }; /* diff --git a/code/server/server.h b/code/server/server.h index 464ecb04..498c15b8 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -21,8 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // server.h -#ifndef __SERVER_H__ -#define __SERVER_H__ +#pragma once #include "../qcommon/q_shared.h" #include "../qcommon/qcommon.h" @@ -43,6 +42,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA extern "C" { #endif +#ifdef USE_VOIP +#define VOIP_QUEUE_LENGTH 64 + +typedef struct voipServerPacket_s +{ + int generation; + int sequence; + int frames; + int len; + int sender; + int flags; + byte data[4000]; +} voipServerPacket_t; +#endif + typedef struct svEntity_s { struct worldSector_s *worldSector; struct svEntity_s *nextEntityInWorldSector; @@ -93,6 +107,10 @@ typedef struct { int gameClientSize; // will be > sizeof(playerState_t) due to game private data } server_t; + + + + typedef struct { int areabytes; byte areabits[MAX_MAP_AREA_BYTES]; // portalarea visibility bits @@ -103,7 +121,7 @@ typedef struct { // order, otherwise the delta compression will fail int messageSent; // time the message was transmitted int messageAcked; // time the message was acked - size_t messageSize; // used to rate drop packets + int messageSize; // used to rate drop packets } clientSnapshot_t; typedef enum { @@ -129,13 +147,13 @@ typedef struct client_s { char userinfo[MAX_INFO_STRING]; // name, etc char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS]; - int reliableSequence; // last added reliable message, not necesarily sent or acknowledged yet + int reliableSequence; // last added reliable message, not necessarily sent or acknowledged yet int reliableAcknowledge; // last acknowledged reliable message - int reliableSent; // last sent reliable message, not necesarily acknowledged yet + int reliableSent; // last sent reliable message, not necessarily acknowledged yet int messageAcknowledge; int gamestateMessageNum; // netchan->outgoingSequence of gamestate - int challenge; + int challenge; int serverIdAcknowledge; usercmd_t lastUsercmd; @@ -151,21 +169,21 @@ typedef struct client_s { // downloading char downloadName[MAX_QPATH]; // if not empty string, we are downloading fileHandle_t download; // file being downloaded - size_t downloadSize; // total bytes (can't use EOF because of paks) - size_t downloadCount; // bytes sent + int downloadSize; // total bytes (can't use EOF because of paks) + int downloadCount; // bytes sent int downloadClientBlock; // last block we sent to the client, awaiting ack int downloadCurrentBlock; // current block number int downloadXmitBlock; // last block we xmited unsigned char *downloadBlocks[MAX_DOWNLOAD_WINDOW]; // the buffers for the download blocks - size_t downloadBlockSize[MAX_DOWNLOAD_WINDOW]; + int downloadBlockSize[MAX_DOWNLOAD_WINDOW]; qboolean downloadEOF; // We have sent the EOF block int downloadSendTime; // time we last got an ack from the client int deltaMessage; // frame last client usercmd message int nextReliableTime; // svs.time when another reliable command will be allowed int lastPacketTime; // svs.time when packet was last received - int lastConnectTime; // svs.time when connection started - int lastSnapshotTime; // svs.time of last sent snapshot + int lastConnectTime; // svs.time when connection started + int lastSnapshotTime; // svs.time of last sent snapshot qboolean rateDelayed; // true if nextSnapshotTime was set based on rate instead of snapshotMsec int timeoutCount; // must timeout a few frames in a row so debugging doesn't break clientSnapshot_t frames[PACKET_BACKUP]; // updates can be delta'd from here @@ -182,8 +200,17 @@ typedef struct client_s { netchan_buffer_t *netchan_start_queue; netchan_buffer_t **netchan_end_queue; +#ifdef USE_VOIP + qboolean hasVoip; + qboolean muteAllVoip; + qboolean ignoreVoipFromClient[MAX_CLIENTS]; + voipServerPacket_t *voipPacket[VOIP_QUEUE_LENGTH]; + int queuedVoipPackets; + int queuedVoipIndex; +#endif + int oldServerTime; - qboolean csUpdated[MAX_CONFIGSTRINGS+1]; + qboolean csUpdated[MAX_CONFIGSTRINGS]; server_sound_t server_sounds[ MAX_SERVER_SOUNDS ]; int number_of_server_sounds; @@ -198,7 +225,7 @@ typedef struct client_s { int lastVisCheckTime[MAX_CLIENTS]; #ifdef LEGACY_PROTOCOL - qboolean compat; + qboolean compat; #endif } client_t; @@ -208,7 +235,11 @@ typedef struct client_s { // MAX_CHALLENGES is made large to prevent a denial // of service attack that could cycle all of them // out before legitimate users connected -#define MAX_CHALLENGES 1024 +#define MAX_CHALLENGES 2048 +// Allow a certain amount of challenges to have the same IP address +// to make it a bit harder to DOS one single IP address from connecting +// while not allowing a single ip to grab all challenge resources +#define MAX_CHALLENGES_MULTI (MAX_CHALLENGES / 2) #define AUTHORIZE_TIMEOUT 5000 @@ -227,47 +258,52 @@ typedef enum { typedef struct { netadr_t adr; - int challenge; - int clientChallenge; // challenge number coming from the client - int time; // time the last packet was sent to the autherize server - int pingTime; // time the challenge response was sent to client - int firstTime; // time the adr was first used, for authorize timeout checks - qboolean wasrefused; - qboolean connected; + int challenge; + int clientChallenge; // challenge number coming from the client + int time; // time the last packet was sent to the autherize server + int pingTime; // time the challenge response was sent to client + int firstTime; // time the adr was first used, for authorize timeout checks + qboolean wasrefused; + qboolean connected; + + // + // gamespy stuff + // unsigned int gamespyId; char gsChallenge[12]; cdKeyState_e cdkeyState; } challenge_t; - -#define MAX_MASTERS 8 // max recipients for heartbeat packets - // this structure will be cleared only when the game dll changes typedef struct { - qboolean initialized; // sv_init has completed + qboolean initialized; // sv_init has completed - int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer() + int time; // will be strictly increasing across level changes - int time; // will be strictly increasing across level changes - int startTime; - int lastTime; - int serverLagTime; - qboolean autosave; - int mapTime; + int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer() - client_t *clients; // [sv_maxclients->integer]; - int iNumClients; - int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_PACKET_ENTITIES - int nextSnapshotEntities; // next snapshotEntities to use + int startTime; + int lastTime; + int serverLagTime; + qboolean autosave; + int mapTime; + + client_t *clients; // [sv_maxclients->integer]; + int iNumClients; + int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_SNAPSHOT_ENTITIES + int nextSnapshotEntities; // next snapshotEntities to use entityState_t *snapshotEntities; // [numSnapshotEntities] - int nextHeartbeatTime; - challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting - netadr_t redirectAddress; // for rcon return messages - netadr_t authorizeAddress; // for rcon return messages + int nextHeartbeatTime; + challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting + netadr_t redirectAddress; // for rcon return messages +#ifndef STANDALONE + netadr_t authorizeAddress; // authorize server address +#endif char gameName[ MAX_QPATH ]; char mapName[ MAX_QPATH ]; char rawServerName[ MAX_QPATH ]; int areabits_warning_time; + qboolean soundsNeedLoad; char tm_filename[ MAX_QPATH ]; int tm_loopcount; @@ -291,53 +327,51 @@ typedef struct //============================================================================= -extern cvar_t *sv_mapname; -extern serverStatic_t svs; // persistant server info across maps -extern server_t sv; // cleared each map -extern game_export_t *ge; // game exports +extern serverStatic_t svs; // persistant server info across maps +extern server_t sv; // cleared each map +extern game_export_t *ge; // game exports -#define MAX_MASTER_SERVERS 5 +extern cvar_t *sv_fps; +extern cvar_t *sv_timeout; +extern cvar_t *sv_zombietime; +extern cvar_t *sv_rconPassword; +extern cvar_t *sv_privatePassword; +extern cvar_t *sv_allowDownload; +extern cvar_t *sv_maxclients; -extern cvar_t *sv_fps; -extern cvar_t *sv_timeout; -extern cvar_t *sv_zombietime; -extern cvar_t *sv_rconPassword; -extern cvar_t *sv_privatePassword; -extern cvar_t *sv_allowDownload; -extern cvar_t *sv_maxclients; - -extern cvar_t *sv_privateClients; -extern cvar_t *sv_hostname; -extern cvar_t *sv_master[ MAX_MASTER_SERVERS ]; -extern cvar_t *sv_reconnectlimit; -extern cvar_t *sv_showloss; -extern cvar_t *sv_padPackets; -extern cvar_t *sv_killserver; -extern cvar_t *sv_mapChecksum; -extern cvar_t *sv_serverid; -extern cvar_t *sv_minRate; -extern cvar_t *sv_maxRate; -extern cvar_t *sv_dlRate; -extern cvar_t *sv_minPing; -extern cvar_t *sv_maxPing; -extern cvar_t *sv_pure; -extern cvar_t *sv_floodProtect; -extern cvar_t *sv_maplist; -extern cvar_t *sv_drawentities; -extern cvar_t *sv_deeptracedebug; -extern cvar_t *sv_netprofile; -extern cvar_t *sv_netprofileoverlay; -extern cvar_t *sv_netoptimize; -extern cvar_t *sv_netoptimize_vistime; -extern cvar_t *g_netoptimize; -extern cvar_t *g_gametype; -extern cvar_t *g_gametypestring; -extern cvar_t *sv_chatter; -extern cvar_t *sv_gamename; -extern cvar_t *sv_location; -extern cvar_t *sv_debug_gamespy; -extern cvar_t *sv_gamespy; -extern cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491) +extern cvar_t *sv_privateClients; +extern cvar_t *sv_hostname; +extern cvar_t *sv_master[MAX_MASTER_SERVERS]; +extern cvar_t *sv_reconnectlimit; +extern cvar_t *sv_showloss; +extern cvar_t *sv_padPackets; +extern cvar_t *sv_killserver; +extern cvar_t *sv_mapname; +extern cvar_t *sv_mapChecksum; +extern cvar_t *sv_serverid; +extern cvar_t *sv_minRate; +extern cvar_t *sv_maxRate; +extern cvar_t *sv_dlRate; +extern cvar_t *sv_minPing; +extern cvar_t *sv_maxPing; +extern cvar_t *g_gametype; +extern cvar_t *g_gametypestring; +extern cvar_t *sv_pure; +extern cvar_t *sv_floodProtect; +extern cvar_t *sv_lanForceRate; +extern cvar_t *sv_maplist; +extern cvar_t *sv_drawentities; +extern cvar_t *sv_deeptracedebug; +extern cvar_t *sv_netprofile; +extern cvar_t *sv_netprofileoverlay; +extern cvar_t *sv_netoptimize; +extern cvar_t *sv_netoptimize_vistime; +extern cvar_t *g_netoptimize; +extern cvar_t *sv_chatter; +extern cvar_t *sv_gamename; +extern cvar_t *sv_location; +extern cvar_t *sv_debug_gamespy; +extern cvar_t *sv_gamespy; #ifndef STANDALONE extern cvar_t *sv_strictAuth; #endif @@ -351,6 +385,7 @@ extern cvar_t *sv_voip; extern cvar_t *sv_voipProtocol; #endif + //=========================================================== // @@ -378,8 +413,8 @@ extern leakyBucket_t outboundLeakyBucket; qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ); qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ); -void SV_FinalMessage( const char *message ); -void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ...); +void SV_FinalMessage (const char *message); +void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); void SV_AddOperatorCommands (void); @@ -444,8 +479,8 @@ void SV_SpawnServer( const char *server, qboolean loadgame, qboolean restart, qb // // sv_client.c // -challenge_t* FindChallenge(netadr_t from, qboolean connecting); -void SV_GetChallenge( netadr_t from ); +challenge_t* FindChallenge(netadr_t from, qboolean connecting); +void SV_GetChallenge(netadr_t from); void SV_DirectConnect( netadr_t from ); @@ -455,15 +490,17 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ); void SV_UserinfoChanged( client_t *cl ); void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ); +void SV_FreeClient(client_t *client); void SV_DropClient( client_t *drop, const char *reason ); void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ); -void SV_ClientThink( client_t *cl, usercmd_t *cmd ); +void SV_ClientThink (client_t *cl, usercmd_t *cmd); -int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ); +int SV_WriteDownloadToClient(client_t *cl , msg_t *msg); int SV_SendDownloadMessages(void); int SV_SendQueuedMessages(void); + // // sv_ccmds.c // @@ -524,7 +561,7 @@ void SV_UnlinkEntity( gentity_t *ent ); void SV_LinkEntity( gentity_t *ent ); // Needs to be called any time an entity changes origin, mins, maxs, // or solid. Automatically unlinks if needed. -// sets ent->v.absmin and ent->v.absmax +// sets ent->r.absmin and ent->r.absmax // sets ent->leafnums[] for pvs determination even if the entity // is not solid @@ -585,5 +622,3 @@ void SV_ShutdownGamespy(); #ifdef __cplusplus } #endif - -#endif // __SERVER_H__ diff --git a/code/server/sv_client.c b/code/server/sv_client.c index a2868930..1e4b4646 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -46,10 +46,19 @@ to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. + +ioquake3: we added a possibility for clients to add a challenge +to their packets, to make it more difficult for malicious servers +to hi-jack client connections. +Also, the auth stuff is completely disabled for com_standalone games +as well as IPv6 connections, since there is no way to use the +v4-only auth server for these new types of connections. ================= */ -void SV_GetChallenge( netadr_t from ) { +void SV_GetChallenge(netadr_t from) +{ challenge_t *challenge; + qboolean wasfound = qfalse; // ignore if we are in single player // Removed in OPM @@ -58,9 +67,23 @@ void SV_GetChallenge( netadr_t from ) { // return; //} - challenge = FindChallenge(from, qtrue); + // Prevent using getchallenge as an amplifier + if ( SVC_RateLimitAddress( from, 10, 1000 ) ) { + Com_DPrintf( "SV_GetChallenge: rate limit from %s exceeded, dropping request\n", + NET_AdrToString( from ) ); + return; + } - // if they are on a lan address, send the challengeResponse immediately + // Allow getchallenge to be DoSed relatively easily, but prevent + // excess outbound bandwidth usage when being flooded inbound + if ( SVC_RateLimit( &outboundLeakyBucket, 10, 100 ) ) { + Com_DPrintf( "SV_GetChallenge: rate limit exceeded, dropping request\n" ); + return; + } + + challenge = FindChallenge(from, qtrue); + + // if they are on a lan address, send the challengeResponse immediately // we send the challengeResponse immediately as there is no AUTH server for us // it's also way more cool this way :) @@ -89,8 +112,10 @@ void SV_GetChallenge( netadr_t from ) { // check client's cd key NET_OutOfBandPrint(NS_SERVER, from, "getKey %s", challenge->gsChallenge); + challenge->pingTime = svs.time; } +#ifndef STANDALONE /* ==================== SV_AuthorizeIpPacket @@ -98,8 +123,6 @@ SV_AuthorizeIpPacket A packet has been returned from the authorize server. If we have a challenge adr for that ip, send the challengeResponse to it - -NOTE: This function is deprecated, SV_GamespyAuthorize must be used instead. ==================== */ void SV_AuthorizeIpPacket( netadr_t from ) { @@ -107,6 +130,7 @@ void SV_AuthorizeIpPacket( netadr_t from ) { int i; char *s; char *r; + challenge_t *challengeptr; if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) { Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" ); @@ -124,45 +148,48 @@ void SV_AuthorizeIpPacket( netadr_t from ) { Com_Printf( "SV_AuthorizeIpPacket: challenge not found\n" ); return; } + + challengeptr = &svs.challenges[i]; // send a packet back to the original client - svs.challenges[i].pingTime = svs.time; + challengeptr->pingTime = svs.time; s = Cmd_Argv( 2 ); r = Cmd_Argv( 3 ); // reason if ( !Q_stricmp( s, "demo" ) ) { // they are a demo client trying to connect to a real server - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nServer is not a demo server\n" ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nServer is not a demo server\n" ); // clear the challenge record so it won't timeout and let them through - Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + Com_Memset( challengeptr, 0, sizeof( *challengeptr ) ); return; } if ( !Q_stricmp( s, "accept" ) ) { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, - "challengeResponse %i", svs.challenges[i].challenge ); + NET_OutOfBandPrint(NS_SERVER, challengeptr->adr, + "challengeResponse %d %d %d", challengeptr->challenge, challengeptr->clientChallenge, com_protocol->integer); return; } if ( !Q_stricmp( s, "unknown" ) ) { if (!r) { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nAwaiting CD key authorization\n" ); } else { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\n%s\n", r); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r); } // clear the challenge record so it won't timeout and let them through - Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + Com_Memset( challengeptr, 0, sizeof( *challengeptr ) ); return; } // authorization failed if (!r) { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nSomeone is using this CD Key\n" ); } else { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\n%s\n", r ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r ); } // clear the challenge record so it won't timeout and let them through - Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + Com_Memset( challengeptr, 0, sizeof(*challengeptr) ); } +#endif /* ================== @@ -265,16 +292,11 @@ A "connect" OOB command has been received ================== */ -#define PB_MESSAGE "PunkBuster Anti-Cheat software must be installed " \ - "and Enabled in order to join this server. An updated game patch can be downloaded from " \ - "www.idsoftware.com" - void SV_DirectConnect( netadr_t from ) { char userinfo[MAX_INFO_STRING]; int i; client_t *cl, *newcl; - // Make this a temp variable to avoid stack overflow issues - static client_t temp; + static client_t temp; // static variable, otherwise it causes a stack overflow gentity_t *ent; int clientNum; int version; @@ -290,7 +312,7 @@ void SV_DirectConnect( netadr_t from ) { #endif challenge_t* ch; - Com_DPrintf( "SVC_DirectConnect ()\n" ); + Com_DPrintf ("SVC_DirectConnect ()\n"); // Check whether this client is banned. if(SV_IsBanned(&from, qfalse)) @@ -299,9 +321,10 @@ void SV_DirectConnect( netadr_t from ) { return; } - Q_strncpyz( userinfo, Cmd_Argv( 1 ), sizeof( userinfo ) ); + Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) ); - version = atoi( Info_ValueForKey( userinfo, "protocol" ) ); + version = atoi(Info_ValueForKey(userinfo, "protocol")); + #ifdef LEGACY_PROTOCOL if(version > 0 && com_legacyprotocol->integer == version) compat = qtrue; @@ -351,42 +374,54 @@ void SV_DirectConnect( netadr_t from ) { Info_SetValueForKey( userinfo, "ip", ip ); // see if the challenge is valid (LAN clients don't need to challenge) - if ( !NET_IsLocalAddress (from) ) { - int ping; + if (!NET_IsLocalAddress(from)) + { + int ping; + challenge_t *challengeptr; - for (i=0 ; iwasrefused) + { + // Return silently, so that error messages written by the server keep being displayed. return; } - ping = svs.time - svs.challenges[i].pingTime; - Com_Printf( "Client %i connecting with %i challenge ping\n", i, ping ); - svs.challenges[i].connected = qtrue; + ping = svs.time - challengeptr->pingTime; // never reject a LAN client based on ping if ( !Sys_IsLANAddress( from ) ) { if ( sv_minPing->value && ping < sv_minPing->value ) { - // don't let them keep trying until they get a big delay - NET_OutOfBandPrint( NS_SERVER, from, "droperror\nServer is for high pings only\n" ); + NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" ); Com_DPrintf ("Client %i rejected on a too low ping\n", i); - // reset the address otherwise their ping will keep increasing - // with each connect message and they'd eventually be able to connect - svs.challenges[i].adr.port = 0; + challengeptr->wasrefused = qtrue; return; } if ( sv_maxPing->value && ping > sv_maxPing->value ) { - NET_OutOfBandPrint( NS_SERVER, from, "droperror\nServer is for low pings only\n" ); + NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" ); Com_DPrintf ("Client %i rejected on a too high ping\n", i); + challengeptr->wasrefused = qtrue; return; } } + + Com_Printf("Client %i connecting with %i challenge ping\n", i, ping); + challengeptr->connected = qtrue; } newcl = &temp; @@ -425,7 +460,7 @@ void SV_DirectConnect( netadr_t from ) { // check for privateClient password password = Info_ValueForKey( userinfo, "password" ); - if ( !strcmp( password, sv_privatePassword->string ) ) { + if ( *password && !strcmp( password, sv_privatePassword->string ) ) { startIndex = 0; } else { // skip past the reserved slots @@ -499,10 +534,9 @@ gotnewcl: // get the game a chance to reject this connection or modify the userinfo denied = ge->ClientConnect( clientNum, qtrue, qfalse ); - if ( denied ) { NET_OutOfBandPrint( NS_SERVER, from, "droperror\n%s\n", denied ); - Com_DPrintf( "Game rejected a connection: %s.\n", denied ); + Com_DPrintf ( "Game rejected a connection: %s.\n", denied ); return; } @@ -514,7 +548,7 @@ gotnewcl: SV_UserinfoChanged( newcl ); // send the connect packet to the client - NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" ); + NET_OutOfBandPrint(NS_SERVER, from, "connectResponse %d", challenge); Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name ); @@ -554,23 +588,23 @@ SV_FreeClient Destructor for data allocated in a client structure ===================== */ -void SV_FreeClient(client_t* client) +void SV_FreeClient(client_t *client) { #ifdef USE_VOIP - int index; - - for (index = client->queuedVoipIndex; index < client->queuedVoipPackets; index++) - { - index %= ARRAY_LEN(client->voipPacket); - - Z_Free(client->voipPacket[index]); - } - - client->queuedVoipPackets = 0; + int index; + + for(index = client->queuedVoipIndex; index < client->queuedVoipPackets; index++) + { + index %= ARRAY_LEN(client->voipPacket); + + Z_Free(client->voipPacket[index]); + } + + client->queuedVoipPackets = 0; #endif - SV_Netchan_FreeQueue(client); - SV_CloseDownload(client); + SV_Netchan_FreeQueue(client); + SV_CloseDownload(client); } /* @@ -585,35 +619,32 @@ or crashing -- SV_FinalMessage() will handle that void SV_DropClient( client_t *drop, const char *reason ) { int i; challenge_t *challenge; + const qboolean isBot = drop->netchan.remoteAddress.type == NA_BOT; if ( drop->state == CS_ZOMBIE ) { return; // already dropped } - if (drop->netchan.remoteAddress.type != NA_BOT) { + if ( !isBot ) { // see if we already have a challenge for this ip challenge = &svs.challenges[0]; - for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { - if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { - challenge->connected = qfalse; + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) + { + if(NET_CompareAdr(drop->netchan.remoteAddress, challenge->adr)) + { + Com_Memset(challenge, 0, sizeof(*challenge)); break; } } - } + } - // Free all allocated data on the client structure - SV_FreeClient(drop); + // Free all allocated data on the client structure + SV_FreeClient(drop); // tell everyone why they got dropped SV_SendServerCommand( NULL, "print \"%s %s\n\"", drop->name, reason ); - - if (drop->download) { - FS_FCloseFile( drop->download ); - drop->download = 0; - } - // call the prog function for removing a client // this will remove the body, among other things ge->ClientDisconnect( ( gentity_t * )SV_GentityNum( drop - svs.clients ) ); @@ -621,11 +652,18 @@ void SV_DropClient( client_t *drop, const char *reason ) { // add the disconnect command SV_SendServerCommand( drop, "disconnect \"%s\"", reason); + if ( isBot ) { + //SV_BotFreeClient( drop - svs.clients ); + + // bots shouldn't go zombie, as there's no real net connection. + drop->state = CS_FREE; + } else { + Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); + drop->state = CS_ZOMBIE; // become free in a few seconds + } + // nuke user info SV_SetUserinfo( drop - svs.clients, "" ); - - Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); - drop->state = CS_ZOMBIE; // become free in a few seconds // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty @@ -652,7 +690,7 @@ It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ -void SV_SendClientGameState( client_t *client ) { +static void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; @@ -690,7 +728,7 @@ void SV_SendClientGameState( client_t *client ) { SV_UpdateServerCommandsToClient( client, &msg ); // send the gamestate - MSG_WriteSVC( &msg, svc_gamestate ); + MSG_WriteSVC( &msg, svc_gamestate ); MSG_WriteLong( &msg, client->reliableSequence ); // write the configstrings @@ -719,7 +757,7 @@ void SV_SendClientGameState( client_t *client ) { MSG_WriteLong( &msg, client - svs.clients); // write the checksum feed - MSG_WriteLong( &msg, 0); + MSG_WriteLong( &msg, sv.checksumFeed); // write the server frametime to the client (only on TA/TT) MSG_WriteServerFrameTime(&msg, sv.frameTime); @@ -754,7 +792,7 @@ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { client->deltaMessage = -1; client->lastSnapshotTime = 0; // generate a snapshot immediately - if (cmd) + if(cmd) memcpy(&client->lastUsercmd, cmd, sizeof(client->lastUsercmd)); else memset(&client->lastUsercmd, '\0', sizeof(client->lastUsercmd)); @@ -798,7 +836,7 @@ static void SV_CloseDownload( client_t *cl ) { // Free the temporary buffer space for (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) { if (cl->downloadBlocks[i]) { - Z_Free( cl->downloadBlocks[i] ); + Z_Free(cl->downloadBlocks[i]); cl->downloadBlocks[i] = NULL; } } @@ -812,7 +850,7 @@ SV_StopDownload_f Abort a download if in progress ================== */ -void SV_StopDownload_f( client_t *cl ) { +static void SV_StopDownload_f( client_t *cl ) { if (*cl->downloadName) Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", (int) (cl - svs.clients), cl->downloadName ); @@ -826,7 +864,10 @@ SV_DoneDownload_f Downloads are finished ================== */ -void SV_DoneDownload_f( client_t *cl ) { +static void SV_DoneDownload_f( client_t *cl ) { + if ( cl->state == CS_ACTIVE ) + return; + Com_DPrintf( "clientDownload: %s Done\n", cl->name); // resend the game state to update any clients that entered during the download SV_SendClientGameState(cl); @@ -840,7 +881,7 @@ The argument will be the last acknowledged block from the client, it should be the same as cl->downloadClientBlock ================== */ -void SV_NextDownload_f( client_t *cl ) +static void SV_NextDownload_f( client_t *cl ) { int block = atoi( Cmd_Argv(1) ); @@ -869,7 +910,7 @@ void SV_NextDownload_f( client_t *cl ) SV_BeginDownload_f ================== */ -void SV_BeginDownload_f( client_t *cl ) { +static void SV_BeginDownload_f( client_t *cl ) { // Kill any existing download SV_CloseDownload( cl ); @@ -884,15 +925,13 @@ void SV_BeginDownload_f( client_t *cl ) { SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client -Fill up msg with data +Fill up msg with data, return number of download blocks added ================== */ -int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) +int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) { int curindex; - int rate; - int blockspersnap; - int idPack = 0, missionPack = 0, unreferenced = 1; + int unreferenced = 1; char errorMessage[1024]; char pakbuf[MAX_QPATH], *pakptr; int numRefPaks; @@ -900,10 +939,16 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) if (!*cl->downloadName) return 0; // Nothing being downloaded - if (!cl->download) { + if(!cl->download) + { + qboolean idPack = qfalse; + #ifndef STANDALONE + qboolean missionPack = qfalse; + #endif + // Chop off filename extension. Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName); - pakptr = Q_strrchr(pakbuf, '.'); + pakptr = strrchr(pakbuf, '.'); if(pakptr) { @@ -927,8 +972,11 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) // now that we know the file is referenced, // check whether it's legal to download it. - missionPack = FS_idPak(pakbuf, "missionpack"); - idPack = missionPack || FS_idPak(pakbuf, BASEGAME); +#ifndef STANDALONE + //missionPack = FS_idPak(pakbuf, BASETA, NUM_TA_PAKS); + //idPack = missionPack; +#endif + //idPack = idPack || FS_idPak(pakbuf, BASEGAME, NUM_ID_PAKS); break; } @@ -936,11 +984,13 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) } } + cl->download = 0; + // We open the file here if ( !(sv_allowDownload->integer & DLF_ENABLE) || (sv_allowDownload->integer & DLF_NO_UDP) || idPack || unreferenced || - ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) { + ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { // cannot auto-download file if(unreferenced) { @@ -949,18 +999,22 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) } else if (idPack) { Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", (int) (cl - svs.clients), cl->downloadName); - if (missionPack) { +#ifndef STANDALONE + if(missionPack) + { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n" "The Team Arena mission pack can be found in your local game store.", cl->downloadName); } - else { + else +#endif + { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); } } else if ( !(sv_allowDownload->integer & DLF_ENABLE) || (sv_allowDownload->integer & DLF_NO_UDP) ) { - Com_Printf("clientDownload: %d : \"%s\" download disabled", (int) (cl - svs.clients), cl->downloadName); + Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName); if (sv_pure->integer) { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "You will need to get this file elsewhere before you " @@ -983,6 +1037,10 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) MSG_WriteString( msg, errorMessage ); *cl->downloadName = 0; + + if(cl->download) + FS_FCloseFile(cl->download); + return 1; } @@ -1001,7 +1059,7 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); if (!cl->downloadBlocks[curindex]) - cl->downloadBlocks[curindex] = Z_Malloc( MAX_DOWNLOAD_BLKSIZE ); + cl->downloadBlocks[curindex] = Z_Malloc(MAX_DOWNLOAD_BLKSIZE); cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); @@ -1028,75 +1086,42 @@ int SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) cl->downloadEOF = qtrue; // We have added the EOF block } - // Loop up to window size times based on how many blocks we can fit in the - // client snapMsec and rate + if (cl->downloadClientBlock == cl->downloadCurrentBlock) + return 0; // Nothing to transmit - // based on the rate, how many bytes can we fit in the snapMsec time of the client - // normal rate / snapshotMsec calculation - rate = cl->rate; - if ( sv_maxRate->integer ) { - if ( sv_maxRate->integer < 1000 ) { - Cvar_Set( "sv_MaxRate", "1000" ); - } - if ( sv_maxRate->integer < rate ) { - rate = sv_maxRate->integer; - } + // Write out the next section of the file, if we have already reached our window, + // automatically start retransmitting + if (cl->downloadXmitBlock == cl->downloadCurrentBlock) + { + // We have transmitted the complete window, should we start resending? + if (svs.time - cl->downloadSendTime > 1000) + cl->downloadXmitBlock = cl->downloadClientBlock; + else + return 0; } - if (!rate) { - blockspersnap = 1; - } else { - blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) / - MAX_DOWNLOAD_BLKSIZE; - } + // Send current block + curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); - if (blockspersnap < 0) - blockspersnap = 1; + MSG_WriteByte( msg, svc_download ); + MSG_WriteShort( msg, cl->downloadXmitBlock ); - while (blockspersnap--) { + // block zero is special, contains file size + if ( cl->downloadXmitBlock == 0 ) + MSG_WriteLong( msg, cl->downloadSize ); - // Write out the next section of the file, if we have already reached our window, - // automatically start retransmitting + MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); - if (cl->downloadClientBlock == cl->downloadCurrentBlock) - return 0; // Nothing to transmit + // Write the block + if(cl->downloadBlockSize[curindex]) + MSG_WriteData(msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex]); - if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { - // We have transmitted the complete window, should we start resending? + Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock ); - //FIXME: This uses a hardcoded one second timeout for lost blocks - //the timeout should be based on client rate somehow - if (svs.time - cl->downloadSendTime > 1000) - cl->downloadXmitBlock = cl->downloadClientBlock; - else - return 0; - } - - // Send current block - curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); - - MSG_WriteByte( msg, svc_download ); - MSG_WriteShort( msg, cl->downloadXmitBlock ); - - // block zero is special, contains file size - if ( cl->downloadXmitBlock == 0 ) - MSG_WriteLong( msg, (int)cl->downloadSize ); - - MSG_WriteShort( msg, ( short )cl->downloadBlockSize[curindex] ); - - // Write the block - if ( cl->downloadBlockSize[curindex] ) { - MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] ); - } - - Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock ); - - // Move on to the next block - // It will get sent with next snap shot. The rate will keep us in line. - cl->downloadXmitBlock++; - - cl->downloadSendTime = svs.time; - } + // Move on to the next block + // It will get sent with next snap shot. The rate will keep us in line. + cl->downloadXmitBlock++; + cl->downloadSendTime = svs.time; return 1; } @@ -1375,7 +1400,7 @@ void SV_UserinfoChanged( client_t *cl ) { char *val; char *ip; int i; - size_t len; + int len; // name for C code Q_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name) ); @@ -1472,17 +1497,49 @@ SV_UpdateUserinfo_f ================== */ static void SV_UpdateUserinfo_f( client_t *cl ) { - Q_strncpyz( cl->userinfo, Cmd_Argv( 1 ), sizeof( cl->userinfo ) ); + Q_strncpyz( cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo) ); SV_UserinfoChanged( cl ); - // call prog code to allow overrides ge->ClientUserinfoChanged( ( gentity_t * )SV_GentityNum( cl - svs.clients ), cl->userinfo ); } + +#ifdef USE_VOIP +static +void SV_UpdateVoipIgnore(client_t *cl, const char *idstr, qboolean ignore) +{ + if ((*idstr >= '0') && (*idstr <= '9')) { + const int id = atoi(idstr); + if ((id >= 0) && (id < MAX_CLIENTS)) { + cl->ignoreVoipFromClient[id] = ignore; + } + } +} + +/* +================== +SV_Voip_f +================== +*/ +static void SV_Voip_f( client_t *cl ) { + const char *cmd = Cmd_Argv(1); + if (strcmp(cmd, "ignore") == 0) { + SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qtrue); + } else if (strcmp(cmd, "unignore") == 0) { + SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qfalse); + } else if (strcmp(cmd, "muteall") == 0) { + cl->muteAllVoip = qtrue; + } else if (strcmp(cmd, "unmuteall") == 0) { + cl->muteAllVoip = qfalse; + } +} +#endif + + typedef struct { char *name; - void ( *func )( client_t *cl ); + void (*func)( client_t *cl ); } ucmd_t; static ucmd_t ucmds[] = { @@ -1495,6 +1552,10 @@ static ucmd_t ucmds[] = { {"stopdl", SV_StopDownload_f}, {"donedl", SV_DoneDownload_f}, +#ifdef USE_VOIP + {"voip", SV_Voip_f}, +#endif + {NULL, NULL} }; @@ -1533,7 +1594,8 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) { if (clientOK) { // pass unknown strings to the game - if (!u->name && sv.state == SS_GAME) { + if (!u->name && sv.state == SS_GAME && (cl->state == CS_ACTIVE || cl->state == CS_PRIMED)) { + Cmd_Args_Sanitize(); ge->ClientCommand( ( gentity_t * )SV_GentityNum( cl - svs.clients ) ); if (ge->errorMessage) @@ -1566,6 +1628,7 @@ static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) { } if( developer->integer == 2 ) { + // don't spam the console with client commands in production Com_DPrintf( "clientCommand: %s : %i : %s\n", cl->name, seq, s ); } @@ -1582,9 +1645,10 @@ static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) { // the command, we will stop processing the rest of the packet, // including the usercmd. This causes flooders to lag themselves // but not other people - // We don't do this when the client hasn't been active yet since its + // We don't do this when the client hasn't been active yet since it's // normal to spam a lot of commands when downloading - if ( cl->state >= CS_ACTIVE && + if ( !com_cl_running->integer && + cl->state >= CS_ACTIVE && sv_floodProtect->integer && svs.time < cl->nextReliableTime ) { // ignore any other text messages from this client but let them keep playing @@ -1609,8 +1673,7 @@ static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) { // Actual execution of the command SV_ExecuteClientCommand( cl, s, clientOk ); - // continue procesing - return qtrue; + return qtrue; // continue procesing } @@ -1624,8 +1687,7 @@ SV_ClientThink Also called by bot code ================== */ -void SV_ClientThink( client_t *cl, usercmd_t *cmd ) -{ +void SV_ClientThink (client_t *cl, usercmd_t *cmd) { const char *err; cl->lastUsercmd = *cmd; @@ -1686,7 +1748,7 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) { // also use the message acknowledge key ^= cl->messageAcknowledge; // also use the last acknowledged server command in the key - key ^= Com_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32); + key ^= MSG_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32); MSG_ReadDeltaEyeInfo( msg, &cl->lastEyeinfo, &cl->lastEyeinfo ); @@ -1713,7 +1775,7 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) { SV_SendClientGameState( cl ); } return; - } + } // if this is the first usercmd we have received // this gamestate, put the client into the world @@ -1721,9 +1783,9 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) { SV_ClientEnterWorld( cl, &cmds[0] ); // the moves can be processed normaly } - - // a bad cp command was sent, drop the client - if (g_gametype->integer != GT_SINGLE_PLAYER && sv_pure->integer != 0 && !com_sv_running->integer && cl->pureAuthentic == 0) { + + // a bad cp command was sent, drop the client + if (sv_pure->integer != 0 && cl->pureAuthentic == 0) { SV_DropClient( cl, "Cannot validate pure client!"); return; } @@ -1750,12 +1812,122 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) { if ( cmds[i].serverTime <= cl->lastUsercmd.serverTime ) { continue; } - - SV_ClientThink( cl, &cmds[ i ] ); + SV_ClientThink (cl, &cmds[ i ]); } } +#ifdef USE_VOIP +/* +================== +SV_ShouldIgnoreVoipSender + +Blocking of voip packets based on source client +================== +*/ + +static qboolean SV_ShouldIgnoreVoipSender(const client_t *cl) +{ + if (!sv_voip->integer) + return qtrue; // VoIP disabled on this server. + else if (!cl->hasVoip) // client doesn't have VoIP support?! + return qtrue; + + // !!! FIXME: implement player blacklist. + + return qfalse; // don't ignore. +} + +static +void SV_UserVoip(client_t *cl, msg_t *msg, qboolean ignoreData) +{ + int sender, generation, sequence, frames, packetsize; + uint8_t recips[(MAX_CLIENTS + 7) / 8]; + int flags; + byte encoded[sizeof(cl->voipPacket[0]->data)]; + client_t *client = NULL; + voipServerPacket_t *packet = NULL; + int i; + + sender = cl - svs.clients; + generation = MSG_ReadByte(msg); + sequence = MSG_ReadLong(msg); + frames = MSG_ReadByte(msg); + MSG_ReadData(msg, recips, sizeof(recips)); + flags = MSG_ReadByte(msg); + packetsize = MSG_ReadShort(msg); + + if (msg->readcount > msg->cursize) + return; // short/invalid packet, bail. + + if (packetsize > sizeof (encoded)) { // overlarge packet? + int bytesleft = packetsize; + while (bytesleft) { + int br = bytesleft; + if (br > sizeof (encoded)) + br = sizeof (encoded); + MSG_ReadData(msg, encoded, br); + bytesleft -= br; + } + return; // overlarge packet, bail. + } + + MSG_ReadData(msg, encoded, packetsize); + + if (ignoreData || SV_ShouldIgnoreVoipSender(cl)) + return; // Blacklisted, disabled, etc. + + // !!! FIXME: see if we read past end of msg... + + // !!! FIXME: reject if not opus data. + // !!! FIXME: decide if this is bogus data? + + // decide who needs this VoIP packet sent to them... + for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) { + if (client->state != CS_ACTIVE) + continue; // not in the game yet, don't send to this guy. + else if (i == sender) + continue; // don't send voice packet back to original author. + else if (!client->hasVoip) + continue; // no VoIP support, or unsupported protocol + else if (client->muteAllVoip) + continue; // client is ignoring everyone. + else if (client->ignoreVoipFromClient[sender]) + continue; // client is ignoring this talker. + else if (*cl->downloadName) // !!! FIXME: possible to DoS? + continue; // no VoIP allowed if downloading, to save bandwidth. + + if(Com_IsVoipTarget(recips, sizeof(recips), i)) + flags |= VOIP_DIRECT; + else + flags &= ~VOIP_DIRECT; + + if (!(flags & (VOIP_SPATIAL | VOIP_DIRECT))) + continue; // not addressed to this player. + + // Transmit this packet to the client. + if (client->queuedVoipPackets >= ARRAY_LEN(client->voipPacket)) { + Com_Printf("Too many VoIP packets queued for client #%d\n", i); + continue; // no room for another packet right now. + } + + packet = Z_Malloc(sizeof(*packet)); + packet->sender = sender; + packet->frames = frames; + packet->len = packetsize; + packet->generation = generation; + packet->sequence = sequence; + packet->flags = flags; + memcpy(packet->data, encoded, packetsize); + + client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet; + client->queuedVoipPackets++; + } +} +#endif + + + /* =========================================================================== @@ -1777,7 +1949,7 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { MSG_Bitstream(msg); - serverId = MSG_ReadLong(msg); + serverId = MSG_ReadLong( msg ); cl->serverIdAcknowledge = serverId; cl->messageAcknowledge = MSG_ReadLong( msg ); @@ -1795,7 +1967,7 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { // NOTE: when the client message is fux0red the acknowledgement numbers // can be out of range, this could cause the server to send thousands of server // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient - if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) { + if ((cl->reliableSequence - cl->reliableAcknowledge >= MAX_RELIABLE_COMMANDS) || (cl->reliableSequence - cl->reliableAcknowledge < 0)) { // usually only hackers create messages like this // it is more annoying for them to let them hanging #ifndef NDEBUG @@ -1816,24 +1988,36 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { // don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to "" // but we still need to read the next message to move to next download or send gamestate // I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else - if ( serverId != sv.serverId && !*cl->downloadName ) { + if ( serverId != sv.serverId && !*cl->downloadName && !strstr(cl->lastClientCommandString, "nextdl") ) { + if ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { // TTimo - use a comparison here to catch multiple map_restart + // they just haven't caught the map_restart yet + //Com_DPrintf("%s : ignoring pre map_restart / outdated client message\n", cl->name); + return; + } // if we can tell that the client has dropped the last // gamestate we sent them, resend it - // also, don't resend the gamestate if the server just restarted - if ( serverId != sv.restartedServerId && cl->messageAcknowledge > cl->gamestateMessageNum ) { + if ( cl->state != CS_ACTIVE && cl->messageAcknowledge > cl->gamestateMessageNum ) { Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name ); SV_SendClientGameState( cl ); } return; } + // this client has acknowledged the new gamestate so it's + // safe to start sending it the real time again + if( cl->oldServerTime && serverId == sv.serverId ){ + Com_DPrintf( "%s acknowledged gamestate\n", cl->name ); + cl->oldServerTime = 0; + } + // read optional clientCommand strings do { c = MSG_ReadByte( msg ); - //Com_DPrintf( "SV_ExecuteClientMessage: %i\n", c ); + if ( c == clc_EOF ) { break; } + if ( c != clc_clientCommand ) { break; } @@ -1845,6 +2029,22 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { } } while ( 1 ); + // skip legacy speex voip data + if ( c == clc_voipSpeex ) { +#ifdef USE_VOIP + SV_UserVoip( cl, msg, qtrue ); + c = MSG_ReadByte( msg ); +#endif + } + + // read optional voip data + if ( c == clc_voipOpus ) { +#ifdef USE_VOIP + SV_UserVoip( cl, msg, qfalse ); + c = MSG_ReadByte( msg ); +#endif + } + // read the usercmd_t if ( c == clc_move ) { SV_UserMove( cl, msg, qtrue ); diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 145e3548..62c58f58 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -73,12 +73,11 @@ SV_SetConfigstring =============== */ void SV_SetConfigstring (int index, const char *val) { - int i; - size_t len; + int i; client_t *client; if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { - Com_Error( ERR_DROP, "SV_SetConfigstring: bad index %i\n", index ); + Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i\n", index); } if ( !val ) { @@ -98,7 +97,7 @@ void SV_SetConfigstring (int index, const char *val) { // spawning a new server if (sv.state == SS_LOADING2 || sv.state == SS_GAME || sv.restarting ) { - // send the data to all relevent clients + // send the data to all relevant clients for (i = 0, client = svs.clients; i < svs.iNumClients ; i++, client++) { if ( client->state < CS_ACTIVE ) { if ( client->state == CS_PRIMED ) @@ -111,7 +110,6 @@ void SV_SetConfigstring (int index, const char *val) { } - len = strlen( val ); SV_SendConfigstring(client, index); } } @@ -316,7 +314,7 @@ void SV_UpdateConfigstrings(client_t *client) { int index; - for( index = 0; index <= MAX_CONFIGSTRINGS; index++ ) { + for( index = 0; index < MAX_CONFIGSTRINGS; index++ ) { // if the CS hasn't changed since we went to CS_PRIMED, ignore if(!client->csUpdated[index]) continue; @@ -452,6 +450,9 @@ void SV_Startup( void ) { SV_InitGamespy(); Cvar_Set( "sv_running", "1" ); + + // Join the ipv6 multicast group now that a map is running so clients can scan for us on the local network. + NET_JoinMulticast6(); } /* @@ -478,10 +479,10 @@ SV_ChangeMaxClients ================== */ void SV_ChangeMaxClients( void ) { - int oldMaxClients; - int i; + int oldMaxClients; + int i; client_t *oldClients; - int count; + int count; // get the highest client number in use count = 0; @@ -538,6 +539,20 @@ void SV_ClearServer(void) { sv.frameTime = 1.0 / sv_fps->value; } +/* +================ +SV_TouchFile +================ +*/ +static void SV_TouchFile( const char *filename ) { + fileHandle_t f; + + FS_FOpenFileRead( filename, &f, qfalse, qtrue ); + if ( f ) { + FS_FCloseFile( f ); + } +} + /* ================ SV_SpawnServer @@ -980,15 +995,16 @@ SV_Init Only called at main exe startup, not for each game =============== */ -void SV_Init( void ) { +void SV_Init (void) +{ int index; SV_AddOperatorCommands(); // serverinfo vars - Cvar_Get( "dmflags", "0", CVAR_SERVERINFO ); - Cvar_Get( "fraglimit", "20", CVAR_SERVERINFO ); - Cvar_Get( "timelimit", "0", CVAR_SERVERINFO ); + Cvar_Get ("dmflags", "0", CVAR_SERVERINFO); + Cvar_Get ("fraglimit", "20", CVAR_SERVERINFO); + Cvar_Get ("timelimit", "0", CVAR_SERVERINFO); g_gametype = Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH ); g_gametypestring = Cvar_Get( "g_gametypestring", "0", CVAR_SERVERINFO | CVAR_LATCH ); Cvar_Get( "sv_keywords", "", CVAR_SERVERINFO ); @@ -1013,12 +1029,11 @@ void SV_Init( void ) { // sv_pure is disabled by default in mohaa // the problem is because of difference in pak files between languages sv_pure = Cvar_Get ("sv_pure", "0", CVAR_SYSTEMINFO ); - #ifdef USE_VOIP +#ifdef USE_VOIP sv_voip = Cvar_Get("sv_voip", "1", CVAR_LATCH); Cvar_CheckRange(sv_voip, 0, 1, qtrue); sv_voipProtocol = Cvar_Get("sv_voipProtocol", sv_voip->integer ? "opus" : "", CVAR_SYSTEMINFO | CVAR_ROM ); #endif - Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM ); @@ -1129,8 +1144,14 @@ void SV_Shutdown( const char *finalmsg ) { SV_ClearServer(); // free server static data - if ( svs.clients ) { - Z_Free( svs.clients ); + if(svs.clients) + { + int index; + + for(index = 0; index < sv_maxclients->integer; index++) + SV_FreeClient(&svs.clients[index]); + + Z_Free(svs.clients); } Com_Memset( &svs, 0, sizeof( svs ) ); diff --git a/code/server/sv_main.c b/code/server/sv_main.c index a97f9f9b..19944dd9 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -223,7 +223,7 @@ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) ); } - // send the data to all relevent clients + // send the data to all relevant clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { SV_AddServerCommand( client, (char *)message ); } @@ -290,6 +290,167 @@ CONNECTIONLESS COMMANDS ============================================================================== */ +// This is deliberately quite large to make it more of an effort to DoS +#define MAX_BUCKETS 16384 +#define MAX_HASHES 1024 + +static leakyBucket_t buckets[ MAX_BUCKETS ]; +static leakyBucket_t *bucketHashes[ MAX_HASHES ]; +leakyBucket_t outboundLeakyBucket; + +/* +================ +SVC_HashForAddress +================ +*/ +static long SVC_HashForAddress( netadr_t address ) { + byte *ip = NULL; + size_t size = 0; + int i; + long hash = 0; + + switch ( address.type ) { + case NA_IP: ip = address.ip; size = 4; break; + case NA_IP6: ip = address.ip6; size = 16; break; + default: break; + } + + for ( i = 0; i < size; i++ ) { + hash += (long)( ip[ i ] ) * ( i + 119 ); + } + + hash = ( hash ^ ( hash >> 10 ) ^ ( hash >> 20 ) ); + hash &= ( MAX_HASHES - 1 ); + + return hash; +} + +/* +================ +SVC_BucketForAddress + +Find or allocate a bucket for an address +================ +*/ +static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int period ) { + leakyBucket_t *bucket = NULL; + int i; + long hash = SVC_HashForAddress( address ); + int now = Sys_Milliseconds(); + + for ( bucket = bucketHashes[ hash ]; bucket; bucket = bucket->next ) { + switch ( bucket->type ) { + case NA_IP: + if ( memcmp( bucket->ipv._4, address.ip, 4 ) == 0 ) { + return bucket; + } + break; + + case NA_IP6: + if ( memcmp( bucket->ipv._6, address.ip6, 16 ) == 0 ) { + return bucket; + } + break; + + default: + break; + } + } + + for ( i = 0; i < MAX_BUCKETS; i++ ) { + int interval; + + bucket = &buckets[ i ]; + interval = now - bucket->lastTime; + + // Reclaim expired buckets + if ( bucket->lastTime > 0 && ( interval > ( burst * period ) || + interval < 0 ) ) { + if ( bucket->prev != NULL ) { + bucket->prev->next = bucket->next; + } else { + bucketHashes[ bucket->hash ] = bucket->next; + } + + if ( bucket->next != NULL ) { + bucket->next->prev = bucket->prev; + } + + Com_Memset( bucket, 0, sizeof( leakyBucket_t ) ); + } + + if ( bucket->type == NA_BAD ) { + bucket->type = address.type; + switch ( address.type ) { + case NA_IP: Com_Memcpy( bucket->ipv._4, address.ip, 4 ); break; + case NA_IP6: Com_Memcpy( bucket->ipv._6, address.ip6, 16 ); break; + default: break; + } + + bucket->lastTime = now; + bucket->burst = 0; + bucket->hash = hash; + + // Add to the head of the relevant hash chain + bucket->next = bucketHashes[ hash ]; + if ( bucketHashes[ hash ] != NULL ) { + bucketHashes[ hash ]->prev = bucket; + } + + bucket->prev = NULL; + bucketHashes[ hash ] = bucket; + + return bucket; + } + } + + // Couldn't allocate a bucket for this address + return NULL; +} + +/* +================ +SVC_RateLimit +================ +*/ +qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) { + if ( bucket != NULL ) { + int now = Sys_Milliseconds(); + int interval = now - bucket->lastTime; + int expired = interval / period; + int expiredRemainder = interval % period; + + if ( expired > bucket->burst || interval < 0 ) { + bucket->burst = 0; + bucket->lastTime = now; + } else { + bucket->burst -= expired; + bucket->lastTime = now - expiredRemainder; + } + + if ( bucket->burst < burst ) { + bucket->burst++; + + return qfalse; + } + } + + return qtrue; +} + +/* +================ +SVC_RateLimitAddress + +Rate limit for a particular address +================ +*/ +qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) { + leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period ); + + return SVC_RateLimit( bucket, burst, period ); +} + /* ================ SVC_Status @@ -314,6 +475,24 @@ void SVC_Status( netadr_t from ) { return; } + // Prevent using getstatus as an amplifier + if ( SVC_RateLimitAddress( from, 10, 1000 ) ) { + Com_DPrintf( "SVC_Status: rate limit from %s exceeded, dropping request\n", + NET_AdrToString( from ) ); + return; + } + + // Allow getstatus to be DoSed relatively easily, but prevent + // excess outbound bandwidth usage when being flooded inbound + if ( SVC_RateLimit( &outboundLeakyBucket, 10, 100 ) ) { + Com_DPrintf( "SVC_Status: rate limit exceeded, dropping request\n" ); + return; + } + + // A maximum challenge length of 128 should be more than plenty. + if(strlen(Cmd_Argv(1)) > 128) + return; + strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) ); // echo back the parameter to status. so master servers can use it as a challenge @@ -361,6 +540,20 @@ void SVC_Info( netadr_t from ) { return; } + // Prevent using getinfo as an amplifier + if ( SVC_RateLimitAddress( from, 10, 1000 ) ) { + Com_DPrintf( "SVC_Info: rate limit from %s exceeded, dropping request\n", + NET_AdrToString( from ) ); + return; + } + + // Allow getinfo to be DoSed relatively easily, but prevent + // excess outbound bandwidth usage when being flooded inbound + if ( SVC_RateLimit( &outboundLeakyBucket, 10, 100 ) ) { + Com_DPrintf( "SVC_Info: rate limit exceeded, dropping request\n" ); + return; + } + /* * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory. @@ -394,6 +587,12 @@ void SVC_Info( netadr_t from ) { Info_SetValueForKey( infostring, "gametypestring", g_gametypestring->string ); Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) ); +#ifdef USE_VOIP + if (sv_voipProtocol->string && *sv_voipProtocol->string) { + Info_SetValueForKey( infostring, "voip", sv_voipProtocol->string ); + } +#endif + if( sv_minPing->integer ) { Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) ); } @@ -417,7 +616,7 @@ SVC_FlushRedirect ================ */ -void SV_FlushRedirect( char *outputbuf ) { +static void SV_FlushRedirect( char *outputbuf ) { NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf ); } @@ -430,26 +629,32 @@ Shift down the remaining args Redirect all printfs =============== */ -void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { +static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; - unsigned int time; char remaining[1024]; // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc. // (OOB messages are the bottleneck here) #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; - static unsigned int lasttime = 0; char *cmd_aux; - // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534 - time = Com_Milliseconds(); - if ( (unsigned)( time - lasttime ) < 500u ) { + // Prevent using rcon as an amplifier and make dictionary attacks impractical + if ( SVC_RateLimitAddress( from, 10, 1000 ) ) { + Com_DPrintf( "SVC_RemoteCommand: rate limit from %s exceeded, dropping request\n", + NET_AdrToString( from ) ); return; } - lasttime = time; if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { + static leakyBucket_t bucket; + + // Make DoS via rcon impractical + if ( SVC_RateLimit( &bucket, 10, 1000 ) ) { + Com_DPrintf( "SVC_RemoteCommand: rate limit exceeded, dropping request\n" ); + return; + } + valid = qfalse; Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } else { @@ -520,11 +725,11 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c); if (!Q_stricmp(c, "getstatus")) { - SVC_Status( from ); - } else if (!Q_stricmp(c, "getinfo")) { + SVC_Status( from ); + } else if (!Q_stricmp(c, "getinfo")) { SVC_Info( from ); } else if (!Q_stricmp(c, "getchallenge")) { - SV_GetChallenge( from ); + SV_GetChallenge(from); } else if (!Q_stricmp(c, "connect")) { SV_DirectConnect( from ); } else if (!Q_stricmp(c, "authorizeThis")) { @@ -536,8 +741,8 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // server disconnect messages when their new server sees our final // sequenced messages to the old client } else { - Com_DPrintf ("bad connectionless packet from %s:\n%s\n" - , NET_AdrToString (from), s); + Com_DPrintf ("bad connectionless packet from %s:\n%s\n", + NET_AdrToString (from), s); } } @@ -562,7 +767,7 @@ void SV_PacketEvent( netadr_t from, msg_t *msg ) { // read the qport out of the message so we can fix up // stupid address translating routers MSG_BeginReadingOOB( msg ); - i=MSG_ReadLong( msg ); // sequence number + MSG_ReadLong( msg ); // sequence number qport = MSG_ReadShort( msg ) & 0xffff; // find which client the message is from @@ -593,7 +798,7 @@ void SV_PacketEvent( netadr_t from, msg_t *msg ) { // to make sure they don't need to retransmit the final // reliable message, but they don't do any other processing if (cl->state != CS_ZOMBIE) { - cl->lastPacketTime = svs.lastTime; // don't timeout + cl->lastPacketTime = svs.time; // don't timeout SV_ExecuteClientMessage( cl, msg ); } } @@ -613,7 +818,7 @@ SV_CalcPings Updates the cl->ping variables =================== */ -void SV_CalcPings( void ) { +static void SV_CalcPings( void ) { int i, j; client_t *cl; int total, count; @@ -673,7 +878,7 @@ for a few seconds to make sure any final reliable message gets resent if necessary ================== */ -void SV_CheckTimeouts( void ) { +static void SV_CheckTimeouts( void ) { int i; client_t *cl; int droppoint; @@ -799,6 +1004,11 @@ void SV_Frame( int msec ) { if( !com_sv_running->integer ) { // Running as a server, but no map loaded +#ifdef DEDICATED + // Block until something interesting happens + Sys_Sleep(-1); +#endif + return; } @@ -1010,42 +1220,42 @@ a client based on its rate settings #define UDPIP_HEADER_SIZE 28 #define UDPIP6_HEADER_SIZE 48 -int SV_RateMsec(client_t* client) +int SV_RateMsec(client_t *client) { - int rate, rateMsec; - int messageSize; + int rate, rateMsec; + int messageSize; + + messageSize = client->netchan.lastSentSize; + rate = client->rate; - messageSize = client->netchan.lastSentSize; - rate = client->rate; + if(sv_maxRate->integer) + { + if(sv_maxRate->integer < 1000) + Cvar_Set( "sv_MaxRate", "1000" ); + if(sv_maxRate->integer < rate) + rate = sv_maxRate->integer; + } - if (sv_maxRate->integer) - { - if (sv_maxRate->integer < 1000) - Cvar_Set("sv_MaxRate", "1000"); - if (sv_maxRate->integer < rate) - rate = sv_maxRate->integer; - } + if(sv_minRate->integer) + { + if(sv_minRate->integer < 1000) + Cvar_Set("sv_minRate", "1000"); + if(sv_minRate->integer > rate) + rate = sv_minRate->integer; + } - if (sv_minRate->integer) - { - if (sv_minRate->integer < 1000) - Cvar_Set("sv_minRate", "1000"); - if (sv_minRate->integer > rate) - rate = sv_minRate->integer; - } - - if (client->netchan.remoteAddress.type == NA_IP6) - messageSize += UDPIP6_HEADER_SIZE; - else - messageSize += UDPIP_HEADER_SIZE; - - rateMsec = messageSize * 1000 / ((int)(rate * com_timescale->value)); - rate = Sys_Milliseconds() - client->netchan.lastSentTime; - - if (rate > rateMsec) - return 0; - else - return rateMsec - rate; + if(client->netchan.remoteAddress.type == NA_IP6) + messageSize += UDPIP6_HEADER_SIZE; + else + messageSize += UDPIP_HEADER_SIZE; + + rateMsec = messageSize * 1000 / ((int) (rate * com_timescale->value)); + rate = Sys_Milliseconds() - client->netchan.lastSentTime; + + if(rate > rateMsec) + return 0; + else + return rateMsec - rate; } /* @@ -1060,70 +1270,70 @@ Return the time in msec until we expect to be called next int SV_SendQueuedPackets() { - int numBlocks; - int dlStart, deltaT, delayT; - static int dlNextRound = 0; - int timeVal = INT_MAX; + int numBlocks; + int dlStart, deltaT, delayT; + static int dlNextRound = 0; + int timeVal = INT_MAX; - // Send out fragmented packets now that we're idle - delayT = SV_SendQueuedMessages(); - if (delayT >= 0) - timeVal = delayT; + // Send out fragmented packets now that we're idle + delayT = SV_SendQueuedMessages(); + if(delayT >= 0) + timeVal = delayT; - if (sv_dlRate->integer) - { - // Rate limiting. This is very imprecise for high - // download rates due to millisecond timedelta resolution - dlStart = Sys_Milliseconds(); - deltaT = dlNextRound - dlStart; + if(sv_dlRate->integer) + { + // Rate limiting. This is very imprecise for high + // download rates due to millisecond timedelta resolution + dlStart = Sys_Milliseconds(); + deltaT = dlNextRound - dlStart; - if (deltaT > 0) - { - if (deltaT < timeVal) - timeVal = deltaT + 1; - } - else - { - numBlocks = SV_SendDownloadMessages(); + if(deltaT > 0) + { + if(deltaT < timeVal) + timeVal = deltaT + 1; + } + else + { + numBlocks = SV_SendDownloadMessages(); - if (numBlocks) - { - // There are active downloads - deltaT = Sys_Milliseconds() - dlStart; + if(numBlocks) + { + // There are active downloads + deltaT = Sys_Milliseconds() - dlStart; - delayT = 1000 * numBlocks * MAX_DOWNLOAD_BLKSIZE; - delayT /= sv_dlRate->integer * 1024; + delayT = 1000 * numBlocks * MAX_DOWNLOAD_BLKSIZE; + delayT /= sv_dlRate->integer * 1024; - if (delayT <= deltaT + 1) - { - // Sending the last round of download messages - // took too long for given rate, don't wait for - // next round, but always enforce a 1ms delay - // between DL message rounds so we don't hog - // all of the bandwidth. This will result in an - // effective maximum rate of 1MB/s per user, but the - // low download window size limits this anyways. - if (timeVal > 2) - timeVal = 2; + if(delayT <= deltaT + 1) + { + // Sending the last round of download messages + // took too long for given rate, don't wait for + // next round, but always enforce a 1ms delay + // between DL message rounds so we don't hog + // all of the bandwidth. This will result in an + // effective maximum rate of 1MB/s per user, but the + // low download window size limits this anyways. + if(timeVal > 2) + timeVal = 2; - dlNextRound = dlStart + deltaT + 1; - } - else - { - dlNextRound = dlStart + delayT; - delayT -= deltaT; + dlNextRound = dlStart + deltaT + 1; + } + else + { + dlNextRound = dlStart + delayT; + delayT -= deltaT; - if (delayT < timeVal) - timeVal = delayT; - } - } - } - } - else - { - if (SV_SendDownloadMessages()) - timeVal = 0; - } + if(delayT < timeVal) + timeVal = delayT; + } + } + } + } + else + { + if(SV_SendDownloadMessages()) + timeVal = 0; + } - return timeVal; + return timeVal; } diff --git a/code/server/sv_net_chan.c b/code/server/sv_net_chan.c index 1aa5a266..66832630 100644 --- a/code/server/sv_net_chan.c +++ b/code/server/sv_net_chan.c @@ -259,17 +259,17 @@ void SV_Netchan_Transmit( client_t *client, msg_t *msg) Netchan_SV_Process ================= */ -qboolean SV_Netchan_Process(client_t* client, msg_t* msg) { - int ret; - ret = Netchan_Process(&client->netchan, msg); - if (!ret) - return qfalse; +qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) { + int ret; + ret = Netchan_Process( &client->netchan, msg ); + if (!ret) + return qfalse; #ifdef LEGACY_PROTOCOL - if (client->compat) - SV_Netchan_Decode(client, msg); + if(client->compat) + SV_Netchan_Decode(client, msg); #endif - return qtrue; + return qtrue; } diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index 7ac89133..2009947f 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -91,7 +91,7 @@ static void SV_EmitPacketEntities( clientSnapshot_t *from, clientSnapshot_t *to, if ( newnum == oldnum ) { // delta update from old position // because the force parm is qfalse, this will not result - // in any bytes being emited if the entity has not changed at all + // in any bytes being emitted if the entity has not changed at all MSG_WriteDeltaEntity (msg, oldent, newent, qfalse, sv.frameTime); oldindex++; newindex++; @@ -1049,6 +1049,53 @@ static void SV_BuildClientSnapshot( client_t *client ) { frame->ps.radarInfo = client->radarInfo; } +#ifdef USE_VOIP +/* +================== +SV_WriteVoipToClient + +Check to see if there is any VoIP queued for a client, and send if there is. +================== +*/ +static void SV_WriteVoipToClient(client_t *cl, msg_t *msg) +{ + int totalbytes = 0; + int i; + voipServerPacket_t *packet; + + if(cl->queuedVoipPackets) + { + // Write as many VoIP packets as we reasonably can... + for(i = 0; i < cl->queuedVoipPackets; i++) + { + packet = cl->voipPacket[(i + cl->queuedVoipIndex) % ARRAY_LEN(cl->voipPacket)]; + + if(!*cl->downloadName) + { + totalbytes += packet->len; + if (totalbytes > (msg->maxsize - msg->cursize) / 2) + break; + + MSG_WriteByte(msg, svc_voipOpus); + MSG_WriteShort(msg, packet->sender); + MSG_WriteByte(msg, (byte) packet->generation); + MSG_WriteLong(msg, packet->sequence); + MSG_WriteByte(msg, packet->frames); + MSG_WriteShort(msg, packet->len); + MSG_WriteBits(msg, packet->flags, VOIP_FLAGCNT); + MSG_WriteData(msg, packet->data, packet->len); + } + + Z_Free(packet); + } + + cl->queuedVoipPackets -= i; + cl->queuedVoipIndex += i; + cl->queuedVoipIndex %= ARRAY_LEN(cl->voipPacket); + } +} +#endif + /* ======================= SV_SendMessageToClient @@ -1056,7 +1103,8 @@ SV_SendMessageToClient Called by SV_SendClientSnapshot and SV_SendClientGameState ======================= */ -void SV_SendMessageToClient( msg_t *msg, client_t *client ) { +void SV_SendMessageToClient(msg_t *msg, client_t *client) +{ // record information about the message client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time; @@ -1088,7 +1136,6 @@ void SV_SendClientSnapshot( client_t *client ) { return; } - memset(msg_buf, 0, sizeof(msg_buf)); MSG_Init (&msg, msg_buf, sizeof(msg_buf)); msg.allowoverflow = qtrue; @@ -1115,6 +1162,10 @@ void SV_SendClientSnapshot( client_t *client ) { // Add any download data if the client is downloading SV_WriteDownloadToClient( client, &msg ); +#ifdef USE_VOIP + SV_WriteVoipToClient( client, &msg ); +#endif + // check for overflow if ( msg.overflowed ) { Com_Printf ("WARNING: msg overflowed for %s\n", client->name); @@ -1130,16 +1181,19 @@ void SV_SendClientSnapshot( client_t *client ) { SV_SendClientMessages ======================= */ -void SV_SendClientMessages( void ) { - int i; +void SV_SendClientMessages(void) +{ + int i; int rate; client_t *c; // send a message to each connected client - for (i=0, c = svs.clients ; i < sv_maxclients->integer ; i++, c++) { - if (!c->state) { + for(i=0; i < sv_maxclients->integer; i++) + { + c = &svs.clients[i]; + + if(!c->state) continue; // not connected - } if(svs.time - c->lastSnapshotTime < c->snapshotMsec * com_timescale->value) continue; // It's not time yet @@ -1171,8 +1225,8 @@ void SV_SendClientMessages( void ) { } // generate and send a new message - SV_SendClientSnapshot(c); - c->lastSnapshotTime = svs.time; + SV_SendClientSnapshot(c); + c->lastSnapshotTime = svs.time; c->rateDelayed = qfalse; } diff --git a/code/server/sv_world.c b/code/server/sv_world.c index 7f19d1c1..879d9d3d 100644 --- a/code/server/sv_world.c +++ b/code/server/sv_world.c @@ -100,7 +100,7 @@ SV_CreateworldSector Builds a uniformly subdivided tree for the given world size =============== */ -worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) { +static worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) { worldSector_t *anode; vec3_t size; vec3_t mins1, maxs1, mins2, maxs2; @@ -388,8 +388,8 @@ SV_AreaEntities_r ==================== */ -void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) { - svEntity_t *check, *next; +static void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) { + svEntity_t *check, *next; gentity_t *gcheck; worldSector_t *nodestack[ 8 ]; int iStackPos; @@ -499,7 +499,7 @@ void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, con touch = SV_GentityNum( entityNum ); - Com_Memset( trace, 0, sizeof( trace_t ) ); + Com_Memset(trace, 0, sizeof(trace_t)); // if it doesn't have any brushes of a type we // are looking for, ignore it @@ -527,7 +527,7 @@ SV_ClipMoveToEntities ==================== */ -void SV_ClipMoveToEntities( moveclip_t *clip ) { +static void SV_ClipMoveToEntities( moveclip_t *clip ) { int i, num; int touchlist[MAX_GENTITIES]; gentity_t *touch; @@ -797,7 +797,7 @@ void SV_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const ve moveclip_t clip; int i; - Com_Memset( &clip, 0, sizeof( moveclip_t ) ); + Com_Memset ( &clip, 0, sizeof ( moveclip_t ) ); // clip to world CM_BoxTrace( &clip.trace, start, end, mins, maxs, 0, contentmask, cylinder ); From c4683e24178288ac7d48f1aff59e91264def16c1 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 21:18:35 +0200 Subject: [PATCH 0708/2040] Don't execute entity events from the console if the client isn't running This prevent the server from executing console commands for the first player --- code/fgame/gamecmds.cpp | 6 +++++- code/fgame/gamecvars.cpp | 4 ++++ code/fgame/gamecvars.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/code/fgame/gamecmds.cpp b/code/fgame/gamecmds.cpp index 1f931aa8..260449d9 100644 --- a/code/fgame/gamecmds.cpp +++ b/code/fgame/gamecmds.cpp @@ -127,7 +127,11 @@ qboolean G_ConsoleCommand(void) } } - result = G_ProcessClientCommand(ent); + if (cl_running->integer) { + // Don't execute the command in multiplayer + // otherwise, the command will be executed "by" the first client + result = G_ProcessClientCommand(ent); + } } catch (const char *error) { G_ExitWithError(error); } diff --git a/code/fgame/gamecvars.cpp b/code/fgame/gamecvars.cpp index e93ce97b..90eb8c5d 100644 --- a/code/fgame/gamecvars.cpp +++ b/code/fgame/gamecvars.cpp @@ -268,6 +268,8 @@ cvar_t *sv_minPlayers; cvar_t *g_rankedserver; cvar_t *g_spectatefollow_firstperson; +cvar_t *cl_running; + void CVAR_Init(void) { developer = gi.Cvar_Get("developer", "0", 0); @@ -623,4 +625,6 @@ void CVAR_Init(void) gi.Printf("numbots overflow, setting to %d\n", sv_maxbots->integer); gi.cvar_set("sv_numbots", sv_maxbots->string); } + + cl_running = gi.Cvar_Get("cl_running", "", 0); } diff --git a/code/fgame/gamecvars.h b/code/fgame/gamecvars.h index 8103ae5e..8ec3c098 100644 --- a/code/fgame/gamecvars.h +++ b/code/fgame/gamecvars.h @@ -273,6 +273,8 @@ extern cvar_t *sv_minPlayers; extern cvar_t *g_rankedserver; extern cvar_t *g_spectatefollow_firstperson; +extern cvar_t *cl_running; + void CVAR_Init(void); #ifdef __cplusplus From dc24a4a067475b8a7ea3a6e99e865332798cdea6 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 21:32:42 +0200 Subject: [PATCH 0709/2040] Stop spawning if there is no entity 0 (could only happen in multiplayer) --- code/fgame/lodthing.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/fgame/lodthing.cpp b/code/fgame/lodthing.cpp index 74be7738..b9a68ff8 100644 --- a/code/fgame/lodthing.cpp +++ b/code/fgame/lodthing.cpp @@ -129,6 +129,9 @@ void LODMaster::Spawn gi.cvar_set( "lod_tool", "1" ); ent = g_entities->entity; + if (!ent) { + return; + } if( ent->IsSubclassOfPlayer() ) { From 29c3bece4ec92f3d865ef393dd42813500ac36d7 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 21:32:55 +0200 Subject: [PATCH 0710/2040] Prevent players to use developer commands like `lod` or `view` --- code/fgame/gamecmds.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/code/fgame/gamecmds.cpp b/code/fgame/gamecmds.cpp index 260449d9..d3223621 100644 --- a/code/fgame/gamecmds.cpp +++ b/code/fgame/gamecmds.cpp @@ -159,14 +159,18 @@ qboolean G_ProcessClientCommand(gentity_t *ent) consolecmd_t *cmds; int i; int n; - ConsoleEvent *ev; Player *player; + qboolean allowDev; if (!ent || !ent->client || !ent->entity) { // not fully in game yet return qfalse; } + // Added in 2.1 + // Prevent players from messing with the server with developer commands + allowDev = g_gametype->integer == GT_SINGLE_PLAYER; + cmd = gi.Argv(0); player = (Player *)ent->entity; @@ -184,20 +188,28 @@ qboolean G_ProcessClientCommand(gentity_t *ent) } if (Event::Exists(cmd)) { - ev = new ConsoleEvent(cmd); - ev->SetConsoleEdict(ent); + ConsoleEvent ev(cmd); + ev.SetConsoleEdict(ent); n = gi.Argc(); for (i = 1; i < n; i++) { - ev->AddToken(gi.Argv(i)); + ev.AddToken(gi.Argv(i)); } if (!Q_stricmpn(cmd, "lod_", 4)) { + if (!allowDev) { + return false; + } return LODModel.ProcessEvent(ev); } else if (!Q_stricmpn(cmd, "view", 4)) { + if (!allowDev) { + return false; + } return Viewmodel.ProcessEvent(ev); - } else if (ent->entity->CheckEventFlags(ev)) { + } + + if (ent->entity->CheckEventFlags(&ev)) { return ent->entity->ProcessEvent(ev); } } @@ -493,12 +505,11 @@ qboolean G_ScriptCmd(gentity_t *ent) ConsoleEvent *event; int numArgs; int i; - bool recompile; numArgs = gi.Argc(); if (numArgs <= 1) { - gi.Printf("Usage: script [filename] ([recompile])\n"); + gi.Printf("Usage: script [filename]\n"); return qtrue; } From 56cbab8661d76935ff8725a7c494aefd69478075 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 21:42:07 +0200 Subject: [PATCH 0711/2040] Fix NumEventCommands() returning an incorrect result --- code/qcommon/listener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/listener.cpp b/code/qcommon/listener.cpp index fb30bc4b..921647e6 100644 --- a/code/qcommon/listener.cpp +++ b/code/qcommon/listener.cpp @@ -1130,7 +1130,7 @@ Number of total events */ int Event::NumEventCommands() { - return totalevents; + return commandList.size(); } /* From bdec6aab07983796aa124e0eb86e6cc7b4824910 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 22:09:36 +0200 Subject: [PATCH 0712/2040] Fix calls to class dumping functions --- code/fgame/gamecmds.cpp | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/code/fgame/gamecmds.cpp b/code/fgame/gamecmds.cpp index d3223621..e7daa02e 100644 --- a/code/fgame/gamecmds.cpp +++ b/code/fgame/gamecmds.cpp @@ -60,13 +60,17 @@ consolecmd_t G_ConsoleCmds[] = { {"levelvars", G_LevelVarsCmd, qfalse}, {"gamevars", G_GameVarsCmd, qfalse}, {"script", G_ScriptCmd, qfalse}, + // Added in 2.0 {"reloadmap", G_ReloadMap, qfalse}, + // Added in OPM + //==== {"compilescript", G_CompileScript, qfalse}, {"addbot", G_AddBotCommand, qfalse}, {"removebot", G_RemoveBotCommand, qfalse}, #ifdef _DEBUG {"bot", G_BotCommand, qfalse}, #endif + //==== {NULL, NULL, qfalse} }; @@ -223,7 +227,6 @@ Cmd_Say_f ================== */ void G_Say(gentity_t *ent, qboolean team, qboolean arg0) - { int j; gentity_t *other; @@ -287,7 +290,6 @@ void G_Say(gentity_t *ent, qboolean team, qboolean arg0) } qboolean G_CameraCmd(gentity_t *ent) - { Event *ev; const char *cmd; @@ -346,7 +348,6 @@ qboolean G_SoundCmd(gentity_t *ent) } qboolean G_SayCmd(gentity_t *ent) - { G_Say(ent, false, false); @@ -354,7 +355,6 @@ qboolean G_SayCmd(gentity_t *ent) } qboolean G_EventListCmd(gentity_t *ent) - { const char *mask; @@ -363,13 +363,12 @@ qboolean G_EventListCmd(gentity_t *ent) mask = gi.Argv(1); } - //Event::ListCommands( mask ); + Event::ListCommands( mask ); return qtrue; } qboolean G_PendingEventsCmd(gentity_t *ent) - { const char *mask; @@ -378,13 +377,12 @@ qboolean G_PendingEventsCmd(gentity_t *ent) mask = gi.Argv(1); } - //Event::PendingEvents( mask ); + Event::PendingEvents( mask ); return qtrue; } qboolean G_EventHelpCmd(gentity_t *ent) - { const char *mask; @@ -393,13 +391,12 @@ qboolean G_EventHelpCmd(gentity_t *ent) mask = gi.Argv(1); } - //Event::ListDocumentation( mask, false ); + Event::ListDocumentation( mask, false ); return qtrue; } qboolean G_DumpEventsCmd(gentity_t *ent) - { const char *mask; @@ -408,13 +405,12 @@ qboolean G_DumpEventsCmd(gentity_t *ent) mask = gi.Argv(1); } - //Event::ListDocumentation( mask, true ); + Event::ListDocumentation( mask, true ); return qtrue; } qboolean G_ClassEventsCmd(gentity_t *ent) - { const char *className; @@ -424,13 +420,12 @@ qboolean G_ClassEventsCmd(gentity_t *ent) className = gi.Argv(1); } else { className = gi.Argv(1); - //ClassEvents( className ); + ClassEvents( className, qfalse ); } return qtrue; } qboolean G_DumpClassEventsCmd(gentity_t *ent) - { const char *className; @@ -440,31 +435,28 @@ qboolean G_DumpClassEventsCmd(gentity_t *ent) className = gi.Argv(1); } else { className = gi.Argv(1); - //ClassEvents( className, qtrue ); + ClassEvents( className, qtrue ); } return qtrue; } qboolean G_DumpAllClassesCmd(gentity_t *ent) - { DumpAllClasses(); return qtrue; } qboolean G_ClassListCmd(gentity_t *ent) - { - //listAllClasses(); + listAllClasses(); return qtrue; } qboolean G_ClassTreeCmd(gentity_t *ent) - { if (gi.Argc() > 1) { - //listInheritanceOrder( gi.Argv( 1 ) ); + listInheritanceOrder( gi.Argv( 1 ) ); } else { gi.SendServerCommand(ent - g_entities, "print \"Syntax: classtree [classname].\n\""); } @@ -480,7 +472,6 @@ qboolean G_ShowVarCmd(gentity_t *ent) void PrintVariableList(ScriptVariableList *list) {} qboolean G_LevelVarsCmd(gentity_t *ent) - { gi.Printf("Level Variables\n"); PrintVariableList(level.vars); @@ -489,7 +480,6 @@ qboolean G_LevelVarsCmd(gentity_t *ent) } qboolean G_GameVarsCmd(gentity_t *ent) - { gi.Printf("Game Variables\n"); PrintVariableList(game.vars); @@ -546,7 +536,8 @@ qboolean G_ScriptCmd(gentity_t *ent) return scriptEnt->ProcessEvent(event); } -qboolean G_ReloadMap(gentity_t* ent) { +qboolean G_ReloadMap(gentity_t* ent) +{ char name[256]; Com_sprintf(name, sizeof(name), "gamemap \"%s\"\n", level.mapname.c_str()); From 5cc168111c1a0ff2ac270354128e425a931febba Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 22:10:44 +0200 Subject: [PATCH 0713/2040] Fix class not dumping properly --- code/qcommon/class.cpp | 61 ++++++++++++++++++++++++--------------- code/qcommon/class.h | 1 + code/qcommon/listener.cpp | 5 +--- code/qcommon/listener.h | 1 - 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/code/qcommon/class.cpp b/code/qcommon/class.cpp index ea0f9dbf..6e3e8984 100644 --- a/code/qcommon/class.cpp +++ b/code/qcommon/class.cpp @@ -466,6 +466,11 @@ EventDef *ClassDef::GetDef(int eventnum) } } +EventDef *ClassDef::GetDef(Event *ev) +{ + return GetDef(ev->eventnum); +} + int ClassDef::GetFlags(Event *event) { EventDef *def = GetDef(event->eventnum); @@ -490,10 +495,9 @@ void ClassDef::BuildResponseList(void) delete[] responseLookup; responseLookup = NULL; } - - num = Event::NumEventCommands( - ); //size will be total event count, because it WAS faster to look for an event via eventnum - //nowadays there's not much overhead in performance, TODO: change size to appropriate. + //size will be total event count, because it WAS faster to look for an event via eventnum + //nowadays there's not much overhead in performance, TODO: change size to appropriate. + num = Event::NumEventCommands(); responseLookup = (ResponseDef **)new char[sizeof(ResponseDef *) * num]; memset(responseLookup, 0, sizeof(ResponseDef *) * num); @@ -564,8 +568,9 @@ void ClassEvents(const char *classname, qboolean print_to_disk) Event **events; byte *order; FILE *class_file; - str classNames[MAX_INHERITANCE]; + ClassDef *classes[MAX_INHERITANCE]; str class_filename; + EventDef *def; c = getClass(classname); if (!c) { @@ -597,12 +602,13 @@ void ClassEvents(const char *classname, qboolean print_to_disk) orderNum = 0; for (; c != NULL; c = c->super) { if (orderNum < MAX_INHERITANCE) { - classNames[orderNum] = c->classname; + classes[orderNum] = c; } r = c->responses; if (r) { for (i = 0; r[i].event != NULL; i++) { ev = (int)r[i].event->eventnum; + assert(ev < num); if (!set[ev]) { set[ev] = true; @@ -622,20 +628,25 @@ void ClassEvents(const char *classname, qboolean print_to_disk) CLASS_Print(class_file, "********************************************************\n"); CLASS_Print(class_file, "********************************************************\n\n"); + Event::SortEventList(&ClassDef::sortedList); + for (j = orderNum - 1; j >= 0; j--) { CLASS_Print(class_file, "\n********************************************************\n"); - CLASS_Print(class_file, "* Class: %s\n", classNames[j].c_str()); + CLASS_Print(class_file, "* Class: %s\n", classes[j]->classname); CLASS_Print(class_file, "********************************************************\n\n"); for (i = 1; i < num; i++) { int index; index = ClassDef::sortedList.ObjectAt(i); if (events[index] && (order[index] == j)) { - Event::eventDefList[events[index]].PrintEventDocumentation(class_file, qfalse); + def = classes[j]->GetDef(events[index]); + def->PrintEventDocumentation(class_file, qfalse); } } } + ClassDef::sortedList.FreeObjectList(); + if (class_file != NULL) { CLASS_DPrintf("Printed class info to file %s\n", class_filename.c_str()); fclose(class_file); @@ -648,44 +659,46 @@ void ClassEvents(const char *classname, qboolean print_to_disk) void DumpClass(FILE *class_file, const char *className) { + ClassDef *classDef; ClassDef *c; ResponseDef *r; int ev; int i; - int num, num2; + int num; Event **events; + EventDef *def; - c = getClass(className); - if (!c) { + classDef = getClass(className); + if (!classDef) { return; } - num = Event::commandList.size(); - num2 = Event::NumEventCommands(); + num = Event::NumEventCommands(); - events = new Event *[num2]; - memset(events, 0, sizeof(Event *) * num2); + events = new Event *[num]; + memset(events, 0, sizeof(Event *) * num); // gather event responses for this class - r = c->responses; + r = classDef->responses; if (r) { for (i = 0; r[i].event != NULL; i++) { ev = (int)r[i].event->eventnum; if (r[i].response) { + assert(ev < num); events[ev] = r[i].event; } } } CLASS_Print(class_file, "\n"); - if (c->classID[0]) { - CLASS_Print(class_file, "

%s (%s)", c->classname, c->classname, c->classID); + if (classDef->classID[0]) { + CLASS_Print(class_file, "

%s (%s)", classDef->classname, classDef->classname, classDef->classID); } else { - CLASS_Print(class_file, "

%s", c->classname, c->classname); + CLASS_Print(class_file, "

%s", classDef->classname, classDef->classname); } // print out lineage - for (c = c->super; c != NULL; c = c->super) { + for (c = classDef->super; c != NULL; c = c->super) { CLASS_Print(class_file, " -> %s", c->classname, c->classname); } CLASS_Print(class_file, "

\n"); @@ -698,7 +711,8 @@ void DumpClass(FILE *class_file, const char *className) index = ClassDef::sortedList.ObjectAt(i); if (events[index]) { - Event::eventDefList[events[index]].PrintEventDocumentation(class_file, qtrue); + def = classDef->GetDef(events[index]); + def->PrintEventDocumentation(class_file, qtrue); ClassDef::dump_numevents++; } } @@ -762,9 +776,6 @@ void DumpAllClasses(void) ClassDef::dump_numclasses = 0; ClassDef::dump_numevents = 0; - ClassDef::sortedList.ClearObjectList(); - ClassDef::sortedClassList.ClearObjectList(); - Event::SortEventList(&ClassDef::sortedList); ClassDef::SortClassList(&ClassDef::sortedClassList); @@ -776,6 +787,8 @@ void DumpAllClasses(void) DumpClass(class_file, c->classname); } + ClassDef::sortedList.FreeObjectList(); + if (class_file != NULL) { CLASS_Print(class_file, "

\n"); CLASS_Print( diff --git a/code/qcommon/class.h b/code/qcommon/class.h index d6fc751e..7dd14ccf 100644 --- a/code/qcommon/class.h +++ b/code/qcommon/class.h @@ -241,6 +241,7 @@ public: ); EventDef *GetDef(int eventnum); + EventDef *GetDef(Event *ev); int GetFlags(Event *event); void Destroy(); diff --git a/code/qcommon/listener.cpp b/code/qcommon/listener.cpp index 921647e6..ffb45cd0 100644 --- a/code/qcommon/listener.cpp +++ b/code/qcommon/listener.cpp @@ -75,8 +75,6 @@ int DisableListenerNotify = 0; bool Listener::EventSystemStarted = 0; -int Event::totalevents = 1; - Event EV_Listener_CancelFor ( "cancelFor", @@ -1130,7 +1128,7 @@ Number of total events */ int Event::NumEventCommands() { - return commandList.size(); + return commandList.size() + 1; } /* @@ -1629,7 +1627,6 @@ void Event::LoadEvents() #endif delete DataNodeList; - totalevents++; } } diff --git a/code/qcommon/listener.h b/code/qcommon/listener.h index 70acb320..8bf343d5 100644 --- a/code/qcommon/listener.h +++ b/code/qcommon/listener.h @@ -274,7 +274,6 @@ public: static EventQueueNode EventQueue; - static int totalevents; static int NumEventCommands(); static void ListCommands(const char *mask = NULL); From bed9bbbd05fbba2c2f6cabc04f63d524d7ece9e3 Mon Sep 17 00:00:00 2001 From: smallmodel <15067410+smallmodel@users.noreply.github.com> Date: Sat, 31 Aug 2024 22:13:21 +0200 Subject: [PATCH 0714/2040] Update classes documentation --- docs/features_g_allclasses.html | 715 +++++++++++++++++--------------- 1 file changed, 384 insertions(+), 331 deletions(-) diff --git a/docs/features_g_allclasses.html b/docs/features_g_allclasses.html index 5b4b8471..0c82ecfa 100644 --- a/docs/features_g_allclasses.html +++ b/docs/features_g_allclasses.html @@ -28,14 +28,17 @@

ai_on

    Turns the AI on for this actor.
+

alarmnode( String value )
+

    Sets the name of the alarm node for the actor (must have type set to alarm for effect)
+

alarmnode

    Gets the name of the alarm node for the actor (must have type set to alarm for effect)

alarmnode( String value )

    Sets the name of the alarm node for the actor (must have type set to alarm for effect)
-

alarmnode( String value )
-

    Sets the name of the alarm node for the actor (must have type set to alarm for effect)
+

alarmthread( String value )
+

    Sets the name of the alarm thread for the actor (must have type set to alarm for effect)

alarmthread

    Gets the name of the alarm thread for the actor (must have type set to alarm for effect)
@@ -43,8 +46,8 @@

alarmthread( String value )

    Sets the name of the alarm thread for the actor (must have type set to alarm for effect)
-

alarmthread( String value )
-

    Sets the name of the alarm thread for the actor (must have type set to alarm for effect)
+

ammo_grenade( Integer grenade_count )
+

    Gives the AI some grenades

ammo_grenade

    Returns how many grenades an AI has
@@ -52,9 +55,6 @@

ammo_grenade( Integer grenade_count )

    Gives the AI some grenades
-

ammo_grenade( Integer grenade_count )
-

    Gives the AI some grenades
-

anim( String name )

    Play animation.
@@ -65,10 +65,10 @@
    Loop animation.

animname
-

    Gets the animname.
+
    Sets the animname.

animname
-

    Sets the animname.
+
    Gets the animname.

animscript( String name )

    Play the animation script
@@ -95,43 +95,43 @@
    Used only by grenade return animations to tell the code when to attach the grenade to the actor

attackhandler
-

    Sets the current script that will handle attack events
+
    Gets the current script that will handle attack events

attackhandler
-

    Gets the current script that will handle attack events
+
    Sets the current script that will handle attack events

attackplayer

    Force Actor to attack the player
+

avoidplayer( Integer allowavoid )
+

    set to 0 if this AI shouldn't automatically get out of the way, non-zero if he should.
    +
+ +

avoidplayer( Integer allowavoid )
+

    set to 0 if this AI shouldn't automatically get out of the way, non-zero if he should.
    +
+

avoidplayer

    is 0 if this AI won't automatically get out of the way, non-zero if he will
-

avoidplayer( Integer allowavoid )
-

    set to 0 if this AI shouldn't automatically get out of the way, non-zero if he should.
    -
- -

avoidplayer( Integer allowavoid )
-

    set to 0 if this AI shouldn't automatically get out of the way, non-zero if he should.
    -
- -

balconyheight( Float height )
-

    minimum height a balcony guy must fall to do special balcony death
-

balconyheight( Float height )

    minimum height a balcony guy must fall to do special balcony death

balconyheight

    minimum height a balcony guy must fall to do special balcony death
+

balconyheight( Float height )
+

    minimum height a balcony guy must fall to do special balcony death
+

bedead

    Forces the actor to be instantly and totally dead; no death animation is played

blendtime
-

    Get the crossblend time
+
    Set the crossblend time to something other than the default, in seconds

blendtime
-

    Set the crossblend time to something other than the default, in seconds
+
    Get the crossblend time

breakspecial

    tell ai to break special attack
@@ -175,10 +175,10 @@ Should be called infrequently, and never during the middle of a grenade toss.
preps the dead actor for turning nonsolid gradually over time

deathhandler
-

    Gets the current script that will handle death events
+
    Sets the current script that will handle death events

deathhandler
-

    Sets the current script that will handle death events
+
    Gets the current script that will handle death events

deathsinkstart

    Makes the entity sink into the ground and then get removed (this starts it).
@@ -192,21 +192,21 @@ Should be called infrequently, and never during the middle of a grenade toss.
detachgrenade
    Used only by grenade return animations to tell the code when to throw the grenade
-

disguise_accept_thread( String value )
-

    Sets the name of the thread for the actor to start when accepting papers
- -

disguise_accept_thread( String value )
-

    Sets the name of the thread for the actor to start when accepting papers
-

disguise_accept_thread

    Gets the name of the thread for the actor to start when accepting papers
-

disguise_level
-

    Gets the disguise level of the actor. May be 1 or 2
+

disguise_accept_thread( String value )
+

    Sets the name of the thread for the actor to start when accepting papers
+ +

disguise_accept_thread( String value )
+

    Sets the name of the thread for the actor to start when accepting papers

disguise_level( Integer value )

    Sets the disguise level of the actor. May be 1 or 2
+

disguise_level
+

    Gets the disguise level of the actor. May be 1 or 2
+

disguise_level( Integer value )

    Sets the disguise level of the actor. May be 1 or 2
@@ -219,12 +219,12 @@ Should be called infrequently, and never during the middle of a grenade toss.
disguise_period
    Gets the time between the end of one disguise behavior and start of the next
-

disguise_range
-

    Gets the maximum distance for disguise behavior to get triggered
-

disguise_range( Float range_in_units )

    Sets the maximum distance for disguise behavior to get triggered
+

disguise_range
+

    Gets the maximum distance for disguise behavior to get triggered
+

disguise_range( Float range_in_units )

    Sets the maximum distance for disguise behavior to get triggered
@@ -276,10 +276,10 @@ Should be called infrequently, and never during the middle of a grenade toss.
eyeslookat( Entity entity )
    The actor will look at this entity.
-

fallheight
+

fallheight( Float height )

    Set the fallheight
-

fallheight( Float height )
+

fallheight

    Set the fallheight

favoriteenemy( Entity ai_or_player )
@@ -300,35 +300,38 @@ Should be called infrequently, and never during the middle of a grenade toss.
fixedleash( Float multiplier )

    if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset
-

fixedleash
-

    if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset
-

fixedleash( Float multiplier )

    if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset
-

fov( Float angle )
-

    The fov angle of the actor
- -

fov( Float angle )
-

    The fov angle of the actor
+

fixedleash
+

    if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset

fov

    The fov angle of the actor
+

fov( Float angle )
+

    The fov angle of the actor
+ +

fov( Float angle )
+

    The fov angle of the actor
+

GetRunAnim

    Internal usage

GetWalkAnim

    Internal usage
+

gren_awareness( Float awareness_percent )
+

    sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
+ +

gren_awareness( Float awareness_percent )
+

    sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
+

gren_awareness

    gets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
-

gren_awareness( Float awareness_percent )
-

    sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
- -

gren_awareness( Float awareness_percent )
-

    sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
+

gun( String s )
+

    specifies the gun to use

gun( String s )

    specifies the gun to use
@@ -336,9 +339,6 @@ Should be called infrequently, and never during the middle of a grenade toss.
gun
    gets the gun to being used
-

gun( String s )
-

    specifies the gun to use
-

hascompletelookahead

    returns true if there are no corners to turn on the rest of the AI's current path
@@ -348,12 +348,12 @@ Should be called infrequently, and never during the middle of a grenade toss.
headmodel( String headmodel )
    sets the head model
-

headskin( String headskin )
-

    sets the head skin
-

headskin

    gets the head skin
+

headskin( String headskin )
+

    sets the head skin
+

hearing( Float radius )

    The hearing radius of the actor
@@ -381,24 +381,24 @@ Should be called infrequently, and never during the middle of a grenade toss.
immediateremove
    Removes this listener immediately.
-

inreload( Integer reloading )
-

    set to non-zero to indicate the AI is in a reload
-

inreload

    returns non-zero if the AI is in a reload
+

inreload( Integer reloading )
+

    set to non-zero to indicate the AI is in a reload
+

interrupt_point

    hint from animation scripts to AI code that now is a good time to switch animations

interval( Float distance )

    Sets the distance AI tries to keep between squadmates while moving.
-

interval
-

    Gets the distance AI tries to keep between squadmates while moving.
-

interval( Float distance )

    Sets the distance AI tries to keep between squadmates while moving.
+

interval
+

    Gets the distance AI tries to keep between squadmates while moving.
+

intervaldir

    the direction the AI would like to move to maintain its interval
@@ -439,32 +439,35 @@ Location values:

leash( Float distance )

    Sets the maximum distance the AI will wander from its leash home
-

leash
-

    Gets the maximum distance the AI will wander from its leash home
-

leash( Float distance )

    Sets the maximum distance the AI will wander from its leash home
-

lookaroundangle
-

    gets the angle in degrees left or right of center that the AI will look around while patrolling
+

leash
+

    Gets the maximum distance the AI will wander from its leash home

lookaroundangle( Float angle )

    gets the angle in degrees left or right of center that the AI will look around while patrolling
+

lookaroundangle
+

    gets the angle in degrees left or right of center that the AI will look around while patrolling
+

lookaroundangle( Float angle )

    gets the angle in degrees left or right of center that the AI will look around while patrolling

lookat( Entity entity )

    The actor will look at this entity.
+

maxdist( Float distance )
+

    Sets the maximum distance the AI tries to allow between itself and the player
+ +

maxdist( Float distance )
+

    Sets the maximum distance the AI tries to allow between itself and the player
+

maxdist

    Gets the maximum distance the AI tries to keep between itself and the player
-

maxdist( Float distance )
-

    Sets the maximum distance the AI tries to allow between itself and the player
- -

maxdist( Float distance )
-

    Sets the maximum distance the AI tries to allow between itself and the player
+

mindist( Float distance )
+

    Sets the minimum distance the AI tries to keep between itself and the player

mindist

    Gets the minimum distance the AI tries to keep between itself and the player
@@ -472,15 +475,12 @@ Location values:

mindist( Float distance )

    Sets the minimum distance the AI tries to keep between itself and the player
-

mindist( Float distance )
-

    Sets the minimum distance the AI tries to keep between itself and the player
+

mood
+

    gets the AI mood: 'bored', 'nervous', 'curious', or 'alert'.

mood( String new_mood )

    sets the AI mood... must be 'bored', 'nervous', 'curious', or 'alert'.
-

mood
-

    gets the AI mood: 'bored', 'nervous', 'curious', or 'alert'.
-

movedir

    Returns a unit vector pointing in the current direction of motion, or zero if not moving.This still has meaning if velocity is zero but the AI is starting to move on a path.
@@ -493,15 +493,15 @@ Location values:

moveto( String anim, String dest )

    Specify the location to move to, with animation anim.
+

mumble( Integer can_mumble )
+

    Set to 1 if this guy is allowed to mumble, or 0 if he is not
+ +

mumble( Integer can_mumble )
+

    Set to 1 if this guy is allowed to mumble, or 0 if he is not
+

mumble

    Returns 1 if this guy is allowed to mumble, or 0 if he is not
-

mumble( Integer can_mumble )
-

    Set to 1 if this guy is allowed to mumble, or 0 if he is not
- -

mumble( Integer can_mumble )
-

    Set to 1 if this guy is allowed to mumble, or 0 if he is not
-

nationality

    Get the nationality of an actor. Return values are ger, it, usa, uk, ussr and unset.
@@ -511,15 +511,15 @@ Location values:

nationality( String nationality )

    Set the nationality of an actor. Valid entries are default, ger, it, usa, uk, and ussr.
+

nolongpain( Integer allow )
+

    Set to 1 if long pain is not allowed, or 0 if long pain is allowed.
+ +

nolongpain( Integer allow )
+

    Set to 1 if long pain is not allowed, or 0 if long pain is allowed.
+

nolongpain

    Returns 1 if long pain is not allowed, or 0 if long pain is allowed.
-

nolongpain( Integer allow )
-

    Set to 1 if long pain is not allowed, or 0 if long pain is allowed.
- -

nolongpain( Integer allow )
-

    Set to 1 if long pain is not allowed, or 0 if long pain is allowed.
-

nonvislevel

    visibility level in range 0-1 below which an enemy is treated as non-visible
@@ -529,6 +529,10 @@ Location values:

nonvislevel

    visibility level in range 0-1 below which an enemy is treated as non-visible
+

nosurprise( Integer nosurprise )
+

    set to 0 to allow this guy to play a surprised animation when first encountering an enemy.
    +
+

nosurprise

    gets whether or not this guy is allowed to play a surprised animation when first encountering an enemy.
@@ -537,46 +541,42 @@ Location values:
    set to 0 to allow this guy to play a surprised animation when first encountering an enemy.
-

nosurprise( Integer nosurprise )
-

    set to 0 to allow this guy to play a surprised animation when first encountering an enemy.
    -
- -

noticescale( Float multiplier )
-

    Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)
-

noticescale( Float multiplier )

    Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)

noticescale

    Get the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)
-

no_idle
-

    Specifies if the actor will not go into idle after playing an animation
+

noticescale( Float multiplier )
+

    Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)

no_idle

    Gets if the actor will not go into idle after playing an animation
+

no_idle
+

    Specifies if the actor will not go into idle after playing an animation
+

pain( Entity attacker, Integer damage, Entity inflictor, Vector position, Vector direction, Vector normal, Integer knockback, Integer damageflags, Integer meansofdeath, Integer location )

    used to inflict pain to an entity

painhandler
-

    Sets the current script that will handle pain events
+
    Gets the current script that will handle pain events

painhandler
-

    Gets the current script that will handle pain events
+
    Sets the current script that will handle pain events

pathdist

    returns total distance along current path to the path goal
+

patrolpath( String value )
+

    Sets the name of the patrol path for the actor (must have type set to patrol for effect)
+ +

patrolpath( String value )
+

    Sets the name of the patrol path for the actor (must have type set to patrol for effect)
+

patrolpath

    Gets the name of the patrol path for the actor (must have type set to patrol for effect)
-

patrolpath( String value )
-

    Sets the name of the patrol path for the actor (must have type set to patrol for effect)
- -

patrolpath( String value )
-

    Sets the name of the patrol path for the actor (must have type set to patrol for effect)
-

physics_off

    turn physics off.
@@ -614,15 +614,15 @@ default channel, CHAN_BODY.

resetleash

    resets the AI's leash to their current position
-

runanimrate( Float multiplier )
-

    Set the rate at which the run animation plays back
- -

runanimrate( Float multiplier )
-

    Set the rate at which the run animation plays back
-

runanimrate

    Get the rate at which the run animation plays back
+

runanimrate( Float multiplier )
+

    Set the rate at which the run animation plays back
+ +

runanimrate( Float multiplier )
+

    Set the rate at which the run animation plays back
+

runto( String dest )

    Specify the location to run to.
@@ -665,15 +665,19 @@ default channel, CHAN_BODY.

share_grenade

    internal code use only - shares an AI's grenade with his squad mates.
-

sight( Float max_sight_range )
-

    Sets the vision distance of the actor.
-

sight

    Gets the vision distance of the actor.

sight( Float max_sight_range )

    Sets the vision distance of the actor.
+

sight( Float max_sight_range )
+

    Sets the vision distance of the actor.
+ +

silent( Integer silent )
+

    set to 0 to prevent this guy from saying stuff besides pain and death sounds.
    +
+

silent

    gets whether or not this guy is allowed to say stuff besides pain and death sounds
@@ -681,9 +685,8 @@ default channel, CHAN_BODY.
    set to 0 to prevent this guy from saying stuff besides pain and death sounds.
-

silent( Integer silent )
-

    set to 0 to prevent this guy from saying stuff besides pain and death sounds.
    -
+

sound_awareness( Float awareness_percent )
+

    sets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius

sound_awareness

    gets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius
@@ -691,9 +694,6 @@ default channel, CHAN_BODY.

sound_awareness( Float awareness_percent )

    sets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius
-

sound_awareness( Float awareness_percent )
-

    sets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius
-

stopped

    sent when entity has stopped bouncing for MOVETYPE_TOSS.
@@ -736,23 +736,20 @@ default channel, CHAN_BODY.

turret( String turret )

    Sets the turret of the actor.
-

turret
-

    Gets the turret of the actor.
-

turret( String turret )

    Sets the turret of the actor.
-

type_attack( String value )
-

    Sets the attack type of the actor.
- -

type_attack( String value )
-

    Sets the attack type of the actor.
+

turret
+

    Gets the turret of the actor.

type_attack

    Gets the attack type of the actor.
-

type_disguise( String value )
-

    Sets the disguise type of the actor.
+

type_attack( String value )
+

    Sets the attack type of the actor.
+ +

type_attack( String value )
+

    Sets the attack type of the actor.

type_disguise

    Gets the disguise type of the actor.
@@ -760,6 +757,9 @@ default channel, CHAN_BODY.

type_disguise( String value )

    Sets the disguise type of the actor.
+

type_disguise( String value )
+

    Sets the disguise type of the actor.
+

type_grenade( String value )

    Sets the grenade type of the actor.
@@ -769,15 +769,15 @@ default channel, CHAN_BODY.

type_grenade

    Gets the grenade type of the actor.
-

type_idle( String value )
-

    Sets the idle type of the actor.
-

type_idle

    Gets the idle type of the actor.

type_idle( String value )

    Sets the idle type of the actor.
+

type_idle( String value )
+

    Sets the idle type of the actor.
+

unholster( Integer holster )

    If non-zero, affects offhand. Unholster weapon
@@ -787,19 +787,19 @@ default channel, CHAN_BODY.

use( String name, Integer weapon_hand )

    Use the specified weapon or item in the hand choosen (optional).
+

voicetype
+

    Set voicetype to magic letter postfix
+ +

voicetype
+

    Set voicetype to magic letter postfix
+

voicetype

    Gets the voice type
-

voicetype
-

    Set voicetype to magic letter postfix
- -

voicetype
-

    Set voicetype to magic letter postfix
- -

waittrigger( Boolean bool )
+

waittrigger

    If true, patrol guys and running men wait until triggered to move
-

waittrigger
+

waittrigger( Boolean bool )

    If true, patrol guys and running men wait until triggered to move

waittrigger( Boolean bool )
@@ -839,30 +839,30 @@ default channel, CHAN_BODY.

accuracy

    Set percent to hit
-

alarmnode
-

    Gets the name of the alarm node for the actor (must have type set to alarm for effect)
-

alarmnode( String value )

    Sets the name of the alarm node for the actor (must have type set to alarm for effect)
+

alarmnode
+

    Gets the name of the alarm node for the actor (must have type set to alarm for effect)
+

ammo_grenade

    Returns how many grenades an AI has

ammo_grenade( Integer grenade_count )

    Gives the AI some grenades
-

balconyheight( Float height )
-

    minimum height a balcony guy must fall to do special balcony death
-

balconyheight

    minimum height a balcony guy must fall to do special balcony death
-

disguise_level
-

    Gets the disguise level of the actor. May be 1 or 2
+

balconyheight( Float height )
+

    minimum height a balcony guy must fall to do special balcony death

disguise_level( Integer value )

    Sets the disguise level of the actor. May be 1 or 2
+

disguise_level
+

    Gets the disguise level of the actor. May be 1 or 2
+

disguise_period( Float period_in_seconds )

    Sets the time between the end of one disguise behavior and start of the next
@@ -918,29 +918,29 @@ default channel, CHAN_BODY.
    Get if the sentient is forced to drop health no matter what level.nodrophealth is.

forcedropweapon
-

    Get if the sentient is forced to drop health no matter what level.nodrophealth is.
+
    Force the sentient to drop weapons no matter what level.nodropweapon is.

forcedropweapon
-

    Force the sentient to drop health no matter what level.nodrophealth is.
- -

fov( Float angle )
-

    The fov angle of the actor
+
    Get if the sentient is forced to drop health no matter what level.nodrophealth is.

fov

    The fov angle of the actor
-

gren_awareness
-

    gets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
+

fov( Float angle )
+

    The fov angle of the actor

gren_awareness( Float awareness_percent )

    sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)
-

gun
-

    gets the gun to being used
+

gren_awareness
+

    gets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied once every 0.4 seconds)

gun( String s )

    specifies the gun to use
+

gun
+

    gets the gun to being used
+

health( Integer newHealth )

    set the health of the entity to newHealth
@@ -965,24 +965,24 @@ default channel, CHAN_BODY.

leash

    Gets the maximum distance the AI will wander from its leash home
-

maxdist
-

    Gets the maximum distance the AI tries to keep between itself and the player
-

maxdist( Float distance )

    Sets the maximum distance the AI tries to allow between itself and the player
-

mindist
-

    Gets the minimum distance the AI tries to keep between itself and the player
+

maxdist
+

    Gets the maximum distance the AI tries to keep between itself and the player

mindist( Float distance )

    Sets the minimum distance the AI tries to keep between itself and the player
-

model
-

    get the modelName.
+

mindist
+

    Gets the minimum distance the AI tries to keep between itself and the player

model( Entity modelName )

    set the model to modelName.
+

model
+

    get the modelName.
+

nosurprise

    gets whether or not this guy is allowed to play a surprised animation when first encountering an enemy.
@@ -991,48 +991,48 @@ default channel, CHAN_BODY.
    set to 0 to allow this guy to play a surprised animation when first encountering an enemy.
-

noticescale( Float multiplier )
-

    Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)
-

noticescale

    Get the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)
-

patrolpath
-

    Gets the name of the patrol path for the actor (must have type set to patrol for effect)
+

noticescale( Float multiplier )
+

    Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)

patrolpath( String value )

    Sets the name of the patrol path for the actor (must have type set to patrol for effect)
-

sight( Float max_sight_range )
-

    Sets the vision distance of the actor.
+

patrolpath
+

    Gets the name of the patrol path for the actor (must have type set to patrol for effect)

sight

    Gets the vision distance of the actor.
-

sound_awareness
-

    gets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius
+

sight( Float max_sight_range )
+

    Sets the vision distance of the actor.

sound_awareness( Float awareness_percent )

    sets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius
+

sound_awareness
+

    gets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades to zero outside sound's radius
+

target

    entity's target

target( String targetname_to_target )

    target another entity with targetname_to_target.
-

turret
-

    Gets the turret of the actor.
-

turret( String turret )

    Sets the turret of the actor.
-

type_attack( String value )
-

    Sets the attack type of the actor.
+

turret
+

    Gets the turret of the actor.

type_attack

    Gets the attack type of the actor.
+

type_attack( String value )
+

    Sets the attack type of the actor.
+

type_disguise

    Gets the disguise type of the actor.
@@ -1052,10 +1052,10 @@ default channel, CHAN_BODY.
    Sets the idle type of the actor.

voicetype
-

    Gets the voice type
+
    Set voicetype to magic letter postfix

voicetype
-

    Set voicetype to magic letter postfix
+
    Gets the voice type

waittrigger

    If true, patrol guys and running men wait until triggered to move
@@ -1076,6 +1076,9 @@ default channel, CHAN_BODY.

AmmoEntity -> Item -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

+ +

ammoentity_postspawn
+

    Ammo Entity Post Spawn

Animate (animate) -> Entity -> SimpleEntity -> Listener -> Class

@@ -1134,18 +1137,18 @@ speed - how fast the effect should travel, in other words, how long before the e

max_dist( Float max_dist )

    Set the max distance for this node to be attracted, -1 for unlimited distance.
-

priority
-

    Get the node priority
-

priority( Integer priority )

    Set the node priority
-

respawn_time
-

    Get the how much time will this node re-attract already attracted AIs
+

priority
+

    Get the node priority

respawn_time( Float respawn_time )

    Set the how much time will this node re-attract already attracted AIs. The minimum required value is 1, otherwise AI will get stuck.
+

respawn_time
+

    Get the how much time will this node re-attract already attracted AIs
+

setuse( Boolean use )

    Set if AI should use or not
@@ -1155,11 +1158,11 @@ speed - how fast the effect should travel, in other words, how long before the e

stay_time( Float stay_time )

    Set the maximum stay time AI will stay on this node
-

team
-

    Get the attractive node team. 'none' for no team.
-

team( String team )

    Set the attractive node team. 'none' for no team.
+ +

team
+

    Get the attractive node team. 'none' for no team.

BarrelObject (func_barrel) -> Entity -> SimpleEntity -> Listener -> Class

@@ -1864,14 +1867,14 @@ offset - vector offset for the model from the specified tag
    used to ban certain contact when in parentmode
-

classname
-

    The entity's classname
-

classname( String nameOfClass )

    Determines what class to use for this entity,
    this is pre-processed from the BSP at the start
    of the level.
+

classname
+

    The entity's classname
+

claypidgeon

    turn the entity into a non-solid shootable thing
@@ -1998,9 +2001,6 @@ god - makes the entity invincible

gettagposition( String tag_name )

    Gets the world position of the tag
-

getzone
-

    Gets the current entity zone. NIL if the entity is not in a zone.
-

ghost

    make non-solid but still send to client regardless of hide status.
@@ -2048,9 +2048,6 @@ entity's current health, it will be killed or destroyed.

isinside( Entity ent )

    returns 1 if the entity is inside,0 if not
-

isinzone( Entity zone )
-

    Returns 1 if the entity is in the specified zone. 0 otherwise
-

istouching( Entity ent )

    returns 1 if the entities are touching,0 if not
@@ -2125,21 +2122,21 @@ which is attached to the current entity.

max_health( Integer newHealth )

    sets max_health without changing health
-

max_health( Integer newHealth )
-

    sets max_health without changing health
-

max_health

    gets the entity's max health
+

max_health( Integer newHealth )
+

    sets max_health without changing health
+ +

model( Entity modelName )
+

    set the model to modelName.
+ +

model( Entity modelName )
+

    set the model to modelName.
+

model

    get the modelName.
-

model( Entity modelName )
-

    set the model to modelName.
- -

model( Entity modelName )
-

    set the model to modelName.
-

movementstealth( Float scale )

    Sets the current movement stealth scalar for the sentient
@@ -2211,12 +2208,12 @@ lightstyledynamiclight - the dynamic light uses a light style, use the

revive( Float health )

    sets the health,even if dead
-

rotatedbbox( Integer on_off )
-

    Sets the entity's bbox to rotate with it.
-

rotatedbbox

    Gets te entity's bbox to rotate with it.
+

rotatedbbox( Integer on_off )
+

    Sets the entity's bbox to rotate with it.
+

safesolid

    make solid but first make sure no one is in my bounds that is thinking.
@@ -2351,20 +2348,17 @@ broadcast - always send this entity to the client

usebbox

    do not perform perfect collision,use bounding box instead.
-

velocity
-

    gets the velocity for this entity.
-

velocity( Vector velocity )

    sets the velocity for this entity.
+

velocity
+

    gets the velocity for this entity.
+

volumedamage( Float damage )

    does damage to any entity within this's volume

yaw

    entity's yaw
- -

zone
-

    Get the current entity zone. NIL if the entity is not in a zone.

Event -> Class

@@ -2517,6 +2511,31 @@ Location values:

FencePost (func_fencepost) -> Entity -> SimpleEntity -> Listener -> Class

+ +

killed( Entity attacker, Integer damage, Entity inflictor, Vector position, Vector direction, Vector normal, Integer knockback, Integer damageflags, Integer meansofdeath, Integer location )
+

    event which is sent to an entity once it as been killed
    +
    +Location values:
    +-1 General
    +0 Pelvis
    +1 Lower Torso
    +2 Mid Torso
    +3 Upper Torso
    +4 Neck
    +5 Head
    +6 RUpperArm
    +7 RForearm
    +8 RHand
    +9 LUpperArm
    +10 LForearm
    +11 LHand
    +12 RThigh
    +13 RCalf
    +14 RFoot
    +15 LThigh
    +16 LCalf
    +17 LFoot
    +

FixedTurret -> VehicleTank -> DrivableVehicle -> Vehicle -> VehicleBase -> Animate -> Entity -> SimpleEntity -> Listener -> Class

@@ -2676,6 +2695,12 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

Game -> Listener -> Class

+ +

detail
+

    game.detail
+ +

skill
+

    game.skill

Gib (gib) -> Mover -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

@@ -2776,24 +2801,24 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

Hud -> Listener -> Class

-

alignx( String align )
-

    Sets the horizontal alignment for the HUD. Specified by 'left', 'center', or 'right'
-

alignx

    Gets the horizontal alignment for the HUD. Specified by 'left', 'center', or 'right'
+

alignx( String align )
+

    Sets the horizontal alignment for the HUD. Specified by 'left', 'center', or 'right'
+

aligny( String align )

    Sets the vertical alignment for the HUD. Specified by 'top', 'center', or 'bottom'

aligny

    Gets the vertical alignment for the HUD
-

alpha( Float alpha )
-

    Sets the HUD alpha
-

alpha

    Gets the HUD alpha
+

alpha( Float alpha )
+

    Sets the HUD alpha
+

color

    Gets the HUD colors
@@ -2855,17 +2880,17 @@ Note : you will need to call in HUD functions again as it won't refresh to the p

setvirtualsize( Boolean virtual )

    Sets if the HUD should use virtual screen resolution for positioning and size
-

x( Integer x )
-

    Sets the HUD horizontal position
-

x

    Gets the HUD horizontal position
-

y
-

    Gets the HUD vertical position
+

x( Integer x )
+

    Sets the HUD horizontal position

y( Integer y )

    Sets the HUD vertical position
+ +

y
+

    Gets the HUD vertical position

InfoLandmark (info_landmark) -> Listener -> Class

@@ -2882,7 +2907,7 @@ Note : you will need to call in HUD functions again as it won't refresh to the p
-

InfoNull (info_null) -> Entity -> SimpleEntity -> Listener -> Class

+

InfoNull (info_null) -> Listener -> Class

@@ -3028,51 +3053,60 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

Level -> Listener -> Class

-

alarm( Integer alarm_status )
+

alarm

    zero = global level alarm off,non-zero = alarm on
-

alarm
+

alarm( Integer alarm_status )

    zero = global level alarm off,non-zero = alarm on

badplace( String name, Vector origin, Float radius, [ String [team] ], [ Float [duration] ] )

    Enables a 'bad place' for AI of team 'american', 'german', or (default) 'both' to avoid, and optionally gives it a duration

bombs_planted( Integer num )
-

    the number of bombs that are set
+
    Sets the number of bombs that are set

bombs_planted( Integer num )
-

    Sets the number of bombs that are set
+
    the number of bombs that are set

bombs_planted

    Gets the number of bombs that are set
-

clockside
-

    Gets which side the clock is on... 'axis' or 'allies' win when time is up
+

clockside( String axis_allies_draw_kills )
+

    Sets which side the clock is on... 'axis' or 'allies' win when time is up, 'kills' gives the win to the team with more live members,'draw' no one wins

clockside( String axis_or_allies )

    Sets which side the clock is on... 'axis' or 'allies' win when time is up
-

clockside( String axis_allies_draw_kills )
-

    Sets which side the clock is on... 'axis' or 'allies' win when time is up, 'kills' gives the win to the team with more live members,'draw' no one wins
- -

dmrespawning( Integer allow_respawn )
-

    set to 1 to turn on wave-based DM, to 0 to disable respawns within a round
+

clockside
+

    Gets which side the clock is on... 'axis' or 'allies' win when time is up

dmrespawning

    returns 1 if wave-based DM, 0 if respawns are disabled within a round

dmrespawning( Integer allow_respawn )
-

    set to 1 to turn on wave-based DM,to 0 to disable respawns within a round
+
    set to 1 to turn on wave-based DM, to 0 to disable respawns within a round
-

dmroundlimit( Integer roundlimit )
-

    sets the default roundlimit,in minutes; can be overridden by 'roundlimit' cvar
+

dmrespawning( Integer allow_respawn )
+

    set to 1 to turn on wave-based DM,to 0 to disable respawns within a round

dmroundlimit( Integer roundlimit )

    sets the default roundlimit, in minutes; can be overridden by 'roundlimit' cvar
+

dmroundlimit( Integer roundlimit )
+

    sets the default roundlimit,in minutes; can be overridden by 'roundlimit' cvar
+

dmroundlimit

    gets the actual roundlimit, in minutes; may be 'roundlimit' cvar or the default round limit
+

force_team_objective
+

    Return 1 if each team has a separate objective location
+ +

force_team_objective( Integer force )
+

    Whether or not to force using a separate objective location for each team.
    +1 (forced on TOW/Liberation match): different location for each team
    +0 (default): teams use same location on non-TOW/non-Liberation match
    +
+

found_secrets

    count of found secrets
@@ -3103,12 +3137,12 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

planting_team( String axis_allies_draw_kills )

    which is planting the bomb,'axis' or 'allies'
-

planting_team
-

    Gets which is planting the bomb,'axis' or 'allies'
-

planting_team( String axis_or_allies )

    Sets which is planting the bomb,'axis' or 'allies'
+

planting_team
+

    Gets which is planting the bomb,'axis' or 'allies'
+

rain_density

    Sets the rain density
@@ -3172,21 +3206,21 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

roundstarted

    non-zero if round has started
+

targets_destroyed( Integer num )
+

    Sets the number of bomb targets that have been destroyed
+

targets_destroyed

    Gets the number of bomb targets that have been destroyed
-

targets_destroyed( Integer num )
-

    Sets the number of bomb targets that have been destroyed
-

targets_destroyed( Integer num )

    the number of bomb targets that have been destroyed
-

targets_to_destroy
-

    Gets the number of bomb targets that must be destroyed
-

targets_to_destroy( Integer num )

    Sets the number of bomb targets that must be destroyed
+

targets_to_destroy
+

    Gets the number of bomb targets that must be destroyed
+

targets_to_destroy( Integer num )

    the number of bomb targets that must be destroyed
@@ -3390,6 +3424,15 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

Parm -> Listener -> Class

+

motionfail
+

    motionfail
+ +

movedone
+

    movedone
+ +

movefail
+

    movefail
+

other

    other
@@ -3398,6 +3441,12 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

previousthread

    previousthread
+ +

sayfail
+

    sayfail
+ +

upperfail
+

    upperfail

PathNode (info_pathnode) -> SimpleEntity -> Listener -> Class

@@ -3502,11 +3551,11 @@ Location values:
17 LFoot
-

damage_multiplier
-

damage_multiplier( Float damage_multiplier )

    Sets the current damage multiplier
+

damage_multiplier
+

dead

    Called when the player is dead.
@@ -3604,7 +3653,7 @@ Location values:
    Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount.

giveweapon( String weapon_name )
-

    Gives player all weapons.
+
    Gives the player the specified weapon.

gotkill( Entity victim, Integer damage, Entity inflictor, Integer meansofdeath, Boolean gib )

    event sent to attacker when an entity dies
@@ -3612,10 +3661,10 @@ Location values:

gvo

    Retrieves the server's vote options file
-

has_disguise
+

has_disguise( Integer is_disguised )

    zero = does not have a disguise,non - zero = has a disguise
-

has_disguise( Integer is_disguised )
+

has_disguise

    zero = does not have a disguise,non - zero = has a disguise

hideent( Entity entity )
@@ -3798,10 +3847,10 @@ can specify 'stand', 'duck' or 'prone'.

    returns 1 if this player is holding the primary fire, or 0 if not

ready
-

    returns 1 if this player is ready,0 otherwise
+
    makes this player ready for the round to start

ready
-

    makes this player ready for the round to start
+
    returns 1 if this player is ready,0 otherwise

reload

    Reloads the player's weapon
@@ -4544,6 +4593,9 @@ Default=0:

ScriptAimedStrafingGunfire (script_aimedstrafinggunfire) -> ScriptSimpleStrafingGunfire -> ScriptSlave -> Mover -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

+

aimtarget
+

    Set the aim target.
+

fire

    Fire.
@@ -4748,6 +4800,18 @@ Location values:

dmg( Integer damage )

    Set the damage.
+

doActivate( Entity activatingEntity )
+

    General trigger event for all entities
+ +

doBlocked( Entity obstacle )
+

    sent to entity when blocked.
+ +

doTouch( Entity touchingEntity )
+

    sent to entity when touched.
+ +

doUse( Entity activatingEntity )
+

    sent to entity when it is used by another entity
+

endpath

    Stop following the path
@@ -4759,7 +4823,7 @@ Location values:

followpath( Entity path, [ String arg1 ], [ String arg2 ], [ String arg3 ], [ String arg4 ], [ String arg5 ], [ String arg6 ] )

    Makes the script slave follow the specified path. The allowable arguments are ignoreangles,
    -normalangles, loop, and a number specifying the start time.
+ignorevelocity, normalangles, loop, and a number specifying the start time.

jumpto( String vector_or_entity )

    Jump to specified vector or entity.
@@ -5683,15 +5747,15 @@ Location values:

forcedrophealth

    Get if the sentient is forced to drop health no matter what level.nodrophealth is.
+

forcedropweapon
+

    Force the sentient to drop health no matter what level.nodrophealth is.
+ +

forcedropweapon
+

    Force the sentient to drop health no matter what level.nodrophealth is.
+

forcedropweapon

    Get if the sentient is forced to drop health no matter what level.nodrophealth is.
-

forcedropweapon
-

    Force the sentient to drop weapons no matter what level.nodropweapon is.
- -

forcedropweapon
-

    Force the sentient to drop weapons no matter what level.nodropweapon is.
-

forcelandminemeasure

    Force a remeasurement to all landmines
@@ -5829,18 +5893,15 @@ Location values:
Sets the yaw of the entity or an up and down
direction if newAngle is[ 0 - 359 ] or - 1 or - 2 -

angle( Float newAngle )
-

    set the angles of the entity using just one value.
    -Sets the yaw of the entity or an up and down
    -direction if newAngle is[ 0 - 359 ] or - 1 or - 2
-

angle

    get the angles of the entity using just one value.
    Gets the yaw of the entity or an up and down
    direction if newAngle is[ 0 - 359 ] or - 1 or - 2
-

angles( Vector newAngles<0.00...360.00><0.00...360.00><0.00...360.00> )
-

    set the angles of the entity to newAngles.
+

angle( Float newAngle )
+

    set the angles of the entity using just one value.
    +Sets the yaw of the entity or an up and down
    +direction if newAngle is[ 0 - 359 ] or - 1 or - 2

angles( Vector newAngles<0.00...360.00><0.00...360.00><0.00...360.00> )

    set the angles of the entity to newAngles.
@@ -5848,6 +5909,9 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

angles

    get the angles of the entity.
+

angles( Vector newAngles<0.00...360.00><0.00...360.00><0.00...360.00> )
+

    set the angles of the entity to newAngles.
+

centroid

    entity's centroid
@@ -5869,24 +5933,24 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2

rightvector

    get the right vector of angles
+

target( String targetname_to_target )
+

    target another entity with targetname_to_target.
+

target

    entity's target

target( String targetname_to_target )

    target another entity with targetname_to_target.
-

target( String targetname_to_target )
-

    target another entity with targetname_to_target.
- -

targetname( String targetName )
-

    set the targetname of the entity to targetName.
-

targetname( String targetName )

    set the targetname of the entity to targetName.

targetname

    entity's targetname
+

targetname( String targetName )
+

    set the targetname of the entity to targetName.
+

upvector

    get the up vector of angles
@@ -6120,6 +6184,10 @@ direction if newAngle is[ 0 - 359 ] or - 1 or - 2
    Sets the entity to watch at this node.
+

TargetList -> Class

+
+
+

Teleporter (trigger_teleport) -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

@@ -6234,7 +6302,7 @@ Location values:

stickybombwet

-

ThrowObject (func_throwobject) -> Object -> Animate -> Entity -> SimpleEntity -> Listener -> Class

+

ThrowObject (func_throwobject) -> Animate -> Entity -> SimpleEntity -> Listener -> Class

doTouch( Entity touchingEntity )
@@ -6289,12 +6357,12 @@ Location values:

AxisObjNum( Integer AxisObjNum )

    Sets the objective number for the axis team
-

ControlledBy( Integer ControlledBy )
-

    Sets the team controlling the objective
-

ControlledBy

    Objective controller
+

ControlledBy( Integer ControlledBy )
+

    Sets the team controlling the objective
+

initialize

    Initialize object
@@ -6454,30 +6522,8 @@ If facet is 2 than trigger is East/West oriented. If facet is 3 than trigger is

activatetrigger( Entity triggering_entity )

    Activates all of the targets for this trigger.
-

damage( Entity attacker, Integer damage, Entity inflictor, Vector position, Vector direction, Vector normal, Integer knockback, Integer damageflags, Integer meansofdeath, Integer location )
-

    general damage event used by all entities
    -
    -Location values:
    --1 General
    -0 Pelvis
    -1 Lower Torso
    -2 Mid Torso
    -3 Upper Torso
    -4 Neck
    -5 Head
    -6 RUpperArm
    -7 RForearm
    -8 RHand
    -9 LUpperArm
    -10 LForearm
    -11 LHand
    -12 RThigh
    -13 RCalf
    -14 RFoot
    -15 LThigh
    -16 LCalf
    -17 LFoot
    -
+

damage( Integer damage )
+

    Sets the amount of damage to do.

TriggerEntity (trigger_entity) -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

@@ -6661,6 +6707,10 @@ as a multi-faceted edge trigger.
    Send event to owner of trigger.
+

TriggerSidedUse (trigger_sideduse) -> TriggerUse -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

+
+
+

TriggerSpeaker (sound_speaker) -> TriggerPlaySound -> Trigger -> Animate -> Entity -> SimpleEntity -> Listener -> Class

@@ -6767,14 +6817,14 @@ as a multi-faceted edge trigger.

suppressWidth( Float radius )

    Sets the horizontal radius of suppression fire
-

targettype( String value )
-

    Sets the target type to be none any, or player
+

targettype
+

    Gets the target type

targettype( String value )

    Sets the target type to be none, any, or player
-

targettype
-

    Gets the target type
+

targettype( String value )
+

    Sets the target type to be none any, or player

turnSpeed( Float speed )

    Sets the turret's turn speed
@@ -6947,10 +6997,10 @@ Location values:

canuse( Entity entity )

    Returns 1 if passed entity can 'use' this vehicle.
-

collisionent( Entity entity )
+

collisionent

    Gets the Collision Entity
-

collisionent
+

collisionent( Entity entity )

    Gets the Collision Entity

damage( Entity attacker, Integer damage, Entity inflictor, Vector position, Vector direction, Vector normal, Integer knockback, Integer damageflags, Integer meansofdeath, Integer location )
@@ -7233,6 +7283,9 @@ Location values:
16 LCalf
17 LFoot
+ +

owner
+

    owner

VehicleHalfTrack (VehicleHalfTrack) -> DrivableVehicle -> Vehicle -> VehicleBase -> Animate -> Entity -> SimpleEntity -> Listener -> Class

@@ -7348,12 +7401,12 @@ Location values:

aimtolerance( Vector caps )

    Sets a tolerance for the angles.
-

collisionent( Entity entity )
-

    Sets the Collision Entity
-

collisionent

    Gets the Collision Entity
+

collisionent( Entity entity )
+

    Sets the Collision Entity
+

damage( Entity attacker, Integer damage, Entity inflictor, Vector position, Vector direction, Vector normal, Integer knockback, Integer damageflags, Integer meansofdeath, Integer location )