X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=model_shared.c;h=01e1e46b79964e58a68bf5d3258d8f69eb9acdd1;hb=7ab8cb14df5c1810973f39e92934e5eb3d4c5ef6;hp=9d16ee22101694e3746df9b9dd4b2959f55c32aa;hpb=8dcce44300385b12c46d494c06aadcfa35a8bc14;p=xonotic%2Fdarkplaces.git diff --git a/model_shared.c b/model_shared.c index 9d16ee22..01e1e46b 100644 --- a/model_shared.c +++ b/model_shared.c @@ -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. @@ -24,221 +24,318 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -model_t *loadmodel; -char loadname[32]; // for hunk tags +model_t *loadmodel; -void Mod_LoadSpriteModel (model_t *mod, void *buffer); -void Mod_LoadBrushModel (model_t *mod, void *buffer); -void Mod_LoadAliasModel (model_t *mod, void *buffer); -void Mod_LoadQ2AliasModel (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; +rtexture_t *r_notexture; +rtexturepool_t *r_notexturepool; -extern void Mod_BrushInit(); -extern void Mod_AliasInit(); -extern void Mod_SpriteInit(); +texture_t r_surf_notexture; + +void Mod_SetupNoTexture(void) +{ + int x, y; + qbyte pix[16][16][4]; + + // this makes a light grey/dark grey checkerboard texture + for (y = 0;y < 16;y++) + { + for (x = 0;x < 16;x++) + { + if ((y < 8) ^ (x < 8)) + { + pix[y][x][0] = 128; + pix[y][x][1] = 128; + pix[y][x][2] = 128; + pix[y][x][3] = 255; + } + else + { + pix[y][x][0] = 64; + pix[y][x][1] = 64; + pix[y][x][2] = 64; + pix[y][x][3] = 255; + } + } + } + + r_notexturepool = R_AllocTexturePool(); + r_notexture = R_LoadTexture(r_notexturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP); +} + +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]); + + Mod_SetupNoTexture(); +} + +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]); + + R_FreeTexturePool(&r_notexturepool); +} + +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); } -/* -=============== -Mod_Init +void Mod_RenderInit(void) +{ + R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap); +} -Caches the data if needed -=============== -*/ -void *Mod_Extradata (model_t *mod) +void Mod_FreeModel (model_t *mod) { - void *r; - - r = Cache_Check (&mod->cache); - if (r) - return r; - - Mod_LoadModel (mod, true); - - if (!mod->cache.data) - Sys_Error ("Mod_Extradata: caching failed"); - return mod->cache.data; + R_FreeTexturePool(&mod->texturepool); + Mem_FreePool(&mod->mempool); + + // clear the struct to make it available + memset(mod, 0, sizeof(model_t)); } -/* -=================== -Mod_ClearAll -=================== -*/ -void Mod_ClearAll (void) +void Mod_UnloadModel (model_t *mod) { - int i; - model_t *mod; - - for (i=0 , mod=mod_known ; itype != mod_alias) - mod->needload = true; + 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_FindName +Mod_LoadModel +Loads a model ================== */ -model_t *Mod_FindName (char *name) +static model_t *Mod_LoadModel (model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel) { - int i; - model_t *mod; - - if (!name[0]) - Sys_Error ("Mod_ForName: NULL name"); - -// -// search the currently loaded models -// - for (i=0 , mod=mod_known ; iname, name) ) - break; - - if (i == mod_numknown) + int crc; + void *buf; + + mod->used = true; + + if (mod->name[0] == '*') // submodel + return mod; + + crc = 0; + buf = NULL; + if (!mod->needload) { - if (mod_numknown == MAX_MOD_KNOWN) - Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); - strcpy (mod->name, name); - mod->needload = true; - mod_numknown++; + 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); + } + + // 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); + return mod; } -/* -================== -Mod_TouchModel +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; + } + } +} -================== +/* +=================== +Mod_ClearAll +=================== */ -void Mod_TouchModel (char *name) +void Mod_ClearAll (void) { +} + +void Mod_ClearUsed(void) +{ + int i; model_t *mod; - - mod = Mod_FindName (name); - - if (!mod->needload) - { - if (mod->type == mod_alias) - Cache_Check (&mod->cache); - } + + 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); } /* ================== -Mod_LoadModel +Mod_FindName -Loads a model into the cache ================== */ -model_t *Mod_LoadModel (model_t *mod, qboolean crash) +model_t *Mod_FindName (char *name) { - void *d; - unsigned *buf; - byte stackbuf[1024]; // avoid dirtying the cache heap + int i; + model_t *mod, *freemod; - if (!mod->needload) + if (!name[0]) + Host_Error ("Mod_ForName: NULL name"); + +// search the currently loaded models + freemod = NULL; + for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++) { - if (mod->type == mod_alias) + if (mod->name[0]) { - d = Cache_Check (&mod->cache); - if (d) + if (!strcmp (mod->name, name)) + { + mod->used = true; return mod; + } } - else - return mod; // not cached at all - } - -// load the file - buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), false); - if (!buf) - { - if (crash) - Host_Error ("Mod_NumForName: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING* - return NULL; + else if (freemod == NULL) + freemod = mod; } - -// allocate a new model - COM_FileBase (mod->name, loadname); - - loadmodel = mod; -// call the apropriate loader - mod->needload = false; - - switch (LittleLong(*(unsigned *)buf)) + if (freemod) { - case IDPOLYHEADER: - Mod_LoadAliasModel (mod, buf); - break; - - case MD2IDALIASHEADER: // LordHavoc: added Quake2 model support - Mod_LoadQ2AliasModel (mod, buf); - break; - - case IDSPRITEHEADER: - Mod_LoadSpriteModel (mod, buf); - break; - - default: - Mod_LoadBrushModel (mod, buf); - break; + mod = freemod; + strcpy (mod->name, name); + mod->needload = true; + mod->used = true; + return mod; } - return mod; + Host_Error ("Mod_FindName: ran out of models\n"); + return NULL; } /* ================== -Mod_ForName +Mod_TouchModel -Loads in a model for the given name ================== */ -model_t *Mod_ForName (char *name, qboolean crash) +void Mod_TouchModel (char *name) { model_t *mod; - + mod = Mod_FindName (name); - - return Mod_LoadModel (mod, crash); + mod->used = true; } -byte *mod_base; - /* -================= -RadiusFromBounds -================= +================== +Mod_ForName + +Loads in a model for the given name +================== */ -float RadiusFromBounds (vec3_t mins, vec3_t maxs) +model_t *Mod_ForName (char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel) { - int i; - vec3_t corner; + return Mod_LoadModel (Mod_FindName (name), crash, checkdisk, isworldmodel); +} - for (i=0 ; i<3 ; i++) - corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); +qbyte *mod_base; - return Length (corner); -} //============================================================================= @@ -247,16 +344,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 ("%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]); +}