]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
[xonotic/darkplaces.git] / model_shared.c
index 6209ace388328f1c5d0ef7b8ea6b2d2158906a88..d892a36d3b5aeac9dc9640e41a196677e99af3bc 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 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.
 
@@ -25,45 +25,180 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 
 model_t        *loadmodel;
-char   loadname[32];   // for hunk tags
 
 // LordHavoc: increased from 512 to 2048
 #define        MAX_MOD_KNOWN   2048
 model_t        mod_known[MAX_MOD_KNOWN];
-int            mod_numknown;
+
+void mod_start()
+{
+       int i;
+       for (i = 0;i < MAX_MOD_KNOWN;i++)
+               if (mod_known[i].name[0])
+                       Mod_UnloadModel(&mod_known[i]);
+}
+
+void mod_shutdown()
+{
+       int i;
+       for (i = 0;i < MAX_MOD_KNOWN;i++)
+               if (mod_known[i].name[0])
+                       Mod_UnloadModel(&mod_known[i]);
+}
+
+void mod_newmap()
+{
+}
 
 /*
 ===============
 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;
+       int crc;
+       void *buf;
+       char tempname[MAX_QPATH];
+
+       mod->used = true;
+
+       if (mod->name[0] == '*') // submodel
+               return mod;
 
-       r = Cache_Check (&mod->cache);
-       if (r)
-               return r;
+       if (checkdisk)
+       {
+               // load the file
+               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;
+               }
 
-       Mod_LoadModel (mod, true);
+               crc = CRC_Block(buf, com_filesize);
 
-       if (!mod->cache.data)
-               Host_Error ("Mod_Extradata: caching failed");
-       return mod->cache.data;
+               if (!mod->needload && mod->crc == crc && mod->isworldmodel == isworldmodel)
+               {
+                       Mem_Free(buf);
+                       return mod; // already loaded
+               }
+
+               Con_DPrintf("loading model %s\n", mod->name);
+       }
+       else
+       {
+               if (!mod->needload && mod->isworldmodel == isworldmodel)
+                       return mod; // already loaded
+
+               Con_DPrintf("loading model %s\n", mod->name);
+
+               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);
+       }
+
+       // make sure nothing got trashed
+       Mem_CheckSentinelsGlobal();
+
+       // allocate a new model
+       loadmodel = mod;
+
+       // LordHavoc: clear the model struct
+       strcpy(tempname, mod->name);
+       Mod_FreeModel(mod);
+
+       strcpy(mod->name, tempname);
+       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
+       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)
+               {
+                       if (mod->type == mod_invalid)
+                               Host_Error("Mod_CheckLoaded: invalid model\n");
+                       mod->used = true;
+                       return;
+               }
+
+               Mod_LoadModel(mod, true, true, mod->isworldmodel);
+       }
 }
 
 /*
@@ -73,12 +208,36 @@ Mod_ClearAll
 */
 void Mod_ClearAll (void)
 {
+       /*
        int             i;
        model_t *mod;
 
-       for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
-               if (!mod->cachesize)
-                       mod->needload = true;
+       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 < 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);
 }
 
 /*
@@ -90,28 +249,38 @@ Mod_FindName
 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;
+       freemod = NULL;
+       for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
+       {
+               if (mod->name[0])
+               {
+                       if (!strcmp (mod->name, name))
+                       {
+                               mod->used = true;
+                               return mod;
+                       }
+               }
+               else if (freemod == NULL)
+                       freemod = mod;
+       }
 
-       if (i == mod_numknown)
+       if (freemod)
        {
-               if (mod_numknown == MAX_MOD_KNOWN)
-                       Host_Error ("mod_numknown == MAX_MOD_KNOWN");
+               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;
 }
 
 /*
@@ -125,85 +294,7 @@ void Mod_TouchModel (char *name)
        model_t *mod;
 
        mod = Mod_FindName (name);
-
-       if (!mod->needload)
-               if (mod->cachesize)
-                       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->cachesize)
-               {
-                       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);
-       strcpy(loadname, mod->name);
-
-       loadmodel = mod;
-
-// call the apropriate loader
-       mod->needload = false;
-
-       // LordHavoc: clear some important stuff in the model_t structure
-       mod->flags = 0;
-       mod->flags2 = 0;
-
-       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->used = true;
 }
 
 /*
@@ -213,13 +304,14 @@ Mod_ForName
 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);
+       mod->used = true;
+
+       return Mod_LoadModel (mod, crash, checkdisk, isworldmodel);
 }
 
 byte   *mod_base;
@@ -229,6 +321,7 @@ byte        *mod_base;
 RadiusFromBounds
 =================
 */
+/*
 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
 {
        int             i;
@@ -239,6 +332,7 @@ float RadiusFromBounds (vec3_t mins, vec3_t maxs)
 
        return Length (corner);
 }
+*/
 
 //=============================================================================
 
@@ -247,16 +341,24 @@ float RadiusFromBounds (vec3_t mins, vec3_t maxs)
 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 ("%4iK : %8p : %s\n", (mod->cachesize + 1023) / 1024, 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]);
+}