From 84313ce213f680e25f5e115e80314ad8d0ff80dd Mon Sep 17 00:00:00 2001 From: Shpoike Date: Tue, 27 Apr 2021 19:42:03 +0100 Subject: [PATCH] Basic parsing of hl2bsp static props. --- engine/client/cl_ents.c | 28 ++++++ engine/client/merged.h | 1 + engine/client/view.c | 50 ++++++++++ engine/common/gl_q2bsp.c | 196 +++++++++++++++++++++++++++++++++++++++ engine/gl/gl_model.c | 6 +- engine/gl/gl_model.h | 2 + 6 files changed, 281 insertions(+), 2 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 4abf6633..bd53b321 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -3297,6 +3297,7 @@ void CL_ClearLerpEntsParticleState(void) } } +qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel); void CL_LinkStaticEntities(void *pvs, int *areas) { int i; @@ -3401,6 +3402,33 @@ void CL_LinkStaticEntities(void *pvs, int *areas) // FIXME: no effects on static ents // CLQ1_AddPowerupShell(ent, false, stat->effects); } + + if (cl.worldmodel->numstaticents) + { + entity_t *src; + for (i = 0; i < cl.worldmodel->numstaticents; i++) + { + if (cl_numvisedicts == cl_maxvisedicts) + { + cl_expandvisents=true; + break; + } + src = &cl.worldmodel->staticents[i]; + if (!src->model || src->model->loadstate != MLS_LOADED) + { + if (src->model && src->model->loadstate == MLS_NOTLOADED) + Mod_LoadModel(src->model, MLV_WARN); //we use threads, so these'll load in time. + continue; + } + if (!src->light_known) + R_CalcModelLighting(src, src->model); //bake and cache, now everything else is working. + + ent = &cl_visedicts[cl_numvisedicts++]; + *ent = *src; + ent->framestate.g[FS_REG].frametime[0] = cl.time; + ent->framestate.g[FS_REG].frametime[1] = cl.time; + } + } } //returns cos(angle) diff --git a/engine/client/merged.h b/engine/client/merged.h index b6ff315c..c36cb920 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -168,6 +168,7 @@ enum mod_purge_e }; enum mlverbosity_e { + MLV_NOLOAD, //leave it notloaded. MLV_SILENT, MLV_WARN, MLV_WARNSYNC, diff --git a/engine/client/view.c b/engine/client/view.c index 4183b52f..901eba73 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -2127,6 +2127,56 @@ void R_DrawNameTags(void) } } } + + for (i=0 ; imodel; + if (mod && mod->loadstate == MLS_LOADED) + VectorInterpolate(mod->mins, 0.5, mod->maxs, org); + else + VectorClear(org); + VectorAdd(org, state->origin, org); + if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y)) + { + char *entstr; + int x, y; + + entstr = state->model->name; + if (entstr) + { + vec2_t scale = {8,8}; + x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x; + y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y; + R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN, font_default, scale); + } + } + } + + for (i=0 ; inumstaticents; i++) + { + entity_t *state = &cl.worldmodel->staticents[i]; + mod = state->model; + if (mod && mod->loadstate == MLS_LOADED) + VectorInterpolate(mod->mins, 0.5, mod->maxs, org); + else + VectorClear(org); + VectorAdd(org, state->origin, org); + if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y)) + { + char *entstr; + int x, y; + + entstr = state->model->name; + if (entstr) + { + vec2_t scale = {8,8}; + x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x; + y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y; + R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN, font_default, scale); + } + } + } } #ifdef Q2SERVER //not enough fields for it to really be worth it. if (w == &sv.world && svs.gametype == GT_QUAKE2 && ge) diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index a9777ca6..05dfd697 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -5476,6 +5476,200 @@ static qboolean CModHL2_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l return true; } +typedef struct { + unsigned int count; + struct { + unsigned int id; + unsigned short flags; + unsigned short version; + unsigned int ofs; + unsigned int len; + } sl[1]; +} hlgamelumpheader_t; +static qboolean CModHL2_LoadStaticProps(model_t *mod, qbyte *offset, size_t size, int version) +{ + struct { + const char name[128]; + } *modelref; + size_t nummodels, numleafrefs, numprops, i; + unsigned short *leafref; + entity_t *ent; + + size_t modelindex; + + qboolean skip = false; + int dxlevel = 95, cpulevel=0, gpulevel=0; + + qbyte *prop; + size_t propsize; + switch(version) + { + case 4: + propsize = 14*4; + break; + case 5: //+scale + propsize = 15*4; + break; + case 6://+dxlevels + propsize = 16*4; + break; + case 7: //+rgba + case 8: //-dxlevels+[cg]pulevels + propsize = 17*4; + break; + case 9: //+360 + case 10://-360+flags + propsize = 18*4; + break; + case 11://+scale + propsize = 19*4; + break; + default: + return true; //version not supported, just ignore it entirely. sorry. + } + + + nummodels = LittleLong(*(int*)offset); + offset += 4; + size -= 4; + modelref = (void*)offset; + offset += nummodels*sizeof(*modelref); + size -= nummodels*sizeof(*modelref); + + numleafrefs = LittleLong(*(int*)offset); + offset += 4; + size -= 4; + leafref = (void*)offset; + offset += numleafrefs*sizeof(*leafref); + size -= numleafrefs*sizeof(*leafref); + + numprops = LittleLong(*(int*)offset); + offset += 4; + size -= 4; + prop = (void*)offset; + offset += numprops*propsize; + size -= numprops*propsize; + + if (size) + return true; //funny lump size... + + mod->staticents = ZG_Malloc(&mod->memgroup, sizeof(*mod->staticents)*numprops); + for (i = 0, ent = mod->staticents; i < numprops; i++) + { + skip = false; + V_ClearEntity(ent); + + ent->playerindex = -1; + ent->topcolour = TOP_DEFAULT; + ent->bottomcolour = BOTTOM_DEFAULT; +#ifdef PEXT_SCALE + ent->scale = 1; +#endif + ent->shaderRGBAf[0] = 1; + ent->shaderRGBAf[1] = 1; + ent->shaderRGBAf[2] = 1; + ent->shaderRGBAf[3] = 1; + ent->framestate.g[FS_REG].frame[0] = 0; + ent->framestate.g[FS_REG].lerpweight[0] = 1; + + + ent->origin[0] = LittleFloat(*(float*)prop); prop += sizeof(float); + ent->origin[1] = LittleFloat(*(float*)prop); prop += sizeof(float); + ent->origin[2] = LittleFloat(*(float*)prop); prop += sizeof(float); + ent->angles[0] = LittleFloat(*(float*)prop); prop += sizeof(float); + ent->angles[1] = LittleFloat(*(float*)prop); prop += sizeof(float); + ent->angles[2] = LittleFloat(*(float*)prop); prop += sizeof(float); + modelindex = (unsigned short)LittleShort(*(short*)prop); prop += sizeof(unsigned short); + /*firstleaf = LittleShort(*(unsigned short*)prop)*/; prop += sizeof(unsigned short); + /*leafcount = LittleShort(*(unsigned short*)prop)*/; prop += sizeof(unsigned short); + /*ent->solid = *prop*/; prop += sizeof(qbyte); + /*ent->flags = *prop*/; prop += sizeof(qbyte); + ent->skinnum = LittleLong(*(unsigned int*)prop); prop += sizeof(unsigned int); + /*ent->fademindist = LittleFloat(*(float*)prop)*/; prop += sizeof(float); + /*ent->fademaxdist = LittleFloat(*(float*)prop)*/; prop += sizeof(float); + /*ent->lightingorigin[0] = LittleFloat(*(float*)prop)*/; prop += sizeof(float); + /*ent->lightingorigin[1] = LittleFloat(*(float*)prop)*/; prop += sizeof(float); + /*ent->lightingorigin[2] = LittleFloat(*(float*)prop)*/; prop += sizeof(float); + if (version >= 5) + { + /*ent->fadescale = LittleFloat(*(float*)prop);*/ prop += sizeof(float); + } + if (version >= 8) + { + skip |= (prop[0] > cpulevel || cpulevel > prop[1]); prop += sizeof(qbyte)*2; + skip |= (prop[0] > gpulevel || gpulevel > prop[1]); prop += sizeof(qbyte)*2; + } + else if (version >= 6) + { + unsigned short minlev, maxlev; + minlev = LittleShort(*(unsigned short*)prop); prop += sizeof(unsigned short); + maxlev = LittleShort(*(unsigned short*)prop); prop += sizeof(unsigned short); + skip |= (minlev > dxlevel || dxlevel > maxlev); + } + if (version >= 7) + { + VectorScale(prop, 1/255.0, ent->shaderRGBAf); prop += sizeof(qbyte)*4; + } + + if (version == 9) + { + /*disablex360 = LittleLong(*(int*)prop);*/ prop += sizeof(int); + } + if (version >= 10) + { + ent->flags = LittleLong(*(int*)prop); prop += sizeof(int); + } + if (version >= 11) + { + ent->scale = LittleFloat(*(float*)prop); prop += sizeof(float); + } + + //okay, we parsed the prop data now... + skip |= modelindex >= nummodels; + if (skip) + continue; //we're ignoring it for some reason + ent->model = Mod_FindName(modelref[modelindex].name); + AngleVectorsFLU(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]); + + //Hack: lighting is wrong. + ent->light_known = 1; + VectorSet(ent->light_dir, 0, 0.707, 0.707); + VectorSet(ent->light_avg, 0.75, 0.75, 0.75); + VectorSet(ent->light_range, 0.5, 0.5, 0.5); + + //not all props will be emitted, according to d3d levels... + mod->numstaticents++; + ent++; + } + + return true; +} +static qboolean CModHL2_LoadGameLump(model_t *mod, qbyte *mod_base, lump_t *l) +{ + size_t i; + hlgamelumpheader_t *blob = (void*)(mod_base + l->fileofs); + if (!l->filelen) + return true; //missing + if (l->filelen < sizeof(*blob) + sizeof(*blob->sl)*(blob->count-1)) + return false; //not even enough space for the header... + for (i = 0; i < blob->count; i++) + { +#define LUMPTYPE(a,b,c,d, minver, maxver) (blob->sl[i].id == (((qbyte)a<<24)|((qbyte)b<<16)|((qbyte)c<<8)|((qbyte)d<<0)) && blob->sl[i].version >= minver && blob->sl[i].version <= maxver) + if (LUMPTYPE('s','p','r','p', 4,10) && !blob->sl[i].flags) //static props (placed by mapper) + CModHL2_LoadStaticProps(mod, mod_base+blob->sl[i].ofs/*sigh*/, blob->sl[i].len, blob->sl[i].version); + else if (LUMPTYPE('d','p','r','p', 4,4) && !blob->sl[i].flags) //dynamic props (generated by textures) + ; + else if (LUMPTYPE('d','p','l','t', 0,0) && !blob->sl[i].flags) //detail prop ldr lighting + ; + else if (LUMPTYPE('d','p','l','h', 0,0) && !blob->sl[i].flags) //detail prop hdr lighting + ; + else + Con_Printf("Unsupported gamelump id/version %c%c%c%c %i\n", (blob->sl[i].id>>24),(blob->sl[i].id>>16),(blob->sl[i].id>>8),(blob->sl[i].id>>0),blob->sl[i].version); +#undef LUMPTYPE + } + return true; +} + #include "fs.h" static searchpathfuncs_t *CModHL2_LoadArchive(model_t *mod, void *base, size_t len) { @@ -5591,6 +5785,8 @@ static qboolean VBSP_LoadModel(model_t *mod, qbyte *mod_base, size_t filelen, ch noerrors = noerrors && CModQ2_LoadAreas (mod, mod_base, &header.lumps[VLUMP_AREAS]); noerrors = noerrors && CModHL2_LoadAreaPortals (mod, mod_base, &header.lumps[VLUMP_AREAPORTALS], &header.lumps[VLUMP_AREAPORTALVERTS]); + noerrors = noerrors && CModHL2_LoadGameLump (mod, mod_base, &header.lumps[VLUMP_GAMELUMP]); + if (!noerrors) return false; #ifdef HAVE_SERVER diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index f89f189f..b3a8033c 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1059,6 +1059,7 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b) } #endif + if (a != MLS_LOADED) switch(verbose) { default: @@ -1070,6 +1071,7 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b) if (*mod->name != '*' && strcmp(mod->name, "null") && mod_warnmodels.ival && !previouslyfailed) Con_Printf(CON_ERROR "Unable to load %s\n", mod->name); break; + case MLV_NOLOAD: //shouldn't happen. case MLV_SILENT: break; } @@ -1338,7 +1340,7 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b) BZ_Free(buf); - COM_AddWork(WG_MAIN, Mod_ModelLoaded, mod, NULL, MLS_LOADED, 0); + COM_AddWork(WG_MAIN, Mod_ModelLoaded, mod, NULL, MLS_LOADED, verbose); return; } @@ -1356,7 +1358,7 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b) model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) { - if (mod->loadstate == MLS_NOTLOADED && *mod->name != '*') + if (mod->loadstate == MLS_NOTLOADED && *mod->name != '*' && verbose != MLV_NOLOAD) { mod->loadstate = MLS_LOADING; if (verbose == MLV_ERROR || verbose == MLV_WARNSYNC) diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 106a1a2d..032859d2 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -1133,6 +1133,8 @@ typedef struct model_s #ifdef HL2BSPS dispinfo_t *displacements; unsigned int numdisplacements; + entity_t *staticents; + size_t numstaticents; #endif modelfuncs_t funcs;