#include "quakedef.h" enum { // values for model_t's needload NL_PRESENT, NL_NEEDS_LOADED, NL_UNREFERENCED, MAX_MOD_KNOWN = 4096,}; static char loadname[32]; // for hunk tagsstatic model_t *mod_known;static int mod_numknown; static model_t *Mod_LoadModel(model_t *mod, bool crash); voidMod_Init(void){ mod_known = Hunk_Alloc(MAX_MOD_KNOWN * sizeof(*mod_known));} /* Caches the data if needed */void *Mod_Extradata(model_t *mod){ void *r; if((r = Cache_Check(&mod->cache)) != nil) return r; Mod_LoadModel(mod, true); if(!mod->cache.data) Host_Error("Mod_Extradata: caching failed: %s", mod->name); return mod->cache.data;} mleaf_t *Mod_PointInLeaf(const vec3_t p, model_t *model){ mnode_t *node; float d; mplane_t *plane; if(!model || !model->nodes) Host_Error("Mod_PointInLeaf: bad model"); node = model->nodes; while(1) { if(node->contents < 0) return (mleaf_t *)node; plane = node->plane; d = DotProduct(p, plane->normal) - plane->dist; node = node->children[d <= 0]; }} static byte *Mod_DecompressVis(byte *in, model_t *model, int *outsz){ static byte *decompressed; static int decompressed_size; int c; byte *out; int row; row = (model->numleafs + 7) / 8; if(decompressed == nil || row > decompressed_size) { decompressed_size = row; decompressed = realloc(decompressed, decompressed_size); } out = decompressed; *outsz = row; if(!in) { // no vis info, so make all visible memset(out, 0xff, row); return decompressed; } do { if(*in) { *out++ = *in++; continue; } c = in[1]; in += 2; while(c && out - decompressed < row) { *out++ = 0; c--; } } while(out - decompressed < row); return decompressed;} byte *Mod_LeafPVS(mleaf_t *leaf, model_t *model, int *outsz){ static byte *mod_novis; static int mod_novis_size; int sz; sz = ((model->numleafs + 7) / 8 + 3) & ~3; *outsz = sz; if(leaf == model->leafs) { if(mod_novis == nil || mod_novis_size < sz) { mod_novis = realloc(mod_novis, sz); mod_novis_size = sz; } memset(mod_novis, 0xff, mod_novis_size); return mod_novis; } return Mod_DecompressVis(leaf->compressed_vis, model, outsz);} voidMod_ClearAll(void){ int i; model_t *mod; for(i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { mod->needload = NL_UNREFERENCED; // FIX FOR CACHE_ALLOC ERRORS: if(mod->type == mod_sprite) mod->cache.data = nil; }} model_t *Mod_FindName(const char *name){ int i; model_t *mod, *avail = nil; if(!name[0]) Host_Error("Mod_FindName: nil name"); // search the currently loaded models for(i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { if(strcmp(mod->name, name) == 0) break; if(mod->needload == NL_UNREFERENCED) if(!avail || mod->type != mod_alias) avail = mod; } if(i == mod_numknown) { if(mod_numknown == MAX_MOD_KNOWN) { if(avail) { mod = avail; if(mod->type == mod_alias) if(Cache_Check(&mod->cache)) Cache_Free(&mod->cache); } else Host_Error("mod_numknown == MAX_MOD_KNOWN"); } else mod_numknown++; strcpy(mod->name, name); mod->needload = NL_NEEDS_LOADED; } return mod;} voidMod_TouchModel(const char *name){ model_t *mod; mod = Mod_FindName(name); if(mod->needload == NL_PRESENT) { if(mod->type == mod_alias) Cache_Check(&mod->cache); }} static model_t *Mod_LoadModel(model_t *mod, bool crash){ byte *buf; int len; if(mod->type == mod_alias) { if(Cache_Check(&mod->cache)) { mod->needload = NL_PRESENT; return mod; } } else if(mod->needload == NL_PRESENT) return mod; // because the world is so huge, load it one piece at a time if((buf = loadstklmp(mod->name, nil, 0, &len)) == nil) { if(crash) Host_Error("Mod_LoadModel: %s", lerr()); return nil; } // allocate a new model radix(mod->name, loadname); // fill it in mod->lmpfrom = fs_lmpfrom; // call the apropriate loader mod->needload = NL_PRESENT; switch(LittleLong(*(unsigned *)buf)) { case IDPOLYHEADER: Mod_LoadAliasModel(mod, buf); break; case IDSPRITEHEADER: Mod_LoadSpriteModel(mod, buf, len); break; default: Mod_LoadBrushModel(mod, buf, len); break; } return mod;} model_t *Mod_ForName(const char *name, bool crash){ return Mod_LoadModel(Mod_FindName(name), crash);} voidMod_Print_f(cmd_t *c){ int i; model_t *mod; USED(c); Con_Printf("Cached models:\n"); for(i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { Con_Printf("%8p : %s", mod->cache.data, mod->name); if(mod->needload & NL_UNREFERENCED) Con_Printf(" (!R)"); if(mod->needload & NL_NEEDS_LOADED) Con_Printf(" (!P)"); Con_Printf("\n"); }}
#include "quakedef.h"
enum {
// values for model_t's needload
NL_PRESENT,
NL_NEEDS_LOADED,
NL_UNREFERENCED,
MAX_MOD_KNOWN = 4096,
};
static char loadname[32]; // for hunk tags
static model_t *mod_known;
static int mod_numknown;
static model_t *Mod_LoadModel(model_t *mod, bool crash);
void
Mod_Init(void)
{
mod_known = Hunk_Alloc(MAX_MOD_KNOWN * sizeof(*mod_known));
}
/* Caches the data if needed */
void *
Mod_Extradata(model_t *mod)
{
void *r;
if((r = Cache_Check(&mod->cache)) != nil)
return r;
Mod_LoadModel(mod, true);
if(!mod->cache.data)
Host_Error("Mod_Extradata: caching failed: %s", mod->name);
return mod->cache.data;
}
mleaf_t *
Mod_PointInLeaf(const vec3_t p, model_t *model)
{
mnode_t *node;
float d;
mplane_t *plane;
if(!model || !model->nodes)
Host_Error("Mod_PointInLeaf: bad model");
node = model->nodes;
while(1) {
if(node->contents < 0)
return (mleaf_t *)node;
plane = node->plane;
d = DotProduct(p, plane->normal) - plane->dist;
node = node->children[d <= 0];
}
}
static byte *
Mod_DecompressVis(byte *in, model_t *model, int *outsz)
{
static byte *decompressed;
static int decompressed_size;
int c;
byte *out;
int row;
row = (model->numleafs + 7) / 8;
if(decompressed == nil || row > decompressed_size) {
decompressed_size = row;
decompressed = realloc(decompressed, decompressed_size);
}
out = decompressed;
*outsz = row;
if(!in) { // no vis info, so make all visible
memset(out, 0xff, row);
return decompressed;
}
do {
if(*in) {
*out++ = *in++;
continue;
}
c = in[1];
in += 2;
while(c && out - decompressed < row) {
*out++ = 0;
c--;
}
} while(out - decompressed < row);
return decompressed;
}
byte *
Mod_LeafPVS(mleaf_t *leaf, model_t *model, int *outsz)
{
static byte *mod_novis;
static int mod_novis_size;
int sz;
sz = ((model->numleafs + 7) / 8 + 3) & ~3;
*outsz = sz;
if(leaf == model->leafs) {
if(mod_novis == nil || mod_novis_size < sz) {
mod_novis = realloc(mod_novis, sz);
mod_novis_size = sz;
}
memset(mod_novis, 0xff, mod_novis_size);
return mod_novis;
}
return Mod_DecompressVis(leaf->compressed_vis, model, outsz);
}
void
Mod_ClearAll(void)
{
int i;
model_t *mod;
for(i = 0, mod = mod_known; i < mod_numknown; i++, mod++) {
mod->needload = NL_UNREFERENCED;
// FIX FOR CACHE_ALLOC ERRORS:
if(mod->type == mod_sprite)
mod->cache.data = nil;
}
}
model_t *
Mod_FindName(const char *name)
{
int i;
model_t *mod, *avail = nil;
if(!name[0])
Host_Error("Mod_FindName: nil name");
// search the currently loaded models
for(i = 0, mod = mod_known; i < mod_numknown; i++, mod++) {
if(strcmp(mod->name, name) == 0)
break;
if(mod->needload == NL_UNREFERENCED)
if(!avail || mod->type != mod_alias)
avail = mod;
}
if(i == mod_numknown) {
if(mod_numknown == MAX_MOD_KNOWN) {
if(avail) {
mod = avail;
if(mod->type == mod_alias)
if(Cache_Check(&mod->cache))
Cache_Free(&mod->cache);
} else
Host_Error("mod_numknown == MAX_MOD_KNOWN");
} else
mod_numknown++;
strcpy(mod->name, name);
mod->needload = NL_NEEDS_LOADED;
}
return mod;
}
void
Mod_TouchModel(const char *name)
{
model_t *mod;
mod = Mod_FindName(name);
if(mod->needload == NL_PRESENT) {
if(mod->type == mod_alias)
Cache_Check(&mod->cache);
}
}
static model_t *
Mod_LoadModel(model_t *mod, bool crash)
{
byte *buf;
int len;
if(mod->type == mod_alias) {
if(Cache_Check(&mod->cache)) {
mod->needload = NL_PRESENT;
return mod;
}
} else if(mod->needload == NL_PRESENT)
return mod;
// because the world is so huge, load it one piece at a time
if((buf = loadstklmp(mod->name, nil, 0, &len)) == nil) {
if(crash)
Host_Error("Mod_LoadModel: %s", lerr());
return nil;
}
// allocate a new model
radix(mod->name, loadname);
// fill it in
mod->lmpfrom = fs_lmpfrom;
// call the apropriate loader
mod->needload = NL_PRESENT;
switch(LittleLong(*(unsigned *)buf)) {
case IDPOLYHEADER:
Mod_LoadAliasModel(mod, buf);
break;
case IDSPRITEHEADER:
Mod_LoadSpriteModel(mod, buf, len);
break;
default:
Mod_LoadBrushModel(mod, buf, len);
break;
}
return mod;
}
model_t *
Mod_ForName(const char *name, bool crash)
{
return Mod_LoadModel(Mod_FindName(name), crash);
}
void
Mod_Print_f(cmd_t *c)
{
int i;
model_t *mod;
USED(c);
Con_Printf("Cached models:\n");
for(i = 0, mod = mod_known; i < mod_numknown; i++, mod++) {
Con_Printf("%8p : %s", mod->cache.data, mod->name);
if(mod->needload & NL_UNREFERENCED)
Con_Printf(" (!R)");
if(mod->needload & NL_NEEDS_LOADED)
Con_Printf(" (!P)");
Con_Printf("\n");
}
}