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.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
#include "quakedef.h"
-model_t *loadmodel;
-char loadname[32]; // for hunk tags
+model_t *loadmodel;
-extern void Mod_LoadSpriteModel (model_t *mod, void *buffer);
-extern void Mod_LoadBrushModel (model_t *mod, void *buffer);
-extern void Mod_LoadAliasModel (model_t *mod, void *buffer);
-extern void Mod_LoadQ2AliasModel (model_t *mod, void *buffer);
-extern void Mod_LoadZymoticModel (model_t *mod, void *buffer);
-model_t *Mod_LoadModel (model_t *mod, qboolean crash);
+// LordHavoc: increased from 512 to 2048
+#define MAX_MOD_KNOWN 2048
+static model_t mod_known[MAX_MOD_KNOWN];
-#define MAX_MOD_KNOWN 512
-model_t mod_known[MAX_MOD_KNOWN];
-int mod_numknown;
+static void mod_start(void)
+{
+ int i;
+ for (i = 0;i < MAX_MOD_KNOWN;i++)
+ if (mod_known[i].name[0])
+ Mod_UnloadModel(&mod_known[i]);
+}
-extern void Mod_BrushInit();
-extern void Mod_AliasInit();
-extern void Mod_SpriteInit();
+static void mod_shutdown(void)
+{
+ int i;
+ for (i = 0;i < MAX_MOD_KNOWN;i++)
+ if (mod_known[i].name[0])
+ Mod_UnloadModel(&mod_known[i]);
+}
+
+static void mod_newmap(void)
+{
+}
/*
===============
Mod_Init
===============
*/
+static void Mod_Print (void);
+static void Mod_Flush (void);
void Mod_Init (void)
{
Mod_BrushInit();
Mod_AliasInit();
Mod_SpriteInit();
+
+ Cmd_AddCommand ("modellist", Mod_Print);
+ Cmd_AddCommand ("modelflush", Mod_Flush);
+}
+
+void Mod_RenderInit(void)
+{
+ R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap);
+}
+
+void Mod_FreeModel (model_t *mod)
+{
+ R_FreeTexturePool(&mod->texturepool);
+ Mem_FreePool(&mod->mempool);
+
+ // clear the struct to make it available
+ memset(mod, 0, sizeof(model_t));
+}
+
+void Mod_UnloadModel (model_t *mod)
+{
+ char name[MAX_QPATH];
+ qboolean isworldmodel;
+ strcpy(name, mod->name);
+ isworldmodel = mod->isworldmodel;
+ Mod_FreeModel(mod);
+ strcpy(mod->name, name);
+ mod->isworldmodel = isworldmodel;
+ mod->needload = true;
}
/*
-===============
-Mod_Init
+==================
+Mod_LoadModel
-Caches the data if needed
-===============
+Loads a model
+==================
*/
-void *Mod_Extradata (model_t *mod)
+static model_t *Mod_LoadModel (model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
{
- void *r;
-
- r = Cache_Check (&mod->cache);
- if (r)
- return r;
-
- Mod_LoadModel (mod, true);
-
- if (!mod->cache.data)
- Host_Error ("Mod_Extradata: caching failed");
- return mod->cache.data;
+ int crc;
+ void *buf;
+
+ mod->used = true;
+
+ if (mod->name[0] == '*') // submodel
+ return mod;
+
+ crc = 0;
+ buf = NULL;
+ if (!mod->needload)
+ {
+ if (checkdisk)
+ {
+ buf = COM_LoadFile (mod->name, false);
+ if (!buf)
+ {
+ if (crash)
+ Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
+ return NULL;
+ }
+
+ crc = CRC_Block(buf, com_filesize);
+ }
+ else
+ crc = mod->crc;
+
+ if (mod->crc == crc && mod->isworldmodel == isworldmodel)
+ {
+ if (buf)
+ Mem_Free(buf);
+ return mod; // already loaded
+ }
+ }
+
+ Con_DPrintf("loading model %s\n", mod->name);
+
+ if (!buf)
+ {
+ buf = COM_LoadFile (mod->name, false);
+ if (!buf)
+ {
+ if (crash)
+ Host_Error ("Mod_LoadModel: %s not found", mod->name);
+ return NULL;
+ }
+ crc = CRC_Block(buf, com_filesize);
+ }
+
+ // make sure nothing got trashed
+ //Mem_CheckSentinelsGlobal();
+
+ // allocate a new model
+ loadmodel = mod;
+
+ // LordHavoc: unload the existing model in this slot (if there is one)
+ Mod_UnloadModel(mod);
+ mod->isworldmodel = isworldmodel;
+ mod->needload = false;
+ mod->used = true;
+ mod->crc = crc;
+
+ // all models use memory, so allocate a memory pool
+ mod->mempool = Mem_AllocPool(mod->name);
+ // all models load textures, so allocate a texture pool
+ if (cls.state != ca_dedicated)
+ mod->texturepool = R_AllocTexturePool();
+
+ // call the apropriate loader
+ if (!memcmp(buf, "IDPO" , 4)) Mod_LoadAliasModel (mod, buf);
+ else if (!memcmp(buf, "IDP2" , 4)) Mod_LoadQ2AliasModel(mod, buf);
+ else if (!memcmp(buf, "ZYMOTIC" , 7)) Mod_LoadZymoticModel(mod, buf);
+ else if (!memcmp(buf, "IDSP" , 4)) Mod_LoadSpriteModel (mod, buf);
+ else Mod_LoadBrushModel (mod, buf);
+
+ Mem_Free(buf);
+
+ // make sure nothing got trashed
+ //Mem_CheckSentinelsGlobal();
+
+ return mod;
+}
+
+void Mod_CheckLoaded (model_t *mod)
+{
+ if (mod)
+ {
+ if (mod->needload)
+ Mod_LoadModel(mod, true, true, mod->isworldmodel);
+ else
+ {
+ if (mod->type == mod_invalid)
+ Host_Error("Mod_CheckLoaded: invalid model\n");
+ mod->used = true;
+ return;
+ }
+ }
}
/*
===================
*/
void Mod_ClearAll (void)
+{
+ /*
+ int i;
+ model_t *mod;
+
+ for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ if (mod->name[0])
+ if (mod->usesheap)
+ Mod_FreeModel(mod);
+ */
+}
+
+void Mod_ClearUsed(void)
{
int i;
model_t *mod;
-
- for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
- if (mod->type != mod_alias)
- mod->needload = true;
+
+ for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ if (mod->name[0])
+ mod->used = false;
+}
+
+void Mod_PurgeUnused(void)
+{
+ int i;
+ model_t *mod;
+
+ for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ if (mod->name[0])
+ if (!mod->used)
+ Mod_FreeModel(mod);
}
/*
model_t *Mod_FindName (char *name)
{
int i;
- model_t *mod;
-
+ model_t *mod, *freemod;
+
if (!name[0])
Host_Error ("Mod_ForName: NULL name");
-
-//
+
// search the currently loaded models
-//
- for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
- if (!strcmp (mod->name, name) )
- break;
-
- if (i == mod_numknown)
+ freemod = NULL;
+ for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
{
- if (mod_numknown == MAX_MOD_KNOWN)
- Host_Error ("mod_numknown == MAX_MOD_KNOWN");
+ if (mod->name[0])
+ {
+ if (!strcmp (mod->name, name))
+ {
+ mod->used = true;
+ return mod;
+ }
+ }
+ else if (freemod == NULL)
+ freemod = mod;
+ }
+
+ if (freemod)
+ {
+ mod = freemod;
strcpy (mod->name, name);
mod->needload = true;
- mod_numknown++;
+ mod->used = true;
+ return mod;
}
- return mod;
+ Host_Error ("Mod_FindName: ran out of models\n");
+ return NULL;
}
/*
void Mod_TouchModel (char *name)
{
model_t *mod;
-
- mod = Mod_FindName (name);
-
- if (!mod->needload)
- {
- if (mod->type == mod_alias)
- Cache_Check (&mod->cache);
- }
-}
-
-/*
-==================
-Mod_LoadModel
-Loads a model into the cache
-==================
-*/
-model_t *Mod_LoadModel (model_t *mod, qboolean crash)
-{
- void *d;
- unsigned *buf;
-
- if (!mod->needload)
- {
- if (mod->type == mod_alias)
- {
- d = Cache_Check (&mod->cache);
- if (d)
- return mod;
- }
- else
- return mod; // not cached at all
- }
-
- Con_DPrintf("loading model %s\n", mod->name);
-
-// load the file
- buf = (unsigned *)COM_LoadMallocFile (mod->name, false);
- if (!buf)
- {
- if (crash)
- Host_Error ("Mod_NumForName: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
- return NULL;
- }
-
-// allocate a new model
- COM_FileBase (mod->name, loadname);
-
- loadmodel = mod;
-
-// call the apropriate loader
- mod->needload = false;
-
- switch (LittleLong(*(unsigned *)buf))
- {
- case IDPOLYHEADER:
- Mod_LoadAliasModel (mod, buf);
- break;
-
- case MD2IDALIASHEADER: // LordHavoc: added Quake2 model support
- Mod_LoadQ2AliasModel (mod, buf);
- break;
-
- case (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'):
- Mod_LoadZymoticModel(mod, buf);
- break;
-
- case IDSPRITEHEADER:
- Mod_LoadSpriteModel (mod, buf);
- break;
-
- default:
- Mod_LoadBrushModel (mod, buf);
- break;
- }
- qfree(buf);
-
- return mod;
+ mod = Mod_FindName (name);
+ mod->used = true;
}
/*
Loads in a model for the given name
==================
*/
-model_t *Mod_ForName (char *name, qboolean crash)
+model_t *Mod_ForName (char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
{
- model_t *mod;
-
- mod = Mod_FindName (name);
-
- return Mod_LoadModel (mod, crash);
+ return Mod_LoadModel (Mod_FindName (name), crash, checkdisk, isworldmodel);
}
-byte *mod_base;
+qbyte *mod_base;
/*
=================
RadiusFromBounds
=================
*/
+/*
float RadiusFromBounds (vec3_t mins, vec3_t maxs)
{
int i;
return Length (corner);
}
+*/
//=============================================================================
Mod_Print
================
*/
-void Mod_Print (void)
+static void Mod_Print (void)
{
int i;
model_t *mod;
- Con_Printf ("Cached models:\n");
- for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
- {
- Con_Printf ("%8p : %s\n",mod->cache.data, mod->name);
- }
+ Con_Printf ("Loaded models:\n");
+ for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+ if (mod->name[0])
+ Con_Printf ("%4iK %s\n", mod->mempool ? (mod->mempool->totalsize + 1023) / 1024 : 0, mod->name);
}
+static void Mod_Flush (void)
+{
+ int i;
+
+ Con_Printf ("Unloading models\n");
+ for (i = 0;i < MAX_MOD_KNOWN;i++)
+ if (mod_known[i].name[0])
+ Mod_UnloadModel(&mod_known[i]);
+}