60 lines
2.6 KiB
Diff
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;
|