From: havoc Date: Sat, 4 Apr 2009 14:53:35 +0000 (+0000) Subject: it is now possible to have multiple map models loaded at once - removed X-Git-Tag: xonotic-v0.1.0preview~1753 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=11acf2a5a0a0583a58b93f6c03ec7726b5bd4938 it is now possible to have multiple map models loaded at once - removed the isworldmodel flag, and submodel searches now use the mapname as a second search key so submodels from multiple maps can coexist in memory this is a cleanup that I had wanted to do for a long time... added special modeldecompile support for submodels, they should now save to a name based on the current map as well as the submodel number git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8854 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_main.c b/cl_main.c index 675c3564..7b651685 100644 --- a/cl_main.c +++ b/cl_main.c @@ -461,7 +461,7 @@ static void CL_ModelIndexList_f(void) while(cl.model_precache[i] && i != MAX_MODELS) { // Valid Model - if(cl.model_precache[i]->loaded || cl.model_precache[i]->isworldmodel) + if(cl.model_precache[i]->loaded || i == 1) Con_Printf("%3i: %-30s %-8s %-10i\n", i, cl.model_precache[i]->name, cl.model_precache[i]->modeldatatypestring, cl.model_precache[i]->surfmesh.num_triangles); else Con_Printf("%3i: %-30s %-30s\n", i, cl.model_precache[i]->name, "--no local model found--"); diff --git a/cl_parse.c b/cl_parse.c index a64e1ffd..28c4dda2 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -560,24 +560,24 @@ static void QW_CL_RequestNextDownload(void) if (!sv.active) Mod_ClearUsed(); for (i = 1;i < MAX_MODELS && cl.model_name[i][0];i++) - Mod_FindName(cl.model_name[i]); + Mod_FindName(cl.model_name[i], cl.model_name[i][0] == '*' ? cl.model_name[1] : NULL); // precache any models used by the client (this also marks them used) - cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, false); - cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, false); - cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, false); - cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, false); + cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, NULL); + cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, NULL); + cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, NULL); + cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, NULL); Mod_PurgeUnused(); // now we try to load everything that is new // world model - cl.model_precache[1] = Mod_ForName(cl.model_name[1], false, false, true); + cl.model_precache[1] = Mod_ForName(cl.model_name[1], false, false, NULL); if (cl.model_precache[1]->Draw == NULL) Con_Printf("Map %s could not be found or downloaded\n", cl.model_name[1]); // normal models for (i = 2;i < MAX_MODELS && cl.model_name[i][0];i++) - if ((cl.model_precache[i] = Mod_ForName(cl.model_name[i], false, false, false))->Draw == NULL) + if ((cl.model_precache[i] = Mod_ForName(cl.model_name[i], false, false, cl.model_name[i][0] == '*' ? cl.model_name[1] : NULL))->Draw == NULL) Con_Printf("Model %s could not be found or downloaded\n", cl.model_name[i]); // check memory integrity @@ -1029,7 +1029,7 @@ void CL_BeginDownloads(qboolean aborteddownload) if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw) continue; CL_KeepaliveMessage(true); - cl.model_precache[cl.loadmodel_current] = Mod_ForName(cl.model_name[cl.loadmodel_current], false, false, cl.loadmodel_current == 1); + cl.model_precache[cl.loadmodel_current] = Mod_ForName(cl.model_name[cl.loadmodel_current], false, false, cl.model_name[cl.loadmodel_current][0] == '*' ? cl.model_name[1] : NULL); if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw && cl.loadmodel_current == 1) { // we now have the worldmodel so we can set up the game world @@ -1102,7 +1102,7 @@ void CL_BeginDownloads(qboolean aborteddownload) if (cl.model_precache[cl.downloadmodel_current] && cl.model_precache[cl.downloadmodel_current]->Draw) continue; CL_KeepaliveMessage(true); - if (strcmp(cl.model_name[cl.downloadmodel_current], "null") && !FS_FileExists(cl.model_name[cl.downloadmodel_current])) + if (cl.model_name[cl.downloadmodel_current][0] != '*' && strcmp(cl.model_name[cl.downloadmodel_current], "null") && !FS_FileExists(cl.model_name[cl.downloadmodel_current])) { if (cl.downloadmodel_current == 1) Con_Printf("Map %s not found\n", cl.model_name[cl.downloadmodel_current]); @@ -1116,7 +1116,7 @@ void CL_BeginDownloads(qboolean aborteddownload) return; } } - cl.model_precache[cl.downloadmodel_current] = Mod_ForName(cl.model_name[cl.downloadmodel_current], false, false, cl.downloadmodel_current == 1); + cl.model_precache[cl.downloadmodel_current] = Mod_ForName(cl.model_name[cl.downloadmodel_current], false, false, cl.model_name[cl.downloadmodel_current][0] == '*' ? cl.model_name[1] : NULL); if (cl.downloadmodel_current == 1) { // we now have the worldmodel so we can set up the game world @@ -1445,6 +1445,10 @@ static void CL_SignonReply (void) break; case 4: + // after the level has been loaded, we shouldn't need the shaders, and + // if they are needed again they will be automatically loaded... + Mod_FreeQ3Shaders(); + Con_ClearNotify(); if (COM_CheckParm("-profilegameonly")) Sys_AllowProfiling(true); @@ -1471,6 +1475,8 @@ void CL_ParseServerInfo (void) { SCR_BeginLoadingPlaque(); S_StopAllSounds(); + // free q3 shaders so that any newly downloaded shaders will be active + Mod_FreeQ3Shaders(); } // check memory integrity @@ -1631,12 +1637,12 @@ void CL_ParseServerInfo (void) if (!sv.active) Mod_ClearUsed(); for (i = 1;i < nummodels;i++) - Mod_FindName(cl.model_name[i]); + Mod_FindName(cl.model_name[i], cl.model_name[i][0] == '*' ? cl.model_name[1] : NULL); // precache any models used by the client (this also marks them used) - cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, false); - cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, false); - cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, false); - cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, false); + cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, NULL); + cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, NULL); + cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, NULL); + cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, NULL); Mod_PurgeUnused(); // do the same for sounds @@ -2593,7 +2599,7 @@ void CL_ParseTempEntity(void) // LordHavoc: for compatibility with the Nehahra movie... case TE_LIGHTNING4NEH: - CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false); + CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, NULL), false); break; case TE_LAVASPLASH: @@ -3659,7 +3665,7 @@ void CL_ParseServerMessage(void) { if (i >= 1 && i < MAX_MODELS) { - dp_model_t *model = Mod_ForName(s, false, false, i == 1); + dp_model_t *model = Mod_ForName(s, false, false, s[0] == '*' ? cl.model_name[1] : NULL); if (!model) Con_DPrintf("svc_precache: Mod_ForName(\"%s\") failed\n", s); cl.model_precache[i] = model; diff --git a/clvm_cmds.c b/clvm_cmds.c index 8b6e1480..da4832ed 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -393,7 +393,7 @@ void VM_CL_precache_model (void) } } PRVM_G_FLOAT(OFS_RETURN) = 0; - m = Mod_ForName(name, false, false, false); + m = Mod_ForName(name, false, false, name[0] == '*' ? cl.model_name[1] : NULL); if(m && m->loaded) { for (i = 0;i < MAX_MODELS;i++) diff --git a/host_cmd.c b/host_cmd.c index d77264f1..6e3a2abc 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -933,7 +933,7 @@ void Host_Loadgame_f (void) if (i >= 0 && i < MAX_MODELS) { strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i])); - sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false); + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL); } else Con_Printf("unsupported model %i \"%s\"\n", i, com_token); @@ -2084,7 +2084,7 @@ void Host_Viewmodel_f (void) if (!e) return; - m = Mod_ForName (Cmd_Argv(1), false, true, false); + m = Mod_ForName (Cmd_Argv(1), false, true, NULL); if (!m || !m->loaded || !m->Draw) { Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1)); diff --git a/model_brush.c b/model_brush.c index 723f4dab..f652f221 100644 --- a/model_brush.c +++ b/model_brush.c @@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"}; -cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"}; cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"}; cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too"}; cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"}; @@ -54,7 +53,6 @@ static texture_t mod_q1bsp_texture_water; void Mod_BrushInit(void) { // Cvar_RegisterVariable(&r_subdivide_size); - Cvar_RegisterVariable(&halflifebsp); Cvar_RegisterVariable(&r_novis); Cvar_RegisterVariable(&r_picmipworld); Cvar_RegisterVariable(&r_nosurftextures); @@ -1487,17 +1485,14 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) // LordHavoc: HL sky textures are entirely different than quake if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128) { - if (loadmodel->isworldmodel) + data = loadimagepixelsbgra(tx->name, false, false); + if (data && image_width == 256 && image_height == 128) { - data = loadimagepixelsbgra(tx->name, false, false); - if (data && image_width == 256 && image_height == 128) - { - R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); - Mem_Free(data); - } - else if (mtdata != NULL) - R_Q1BSP_LoadSplitSky(mtdata, mtwidth, mtheight, 1); + R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); + Mem_Free(data); } + else if (mtdata != NULL) + R_Q1BSP_LoadSplitSky(mtdata, mtwidth, mtheight, 1); } else { @@ -3447,9 +3442,13 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint; mod->brush.RoundUpToHullSize = Mod_Q1BSP_RoundUpToHullSize; mod->brush.PointInLeaf = Mod_Q1BSP_PointInLeaf; - - if (loadmodel->isworldmodel) - Cvar_SetValue("halflifebsp", mod->brush.ishlbsp); + mod->Draw = R_Q1BSP_Draw; + mod->DrawDepth = R_Q1BSP_DrawDepth; + mod->DrawDebug = R_Q1BSP_DrawDebug; + mod->GetLightInfo = R_Q1BSP_GetLightInfo; + mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + mod->DrawLight = R_Q1BSP_DrawLight; // load into heap @@ -3555,21 +3554,26 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) if (i > 0) { char name[10]; - // LordHavoc: only register submodels if it is the world - // (prevents external bsp models from replacing world submodels with - // their own) - if (!loadmodel->isworldmodel) - continue; // duplicate the basic information dpsnprintf(name, sizeof(name), "*%i", i); - mod = Mod_FindName(name); + mod = Mod_FindName(name, loadmodel->name); // copy the base model to this one *mod = *loadmodel; // rename the clone back to its proper name strlcpy(mod->name, name, sizeof(mod->name)); + mod->brush.parentmodel = loadmodel; // textures and memory belong to the main model mod->texturepool = NULL; mod->mempool = NULL; + mod->brush.TraceLineOfSight = NULL; + mod->brush.GetPVS = NULL; + mod->brush.FatPVS = NULL; + mod->brush.BoxTouchingPVS = NULL; + mod->brush.BoxTouchingLeafPVS = NULL; + mod->brush.BoxTouchingVisibleLeafs = NULL; + mod->brush.FindBoxClusters = NULL; + mod->brush.LightPoint = NULL; + mod->brush.AmbientSoundLevelsForPoint = NULL; } mod->brush.submodel = i; @@ -3593,29 +3597,6 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->sortedmodelsurfaces = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int); Mod_MakeSortedSurfaces(mod); - // this gets altered below if sky or water is used - mod->DrawSky = NULL; - mod->DrawAddWaterPlanes = NULL; - mod->Draw = R_Q1BSP_Draw; - mod->DrawDepth = R_Q1BSP_DrawDepth; - mod->DrawDebug = R_Q1BSP_DrawDebug; - mod->GetLightInfo = R_Q1BSP_GetLightInfo; - mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; - mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; - mod->DrawLight = R_Q1BSP_DrawLight; - if (i != 0) - { - mod->brush.TraceLineOfSight = NULL; - mod->brush.GetPVS = NULL; - mod->brush.FatPVS = NULL; - mod->brush.BoxTouchingPVS = NULL; - mod->brush.BoxTouchingLeafPVS = NULL; - mod->brush.BoxTouchingVisibleLeafs = NULL; - mod->brush.FindBoxClusters = NULL; - mod->brush.LightPoint = NULL; - mod->brush.AmbientSoundLevelsForPoint = NULL; - } - // copy the submodel bounds, then enlarge the yaw and rotated bounds according to radius // (previously this code measured the radius of the vertices of surfaces in the submodel, but that broke submodels that contain only CLIP brushes, which do not produce surfaces) VectorCopy(bm->mins, mod->normalmins); @@ -3636,18 +3617,25 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->radius = modelradius; mod->radius2 = modelradius * modelradius; + // this gets altered below if sky or water is used + mod->DrawSky = NULL; + mod->DrawAddWaterPlanes = NULL; + // scan surfaces for sky and water and flag the submodel as possessing these features or not // build lightstyle lists for quick marking of dirty lightmaps when lightstyles flicker if (mod->nummodelsurfaces) { for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++) - { - // we only need to have a drawsky function if it is used(usually only on world model) if (surface->texture->basematerialflags & MATERIALFLAG_SKY) - mod->DrawSky = R_Q1BSP_DrawSky; + break; + if (j < mod->nummodelsurfaces) + mod->DrawSky = R_Q1BSP_DrawSky; + + for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++) if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) - mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; - } + break; + if (j < mod->nummodelsurfaces) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; // build lightstyle update chains // (used to rapidly mark lightmapupdateflags on many surfaces @@ -4097,9 +4085,6 @@ void static Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) i = LittleLong(header->version); if (i != Q2BSPVERSION) Host_Error("Mod_Q2BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q2BSPVERSION); - mod->brush.ishlbsp = false; - if (loadmodel->isworldmodel) - Cvar_SetValue("halflifebsp", mod->brush.ishlbsp); mod_base = (unsigned char *)header; @@ -5827,9 +5812,6 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) i = LittleLong(header->version); if (i != Q3BSPVERSION && i != Q3BSPVERSION_IG && i != Q3BSPVERSION_LIVE) Host_Error("Mod_Q3BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q3BSPVERSION); - mod->brush.ishlbsp = false; - if (loadmodel->isworldmodel) - Cvar_SetValue("halflifebsp", mod->brush.ishlbsp); mod->soundfromcenter = true; mod->TraceBox = Mod_Q3BSP_TraceBox; @@ -5845,6 +5827,8 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->brush.FindBoxClusters = Mod_Q1BSP_FindBoxClusters; mod->brush.LightPoint = Mod_Q3BSP_LightPoint; mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation; + mod->brush.AmbientSoundLevelsForPoint = NULL; + mod->brush.RoundUpToHullSize = NULL; mod->brush.PointInLeaf = Mod_Q1BSP_PointInLeaf; mod->Draw = R_Q1BSP_Draw; mod->DrawDepth = R_Q1BSP_DrawDepth; @@ -5853,7 +5837,6 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; mod->DrawLight = R_Q1BSP_DrawLight; - mod->DrawAddWaterPlanes = NULL; mod_base = (unsigned char *)header; @@ -5952,16 +5935,14 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) if (i > 0) { char name[10]; - // LordHavoc: only register submodels if it is the world - // (prevents external bsp models from replacing world submodels with - // their own) - if (!loadmodel->isworldmodel) - continue; // duplicate the basic information dpsnprintf(name, sizeof(name), "*%i", i); - mod = Mod_FindName(name); + mod = Mod_FindName(name, loadmodel->name); + // copy the base model to this one *mod = *loadmodel; + // rename the clone back to its proper name strlcpy(mod->name, name, sizeof(mod->name)); + mod->brush.parentmodel = loadmodel; // textures and memory belong to the main model mod->texturepool = NULL; mod->mempool = NULL; @@ -5973,7 +5954,7 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->brush.BoxTouchingVisibleLeafs = NULL; mod->brush.FindBoxClusters = NULL; mod->brush.LightPoint = NULL; - mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation; + mod->brush.AmbientSoundLevelsForPoint = NULL; } mod->brush.submodel = i; @@ -6025,21 +6006,21 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->radius = modelradius; mod->radius2 = modelradius * modelradius; + // this gets altered below if sky or water is used + mod->DrawSky = NULL; + mod->DrawAddWaterPlanes = NULL; + for (j = 0;j < mod->nummodelsurfaces;j++) if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY) break; if (j < mod->nummodelsurfaces) mod->DrawSky = R_Q1BSP_DrawSky; - else - mod->DrawSky = NULL; for (j = 0;j < mod->nummodelsurfaces;j++) if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) break; if (j < mod->nummodelsurfaces) mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; - else - mod->DrawAddWaterPlanes = NULL; } } diff --git a/model_shared.c b/model_shared.c index 664f0dab..c8cbc433 100644 --- a/model_shared.c +++ b/model_shared.c @@ -54,13 +54,10 @@ static void mod_start(void) int nummodels = Mem_ExpandableArray_IndexRange(&models); dp_model_t *mod; - // parse the Q3 shader files - Mod_LoadQ3Shaders(); - for (i = 0;i < nummodels;i++) if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') if (mod->used) - Mod_LoadModel(mod, true, false, mod->isworldmodel); + Mod_LoadModel(mod, true, false); } static void mod_shutdown(void) @@ -73,7 +70,7 @@ static void mod_shutdown(void) if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool)) Mod_UnloadModel(mod); - Mem_FreePool (&q3shaders_mem); + Mod_FreeQ3Shaders(); } static void mod_newmap(void) @@ -152,14 +149,14 @@ void Mod_RenderInit(void) void Mod_UnloadModel (dp_model_t *mod) { char name[MAX_QPATH]; - qboolean isworldmodel; qboolean used; + dp_model_t *parentmodel; if (developer_loading.integer) Con_Printf("unloading model %s\n", mod->name); strlcpy(name, mod->name, sizeof(name)); - isworldmodel = mod->isworldmodel; + parentmodel = mod->brush.parentmodel; used = mod->used; if (mod->surfmesh.ebo3i) R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3i); @@ -174,7 +171,7 @@ void Mod_UnloadModel (dp_model_t *mod) memset(mod, 0, sizeof(dp_model_t)); // restore the fields we want to preserve strlcpy(mod->name, name, sizeof(mod->name)); - mod->isworldmodel = isworldmodel; + mod->brush.parentmodel = parentmodel; mod->used = used; mod->loaded = false; } @@ -191,7 +188,7 @@ Mod_LoadModel Loads a model ================== */ -dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel) +dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) { int num; unsigned int crc; @@ -205,9 +202,6 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, q if (!strcmp(mod->name, "null")) { - if (mod->isworldmodel != isworldmodel) - mod->loaded = false; - if(mod->loaded) return mod; @@ -217,7 +211,6 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, q if (developer_loading.integer) Con_Printf("loading model %s\n", mod->name); - mod->isworldmodel = isworldmodel; mod->used = true; mod->crc = -1; mod->loaded = false; @@ -246,12 +239,6 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, q // even if the model is loaded it still may need reloading... - // if the model is a worldmodel and is being referred to as a - // non-worldmodel here, then it needs reloading to get rid of the - // submodels - if (mod->isworldmodel != isworldmodel) - mod->loaded = false; - // if it is not loaded or checkdisk is true we need to calculate the crc if (!mod->loaded || checkdisk) { @@ -283,7 +270,6 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, q Mod_UnloadModel(mod); // load the model - mod->isworldmodel = isworldmodel; mod->used = true; mod->crc = crc; // errors can prevent the corresponding mod->loaded = true; @@ -298,15 +284,9 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, q VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius); VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius); - // if we're loading a worldmodel, then this is a level change - if (mod->isworldmodel) + if (!q3shaders_mem) { - // clear out any stale submodels or worldmodels lying around - // if we did this clear before now, an error might abort loading and - // leave things in a bad state - Mod_RemoveStaleWorldModels(mod); - // reload q3 shaders, to make sure they are ready to go for this level - // (including any models loaded for this level) + // load q3 shaders for the first time, or after a level change Mod_LoadQ3Shaders(); } @@ -373,35 +353,21 @@ void Mod_PurgeUnused(void) } } -// only used during loading! -void Mod_RemoveStaleWorldModels(dp_model_t *skip) -{ - int i; - int nummodels = Mem_ExpandableArray_IndexRange(&models); - dp_model_t *mod; - for (i = 0;i < nummodels;i++) - { - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->isworldmodel && mod->loaded && skip != mod) - { - Mod_UnloadModel(mod); - mod->isworldmodel = false; - mod->used = false; - } - } -} - /* ================== Mod_FindName ================== */ -dp_model_t *Mod_FindName(const char *name) +dp_model_t *Mod_FindName(const char *name, const char *parentname) { int i; int nummodels; dp_model_t *mod; + if (!parentname) + parentname = ""; + // if we're not dedicatd, the renderer calls will crash without video Host_StartVideo(); @@ -413,7 +379,7 @@ dp_model_t *Mod_FindName(const char *name) // search the currently loaded models for (i = 0;i < nummodels;i++) { - if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name)) + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname)))) { mod->used = true; return mod; @@ -423,6 +389,10 @@ dp_model_t *Mod_FindName(const char *name) // no match found, create a new one mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models); strlcpy(mod->name, name, sizeof(mod->name)); + if (parentname[0]) + mod->brush.parentmodel = Mod_FindName(parentname, NULL); + else + mod->brush.parentmodel = NULL; mod->loaded = false; mod->used = true; return mod; @@ -435,12 +405,12 @@ Mod_ForName Loads in a model for the given name ================== */ -dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel) +dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname) { dp_model_t *model; - model = Mod_FindName(name); - if (model->name[0] != '*' && (!model->loaded || checkdisk)) - Mod_LoadModel(model, crash, checkdisk, isworldmodel); + model = Mod_FindName(name, parentname); + if (!model->loaded || checkdisk) + Mod_LoadModel(model, crash, checkdisk); return model; } @@ -458,7 +428,7 @@ void Mod_Reload(void) dp_model_t *mod; for (i = 0;i < nummodels;i++) if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) - Mod_LoadModel(mod, true, true, mod->isworldmodel); + Mod_LoadModel(mod, true, true); } unsigned char *mod_base; @@ -479,8 +449,15 @@ static void Mod_Print(void) Con_Print("Loaded models:\n"); for (i = 0;i < nummodels;i++) - if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0]) - Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name); + { + if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + { + if (mod->brush.numsubmodels) + Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels); + else + Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name); + } + } } /* @@ -491,7 +468,7 @@ Mod_Precache static void Mod_Precache(void) { if (Cmd_Argc() == 2) - Mod_ForName(Cmd_Argv(1), false, true, cl.worldmodel && !strcasecmp(Cmd_Argv(1), cl.worldmodel->name)); + Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL); else Con_Print("usage: modelprecache \n"); } @@ -1219,18 +1196,9 @@ q3wavefunc_t Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s) return Q3WAVEFUNC_NONE; } -static void Q3Shaders_Clear() +void Mod_FreeQ3Shaders(void) { - /* Just clear out everything... */ - Mem_FreePool (&q3shaders_mem); - /* ...and alloc the structs again. */ - q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL); - q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem, - sizeof (q3shader_data_t)); - Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries, - q3shaders_mem, sizeof (q3shader_hash_entry_t), 256); - Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs, - q3shaders_mem, sizeof (char**), 256); + Mem_FreePool(&q3shaders_mem); } static void Q3Shader_AddToHash (q3shaderinfo_t* shader) @@ -1280,7 +1248,15 @@ void Mod_LoadQ3Shaders(void) int numparameters; char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH]; - Q3Shaders_Clear(); + Mod_FreeQ3Shaders(); + + q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL); + q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem, + sizeof (q3shader_data_t)); + Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries, + q3shaders_mem, sizeof (q3shader_hash_entry_t), 256); + Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs, + q3shaders_mem, sizeof (char**), 256); search = FS_Search("scripts/*.shader", true, false); if (!search) @@ -1774,8 +1750,12 @@ void Mod_LoadQ3Shaders(void) q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) { - unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name)); - q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE); + unsigned short hash; + q3shader_hash_entry_t* entry; + if (!q3shaders_mem) + Mod_LoadQ3Shaders(); + hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name)); + entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE); while (entry != NULL) { if (strcasecmp (entry->shader.name, name) == 0) @@ -2558,7 +2538,14 @@ static void Mod_Decompile_f(void) strlcpy(inname, Cmd_Argv(1), sizeof(inname)); FS_StripExtension(inname, basename, sizeof(basename)); - mod = Mod_ForName(inname, false, true, cl.worldmodel && !strcasecmp(inname, cl.worldmodel->name)); + mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL); + if (mod->brush.submodel) + { + // if we're decompiling a submodel, be sure to give it a proper name based on its parent + FS_StripExtension(cl.model_name[1], outname, sizeof(outname)); + dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name); + outname[0] = 0; + } if (!mod) { Con_Print("No such model\n"); diff --git a/model_shared.h b/model_shared.h index 3476a4a8..6935b862 100644 --- a/model_shared.h +++ b/model_shared.h @@ -604,14 +604,15 @@ typedef struct model_brush_s // string of entity definitions (.map format) char *entities; - // if non-zero this is a submodel + // if not NULL this is a submodel + struct model_s *parentmodel; // (this is the number of the submodel, an index into submodels) int submodel; // number of submodels in this map (just used by server to know how many // submodels to load) int numsubmodels; - // pointers to each of the submodels if .isworldmodel is true + // pointers to each of the submodels struct model_s **submodels; int num_planes; @@ -797,8 +798,6 @@ typedef struct model_s qboolean loaded; // set if the model is used in current map, models which are not, are purged qboolean used; - // true if this is the world model (I.E. defines what sky to use, and may contain submodels) - qboolean isworldmodel; // CRC of the file this model was loaded from, to reload if changed unsigned int crc; // mod_brush, mod_alias, mod_sprite @@ -910,9 +909,9 @@ extern cvar_t r_fullbrights; void Mod_Init (void); void Mod_Reload (void); -dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel); -dp_model_t *Mod_FindName (const char *name); -dp_model_t *Mod_ForName (const char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel); +dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk); +dp_model_t *Mod_FindName (const char *name, const char *parentname); +dp_model_t *Mod_ForName (const char *name, qboolean crash, qboolean checkdisk, const char *parentname); void Mod_UnloadModel (dp_model_t *mod); void Mod_ClearUsed(void); @@ -941,6 +940,7 @@ shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius); void Mod_ShadowMesh_Free(shadowmesh_t *mesh); +void Mod_FreeQ3Shaders(void); void Mod_LoadQ3Shaders(void); q3shaderinfo_t *Mod_LookupQ3Shader(const char *name); qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags); diff --git a/sv_main.c b/sv_main.c index db271517..b7fbd4df 100644 --- a/sv_main.c +++ b/sv_main.c @@ -157,6 +157,7 @@ cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be use cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"}; cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores (the date is encoded using strftime escapes)" }; +cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"}; server_t sv; server_static_t svs; @@ -438,6 +439,8 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_autodemo_perclient); Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat); + Cvar_RegisterVariable (&halflifebsp); + // any special defaults for gamemodes go here if (gamemode == GAME_HIPNOTIC) { @@ -2399,7 +2402,7 @@ int SV_ModelIndex(const char *s, int precachemode) if (precachemode == 1) Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename); strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i])); - sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false); + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.modelname : NULL); if (sv.state != ss_loading) { MSG_WriteByte(&sv.reliable_datagram, svc_precache); @@ -2701,7 +2704,7 @@ void SV_SaveSpawnparms (void) /* ================ -SV_/pawnServer +SV_SpawnServer This is called at the start of each level ================ @@ -2743,7 +2746,10 @@ void SV_SpawnServer (const char *server) SV_VM_End(); } - worldmodel = Mod_ForName(modelname, false, true, true); + // free q3 shaders so that any newly downloaded shaders will be active + Mod_FreeQ3Shaders(); + + worldmodel = Mod_ForName(modelname, false, true, NULL); if (!worldmodel || !worldmodel->TraceBox) { Con_Printf("Couldn't load map %s\n", modelname); @@ -2800,6 +2806,8 @@ void SV_SpawnServer (const char *server) // level's data which is no longer valiud cls.signon = 0; + Cvar_SetValue("halflifebsp", worldmodel->brush.ishlbsp); + if(*sv_random_seed.string) { srand(sv_random_seed.integer); @@ -2867,7 +2875,7 @@ void SV_SpawnServer (const char *server) for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++) { dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i); - sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false); + sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.modelname); } //