java-topology/defects/xonotic-0001/patch/xonotic-0001.patch

60 lines
2.6 KiB
Diff

# UNDF: UNDF-2026-000000989
--- a/model_shared.c
+++ b/model_shared.c
@@ -4473,12 +4473,36 @@ void Mod_Mesh_Restart(model_t *mod)
mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
}
+// Hash table for Mod_Mesh_GetTexture to avoid O(T) linear scan per draw call.
+// Key: texture name + drawflag + texflags + materialflags, Value: texture index.
+#define MOD_MESH_TEX_HASHSIZE 256
+static unsigned Mod_Mesh_TexHashKey(const char *name, int drawflag, int texflags, int materialflags)
+{
+ unsigned hash = 0;
+ const unsigned char *p;
+ for (p = (const unsigned char *)name; *p; p++)
+ hash = hash * 31 + *p;
+ hash ^= (unsigned)drawflag * 2654435761u;
+ hash ^= (unsigned)texflags * 2246822519u;
+ hash ^= (unsigned)materialflags * 3266489917u;
+ return hash % MOD_MESH_TEX_HASHSIZE;
+}
+
texture_t *Mod_Mesh_GetTexture(model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
{
- int i;
- texture_t *t;
+ int i, hashkey;
+ texture_t *t, *oldtextures;
int drawflag = defaultdrawflags & DRAWFLAG_MASK;
- for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++)
+
+ // Use hash table for O(1) average lookup instead of O(T) linear scan.
+ // This function is called per draw call (every quad, character, image),
+ // so O(T) was a per-frame bottleneck scaling with texture count.
+ hashkey = Mod_Mesh_TexHashKey(name, drawflag, defaulttexflags, defaultmaterialflags);
+ for (i = mod->mesh_texture_hashtable[hashkey]; i >= 0; i = mod->mesh_texture_hashnext[i])
+ {
+ t = &mod->data_textures[i];
+ if (!strcmp(t->name, name) && t->mesh_drawflag == drawflag && t->mesh_defaulttexflags == defaulttexflags && t->mesh_defaultmaterialflags == defaultmaterialflags)
+ return t;
+ }
+
+ // Fallback: linear scan for textures not yet in hash table (should not happen)
+ for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++)
if (!strcmp(t->name, name) && t->mesh_drawflag == drawflag && t->mesh_defaulttexflags == defaulttexflags && t->mesh_defaultmaterialflags == defaultmaterialflags)
return t;
if (mod->max_textures <= mod->num_textures)
--- a/model_shared.h
+++ b/model_shared.h
@@ -428,6 +428,10 @@ typedef struct model_s
int max_textures; // preallocated for expansion (Mod_Mesh_GetTexture)
int num_textures;
texture_t *data_textures;
+ // Hash table for Mod_Mesh_GetTexture O(1) lookup.
+ // mesh_texture_hashtable[hashkey] = first texture index, -1 if empty.
+ int mesh_texture_hashtable[256];
+ int *mesh_texture_hashnext; // per-texture chain, -1 = end
int num_surfaces;
int max_surfaces; // preallocated for expansion (Mod_Mesh_AddSurface)
msurface_t *data_surfaces;