Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map loading time optimizations #173

Merged
merged 16 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CVARS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,15 @@ Client-Side

..

:Name: r_openglMipMaps
:Values: "0", "1"
:Default: "1"
:Description:
Enable / Disable OpenGL mipmap generation. Disable to restore
original downsampling algorithms.

..

:Name: r_saberGlow
:Values: "0", "1"
:Default: "1"
Expand Down
9 changes: 6 additions & 3 deletions src/botlib/l_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1384,10 +1384,13 @@ int MV_MenuPatchFile(const char *in, unsigned long inhash, const char *patch, ch
}

*out = (char *)GetMemory(outlen + 1);
for (size_t i = 0; i < menufile.size(); i++) {
strcat(*out, menufile.at(i).str.c_str());
strcat(*out, "\n");
char *pout = *out;
for (auto it = menufile.begin(); it != menufile.end(); ++it) {
Com_Memcpy(pout, it->str.c_str(), it->str.size());
pout += it->str.size();
*pout++ = '\n';
}
assert(pout == &(*out)[outlen]);
(*out)[outlen] = 0;

return outlen;
Expand Down
7 changes: 7 additions & 0 deletions src/cgame/tr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ typedef enum {
TC_S3TC_DXT
} textureCompression_t;

typedef enum {
QGL_VERSION_1_0,
QGL_VERSION_1_4
} qglVersion_t;

typedef struct {
char renderer_string[MAX_STRING_CHARS];
char vendor_string[MAX_STRING_CHARS];
Expand Down Expand Up @@ -337,6 +342,8 @@ typedef struct {
const char *version_string;
const char *extensions_string;

qglVersion_t glVersion;

int maxTextureSize; // queried from GL
int maxActiveTextures; // multitexture ability

Expand Down
2 changes: 1 addition & 1 deletion src/qcommon/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ int Com_Filter(const char *filter, const char *name, int casesensitive)
Com_FilterPath
============
*/
int Com_FilterPath(char *filter, char *name, int casesensitive)
int Com_FilterPath(char *filter, const char *name, int casesensitive)
{
int i;
char new_filter[MAX_QPATH];
Expand Down
38 changes: 6 additions & 32 deletions src/qcommon/files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ or configs will never get loaded from disk!
#define MAX_FILEHASH_SIZE 1024

typedef struct fileInPack_s {
char *name; // name of the file
const char *name; // name of the file
unsigned int pos; // file info position in zip
unsigned int len; // uncompress file size
struct fileInPack_s* next; // next file in the hash
Expand Down Expand Up @@ -1967,11 +1967,9 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass
char filename_inzip[MAX_ZPATH];
unz_file_info file_info;
ZPOS64_T i;
size_t len;
int hash;
int fs_numHeaderLongs;
int *fs_headerLongs;
char *namePtr;
int strLength;

fs_numHeaderLongs = 0;
Expand All @@ -1984,31 +1982,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass

fs_packFiles += gi.number_entry;

len = 0;
unzGoToFirstFile(uf);
for (i = 0; i < gi.number_entry; i++)
{
err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
if (err != UNZ_OK) {
break;
}
strLength = strlen(filename_inzip);
if ( assetsJKA ) {
// Ugly workarounds:
// - rename academy shader files to avoid collisions
// - rename academy sounds.cfg files to prevent them from overriding sounds of jk2 models that don't have a sounds.cfg
if ( strLength > 7 && !Q_stricmp(filename_inzip + strLength - 7, ".shader") ) {
len += 4; // "_jka"
} else if ( strLength > 15 && !Q_stricmpn(filename_inzip, "models/players/", 15) && !Q_stricmp(filename_inzip + strLength - 11, "/sounds.cfg") ) {
len += 4; // "_jka"
}
}
len += strLength + 1;
unzGoToNextFile(uf);
}

buildBuffer = (struct fileInPack_s *)Z_Malloc((int)((gi.number_entry * sizeof(fileInPack_t)) + len), TAG_FILESYS, qtrue);
namePtr = ((char *) buildBuffer) + gi.number_entry * sizeof( fileInPack_t );
buildBuffer = (struct fileInPack_s *)Z_Malloc((int)((gi.number_entry * sizeof(fileInPack_t))), TAG_FILESYS, qtrue);
fs_headerLongs = (int *)Z_Malloc( gi.number_entry * sizeof(int), TAG_FILESYS, qtrue );

// get the hash table size from the number of files in the zip
Expand Down Expand Up @@ -2060,9 +2034,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass
}
Q_strlwr( filename_inzip );
hash = FS_HashFileName(filename_inzip, pack->hashSize);
buildBuffer[i].name = namePtr;
strcpy( buildBuffer[i].name, filename_inzip );
namePtr += strlen(filename_inzip) + 1;
buildBuffer[i].name = CopyString(filename_inzip, TAG_FILESYS);
// store the file position in the zip
buildBuffer[i].pos = unzGetOffset(uf);
buildBuffer[i].len = file_info.uncompressed_size;
Expand Down Expand Up @@ -2264,7 +2236,7 @@ static const char **FS_ListFilteredFiles( const char *path, const char *extensio
pak = search->pack;
buildBuffer = pak->buildBuffer;
for (i = 0; i < pak->numfiles; i++) {
char *name;
const char *name;
int zpathLen, depth;

// check for directory match
Expand Down Expand Up @@ -3053,6 +3025,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass
if (!found) {
// server has no interest in the file
unzClose(pak->handle);
Z_Free((void *)pak->buildBuffer->name);
Z_Free(pak->buildBuffer);
Z_Free(pak);
continue;
Expand Down Expand Up @@ -3304,6 +3277,7 @@ void FS_Shutdown( qboolean closemfp, qboolean keepModuleFiles ) {

if ( p->pack ) {
unzClose(p->pack->handle);
Z_Free( (void *)p->pack->buildBuffer->name );
Z_Free( p->pack->buildBuffer );
Z_Free( p->pack );
}
Expand Down
166 changes: 166 additions & 0 deletions src/qcommon/msg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1900,6 +1900,165 @@ void MSG_ReadDeltaPlayerstate(msg_t *msg, playerState_t *from, playerState_t *to
}
}

// Huffman code data structure serialization

#pragma pack(push, 1)
typedef struct {
int16_t left, right, parent;
int16_t symbol;
} huffNodeData_t;

typedef struct {
int16_t tree;
int16_t loc[HMAX+1];

huffNodeData_t nodeList[768];
} huffData_t;
#pragma pack(pop)

static void Huff_SerializeEndiannessHelper(huffData_t *huffdat) {
huffdat->tree = LittleShort(huffdat->tree);

for (int i = 0; i < (int)ARRAY_LEN(huffdat->loc); i++) {
huffdat->loc[i] = LittleShort(huffdat->loc[i]);
}

for (int i = 0; i < (int)ARRAY_LEN(huffdat->nodeList); i++) {
huffNodeData_t *nodedat = &huffdat->nodeList[i];

nodedat->left = LittleShort(nodedat->left);
nodedat->right = LittleShort(nodedat->right);
nodedat->parent = LittleShort(nodedat->parent);
nodedat->symbol = LittleShort(nodedat->symbol);
}
}

void Huff_Serialize(huffData_t *huffdat, const huff_t *huff) {
#define HUFF_SERIALIZE_NODEREF(noderef) ((noderef) ? (int16_t)((noderef) - huff->nodeList) : -1)

huffdat->tree = HUFF_SERIALIZE_NODEREF(huff->tree);

for (int i = 0; i < (int)ARRAY_LEN(huffdat->loc); i++) {
huffdat->loc[i] = HUFF_SERIALIZE_NODEREF(huff->loc[i]);
}

for (int i = 0; i < (int)ARRAY_LEN(huffdat->nodeList); i++) {
huffNodeData_t *nodedat = &huffdat->nodeList[i];
const node_t *node = &huff->nodeList[i];

nodedat->left = HUFF_SERIALIZE_NODEREF(node->left);
nodedat->right = HUFF_SERIALIZE_NODEREF(node->right);
nodedat->parent = HUFF_SERIALIZE_NODEREF(node->parent);
nodedat->symbol = node->symbol;
}

Huff_SerializeEndiannessHelper(huffdat);
}

void Huff_Deserialize(huffData_t *huffdat, huff_t *huff) {
#define HUFF_DESERIALIZE_NODEREF(noderef) ((noderef) == -1 ? NULL : &huff->nodeList[noderef])

Huff_SerializeEndiannessHelper(huffdat);

huff->tree = HUFF_DESERIALIZE_NODEREF(huffdat->tree);

for (int i = 0; i < (int)ARRAY_LEN(huff->loc); i++) {
huff->loc[i] = HUFF_DESERIALIZE_NODEREF(huffdat->loc[i]);
}

for (int i = 0; i < (int)ARRAY_LEN(huff->nodeList); i++) {
const huffNodeData_t *nodedat = &huffdat->nodeList[i];
node_t *node = &huff->nodeList[i];

node->left = HUFF_DESERIALIZE_NODEREF(nodedat->left);
node->right = HUFF_DESERIALIZE_NODEREF(nodedat->right);
node->parent = HUFF_DESERIALIZE_NODEREF(nodedat->parent);
node->symbol = nodedat->symbol;
}
}

#define HUFF_DATA_VERSION 1

void Huff_SaveData(const huffman_t *huffman, const char *filename) {
huffData_t huffdata;
unsigned checksum;
fileHandle_t fp = 0;

fp = FS_SV_FOpenFileWrite(filename);

if (!fp) {
Com_DPrintf("Failed to save huffman data to %s", filename);
return;
}

byte version = HUFF_DATA_VERSION;
FS_Write(&version, sizeof(version), fp);

Huff_Serialize(&huffdata, &huffman->compressor);
FS_Write(&huffdata, sizeof(huffdata), fp);
checksum = LittleLong(Com_BlockChecksum(&huffdata, sizeof(huffdata)));
FS_Write(&checksum, sizeof(checksum), fp);

Huff_Serialize(&huffdata, &huffman->decompressor);
FS_Write(&huffdata, sizeof(huffdata), fp);
checksum = LittleLong(Com_BlockChecksum(&huffdata, sizeof(huffdata)));
FS_Write(&checksum, sizeof(checksum), fp);

FS_FCloseFile(fp);
}

qboolean Huff_ReadData(huffman_t *huffman, const char *filename) {
huffData_t huffdata;
unsigned checksum;
byte version;
fileHandle_t fp = 0;

FS_SV_FOpenFileRead(filename, &fp);

if (!fp) {
Com_DPrintf("Failed to open huffman data from %s\n", filename);
return qfalse;
}

if (FS_Read(&version, sizeof(version), fp) != (int)sizeof(version))
goto corrupted;

if (version != HUFF_DATA_VERSION) {
Com_DPrintf("Huffman data in %s has incompatible version\n", filename);
return qfalse;
}

memset(&huffman->compressor, 0, sizeof(huff_t));
memset(&huffman->decompressor, 0, sizeof(huff_t));

if (FS_Read(&huffdata, sizeof(huffdata), fp) != (int)sizeof(huffdata))
goto corrupted;
if (FS_Read(&checksum, sizeof(checksum), fp) != (int)sizeof(checksum))
goto corrupted;
checksum = LittleLong(checksum);
if (checksum != Com_BlockChecksum(&huffdata, sizeof(huffdata))) {
Com_Printf(S_COLOR_YELLOW "WARNING: %s checksum mismatch - recalculating Huffman code...", filename);
return qfalse;
}
Huff_Deserialize(&huffdata, &huffman->compressor);

if (FS_Read(&huffdata, sizeof(huffdata), fp) != (int)sizeof(huffdata))
goto corrupted;
if (FS_Read(&checksum, sizeof(checksum), fp) != (int)sizeof(checksum))
goto corrupted;
checksum = LittleLong(checksum);
if (checksum != Com_BlockChecksum(&huffdata, sizeof(huffdata))) {
Com_Printf(S_COLOR_YELLOW "WARNING: %s checksum mismatch - recalculating Huffman code...", filename);
return qfalse;
}
Huff_Deserialize(&huffdata, &huffman->decompressor);

return qtrue;
corrupted:
Com_Printf(S_COLOR_YELLOW "WARNING: %s corrupted - recalculating Huffman code...\n", filename);
return qfalse;
}

/*
// New data gathered to tune Q3 to JK2MP. Takes longer to crunch and gain was minimal.
int msg_hData[256] =
Expand Down Expand Up @@ -2428,6 +2587,11 @@ static const int msg_hData[256] = {
void MSG_initHuffman() {
int i, j;

if (Huff_ReadData(&msgHuff, "huffman.dat")) {
msgInit = qtrue;
return;
}

#ifdef _NEWHUFFTABLE_
fp = fopen("c:\\netchan.bin", "a");
#endif // _NEWHUFFTABLE_
Expand All @@ -2440,6 +2604,8 @@ void MSG_initHuffman() {
Huff_addRef(&msgHuff.decompressor, (byte)i); // Do update
}
}

Huff_SaveData(&msgHuff, "huffman.dat");
}

#else
Expand Down
7 changes: 6 additions & 1 deletion src/qcommon/qcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ unsigned Com_BlockChecksum( const void *buffer, int length );
unsigned Com_BlockChecksumKey (void *buffer, int length, int key);
int Com_HashKey(const char *string, int maxlen);
int Com_Filter(const char *filter, const char *name, int casesensitive);
int Com_FilterPath(char *filter, char *name, int casesensitive);
int Com_FilterPath(char *filter, const char *name, int casesensitive);
int Com_RealTime(qtime_t *qtime);
qboolean Com_SafeMode( void );
void Com_RunAndTimeServerPacket(netadr_t *evFrom, msg_t *buf);
Expand Down Expand Up @@ -1027,6 +1027,11 @@ typedef struct {
node_t* lhead;
node_t* ltail;
node_t* loc[HMAX+1];
// freelist is a head of linked list of nodePtrs
// elements. nodePtrs element type is overloaded and may hold
// node_t* pointer pointing to nodeList element or node_t**
// pointer pointing to another nodePtrs element when part of
// freelist!
node_t** freelist;

node_t nodeList[768];
Expand Down
7 changes: 6 additions & 1 deletion src/renderer/tr_WorldEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,17 @@ CMistyFog::CMistyFog(int index, CWorldEffect *owner, bool buddy) :
}
else
{
pixelFormat_t format;
Com_sprintf(name, MAX_QPATH, "gfx/world/fog%d", index);
R_LoadImage(name, &mData, &mWidth, &mHeight);
R_LoadImage(name, &mData, &mWidth, &mHeight, &format);
if (!mData)
{
ri.Error (ERR_DROP, "Could not load %s", name);
}
if (format != PXF_RGBA)
{
ri.Error (ERR_DROP, "Fog image must be RGBA %s", name);
}

mRendering = true;
AddSlave(new CMistyFog(index, this, true));
Expand Down
Loading
Loading