From 955e9d3fb67af85d4856c6c9a0cef03298574cb2 Mon Sep 17 00:00:00 2001 From: Shpoike Date: Sun, 25 Apr 2021 19:31:08 +0100 Subject: [PATCH] Basic hl2bsp support. --- engine/client/r_surf.c | 253 +++++++++- engine/client/renderer.c | 2 +- engine/common/bspfile.h | 38 +- engine/common/gl_q2bsp.c | 1002 +++++++++++++++++++++++++++++++++++++- engine/gl/gl_model.c | 36 +- engine/gl/gl_model.h | 25 +- engine/gl/gl_rlight.c | 82 +++- 7 files changed, 1417 insertions(+), 21 deletions(-) diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index eeb5218a..8567ac86 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -643,6 +643,25 @@ static void Surf_BuildDeluxMap (model_t *wmodel, msurface_t *surf, qbyte *dest, { switch(wmodel->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: //FIXME + deluxmap = ((surf->samples - wmodel->lightdata)/4)*3 + wmodel->deluxdata; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + for (i=0 ; i>0)&0xff),((lm>>8)&0xff),((lm>>16)&0xff)) * scale * pow(2, (signed char)(lm>>24)); + blocknormals[i][0] += intensity*(deluxmap[i*3+0]-127); + blocknormals[i][1] += intensity*(deluxmap[i*3+1]-127); + blocknormals[i][2] += intensity*(deluxmap[i*3+2]-127); + } + lightmap += size*4; // skip to next lightmap + deluxmap += size*3; + } + break; +#endif case LM_E5BGR9: deluxmap = ((surf->samples - wmodel->lightdata)/4)*3 + wmodel->deluxdata; for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) @@ -1484,6 +1503,28 @@ static void Surf_BuildLightMap (model_t *model, msurface_t *surf, int map, int s Sys_Error("Surf_BuildLightMap: q3bsp"); switch(model->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + if (scale) + { + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); + for (i=0 ; i>24)); + blocklights[i*3+0] += scalergb[0] * e * ((l>> 0)&0xff); + blocklights[i*3+1] += scalergb[1] * e * ((l>> 8)&0xff); + blocklights[i*3+2] += scalergb[2] * e * ((l>>16)&0xff); + } + } + src += size*4; // skip to next lightmap + } + break; +#endif case LM_E5BGR9: for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { @@ -1615,6 +1656,23 @@ static void Surf_BuildLightMap (model_t *model, msurface_t *surf, int map, int s { switch(model->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: //FIXME + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + for (i=0 ; i>0)&0xff),((lm>>8)&0xff),((lm>>16)&0xff)) * scale * + pow(2, (signed char)(lm>>24)); + } + src += size*4; // skip to next lightmap + } + break; +#endif case LM_E5BGR9: for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { @@ -1781,6 +1839,28 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh } else switch(wmodel->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: //FIXME + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + if (scale) + { + VectorScale(cl_lightstyle[surf->styles[maps]].colours, scale, scalergb); + for (i=0 ; i>24)); + blocklights[i*3+0] += scalergb[0] * e * ((l>> 0)&0xff); + blocklights[i*3+1] += scalergb[1] * e * ((l>> 8)&0xff); + blocklights[i*3+2] += scalergb[2] * e * ((l>>16)&0xff); + } + } + src += size*4; // skip to next lightmap + } + break; +#endif case LM_E5BGR9: for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { @@ -1881,6 +1961,23 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh { switch(wmodel->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: //FIXME + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; + for (i=0 ; i>0)&0x1ff),((lm>>9)&0x1ff),((lm>>18)&0x1ff)) * scale * + pow(2, (signed char)(lm>>24)); + } + lightmap += size*4; // skip to next lightmap + } + break; +#endif case LM_E5BGR9: for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { @@ -2441,6 +2538,117 @@ static void Surf_RecursiveQ2WorldNode (mnode_t *node) } #endif +#ifdef HL2BSPS +static void Surf_RecursiveHL2WorldNode (mnode_t *node) +{ + int c, side; + mplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double dot; + + int sidebit; + + if (node->contents == Q2CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + if (R_CullBox (node->minmaxs, node->minmaxs+3)) + return; + +// if a leaf node, draw stuff + if (node->contents != -1) + { + pleaf = (mleaf_t *)node; + + // check for door connected areas + if (! (r_refdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) + return; // not visible + + c = pleaf->cluster; + if (c >= 0) + frustumvis[c>>3] |= 1<<(c&7); + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + surf = *mark; + if (surf->flags & SURF_ONNODE) + surf->visframe = r_framecount; + else if (surf->visframe != r_framecount) + { + surf->visframe = r_framecount; + Surf_RenderDynamicLightmaps (surf); + surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh; + } + mark++; + } while (--c); + } + return; + } + +// node is just a decision point, so go down the apropriate sides + +// find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + { + side = 0; + sidebit = 0; + } + else + { + side = 1; + sidebit = SURF_PLANEBACK; + } + +// recurse down the children, front side first + Surf_RecursiveHL2WorldNode (node->children[side]); + + // draw stuff + for ( c = node->numsurfaces, surf = currentmodel->surfaces + node->firstsurface; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; // wrong side + + surf->visframe = 0;//r_framecount+1;//-1; + + Surf_RenderDynamicLightmaps (surf); + + surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh; + } + + +// recurse down the back side + Surf_RecursiveHL2WorldNode (node->children[!side]); +} +#endif + #ifdef Q3BSPS #if 0 static void Surf_LeafWorldNode (void) @@ -2726,7 +2934,11 @@ void Surf_SetupFrame(void) r_viewcluster2 = -1; } #if defined(Q2BSPS) || defined(Q3BSPS) - else if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) + else if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3 +#ifdef HL2BSPS + || cl.worldmodel->fromgame == fg_halflife2 +#endif + ) { leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg); r_viewarea = leaf->area; @@ -3513,7 +3725,11 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], &es->pvs, PVM_REPLACE); #if defined(Q2BSPS) || defined(Q3BSPS) - if (es->wmodel->fromgame == fg_quake2 || es->wmodel->fromgame == fg_quake3) + if (es->wmodel->fromgame == fg_quake2 || es->wmodel->fromgame == fg_quake3 +#ifdef HL2BSPS + || es->wmodel->fromgame == fg_halflife2 +#endif + ) Surf_SimpleWorld_Q3BSP(es, pvs); else #endif @@ -3784,7 +4000,11 @@ void Surf_DrawWorld (void) entvis = surfvis = NULL; } #if defined(Q2BSPS) || defined(Q3BSPS) - else if (currentmodel->fromgame == fg_quake2 || currentmodel->fromgame == fg_quake3) + else if (currentmodel->fromgame == fg_quake2 || currentmodel->fromgame == fg_quake3 +#ifdef HL2BSPS + || currentmodel->fromgame == fg_halflife2 +#endif + ) { pvsbuffer_t *vis = &surf_frustumvis[r_refdef.recurse]; if (vis->buffersize < currentmodel->pvsbytes) @@ -3808,6 +4028,30 @@ void Surf_DrawWorld (void) } else #endif +#ifdef HL2BSPS + if (currentmodel->fromgame == fg_halflife2) + { + entvis = surfvis = R_MarkLeaves_Q2 (); + VectorCopy (r_refdef.vieworg, modelorg); + if (!surfvis) + { + size_t i; + msurface_t *surf; + for (i = 0; i < currentmodel->nummodelsurfaces; i++) + { + surf = ¤tmodel->surfaces[i]; + Surf_RenderDynamicLightmaps (surf); + surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh; + } + } + else + { + areas[0] = 1; + areas[1] = r_viewarea; + Surf_RecursiveHL2WorldNode (currentmodel->nodes); + } + } +#endif #ifdef Q2BSPS if (currentmodel->fromgame == fg_quake2) { @@ -4055,6 +4299,9 @@ uploadfmt_t Surf_LightmapMode(model_t *model) { switch (model->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: +#endif case LM_E5BGR9: hdr = rgb = true; break; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index d2cbd382..ce3d1f1e 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -2766,7 +2766,7 @@ qbyte *R_MarkLeaves_Q2 (void) vis = cvis[portal]; if (!portal) { - if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2) + if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2 && vis) return vis; r_oldviewcluster = r_viewcluster; diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index face257a..12ef8fb1 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -458,7 +458,7 @@ typedef struct { int ident; int version; - lump_t lumps[50]; + lump_t lumps[64]; } q2dheader_t; typedef struct @@ -604,6 +604,42 @@ typedef struct #define Q3CONTENTS_TRIGGER 0x40000000 #define Q3CONTENTS_NODROP FTECONTENTS_SKY //0x80000000 +#ifdef HL2BSPS +//this is more for documentation, hence why the q2 values where the match +#define HL2CONTENTS_SOLID FTECONTENTS_SOLID //0x00000001 +#define HL2CONTENTS_WINDOW Q2CONTENTS_WINDOW //0x00000002 +#define HL2CONTENTS_AUX Q2CONTENTS_AUX //0x00000004 +#define HL2CONTENTS_GRATE /*FTECONTENTS_LAVA*/ 0x00000008 //Surprise... +#define HL2CONTENTS_SLIME FTECONTENTS_SLIME //0x00000010 +#define HL2CONTENTS_WATER FTECONTENTS_WATER //0x00000020 +#define HL2CONTENTS_MIST Q2CONTENTS_MIST //0x00000040 +#define HL2CONTENTS_OPAQUE 0x00000080 +#define HL2CONTENTS_TESTFOGVOLUME 0x00000100 + //0x00000200 + //0x00000400 +#define HL2CONTENTS_TEAM1 0x00000800 +#define HL2CONTENTS_TEAM2 0x00001000 +#define HL2CONTENTS_IGNORE_NODRAW_OPAQUE 0x00002000 +#define HL2CONTENTS_MOVEABLE /*FTECONTENTS_LADDER*/ 0x00004000 +#define HL2CONTENTS_AREAPORTAL Q2CONTENTS_AREAPORTAL //0x00008000 +#define HL2CONTENTS_PLAYERCLIP FTECONTENTS_PLAYERCLIP //0x00010000 +#define HL2CONTENTS_MONSTERCLIP FTECONTENTS_MONSTERCLIP //0x00020000 +#define HL2CONTENTS_CURRENT_0 Q2CONTENTS_CURRENT_0 //0x00040000 +#define HL2CONTENTS_CURRENT_90 Q2CONTENTS_CURRENT_90 //0x00080000 +#define HL2CONTENTS_CURRENT_180 Q2CONTENTS_CURRENT_180 //0x00100000 +#define HL2CONTENTS_CURRENT_270 Q2CONTENTS_CURRENT_270 //0x00200000 +#define HL2CONTENTS_CURRENT_UP Q2CONTENTS_CURRENT_UP //0x00400000 +#define HL2CONTENTS_CURRENT_DWN Q2CONTENTS_CURRENT_DOWN //0x00800000 +#define HL2CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000 // removed before bsping an entity +#define HL2CONTENTS_MONSTER FTECONTENTS_BODY //0x02000000 // should never be on a brush, only in game +#define HL2CONTENTS_DEADMONSTER FTECONTENTS_CORPSE //0x04000000 +#define HL2CONTENTS_DETAIL Q2CONTENTS_DETAIL //0x08000000 // brushes to be added after vis leafs +#define HL2CONTENTS_TRANSLUCENT Q2CONTENTS_TRANSLUCENT //0x10000000 // auto set if any surface has trans +#define HL2CONTENTS_LADDER Q2CONTENTS_LADDER //0x20000000 +#define HL2CONTENTS_HITBOX 0x40000000 + /*FTECONTENTS_SKY*/ //0x80000000 +#endif + //qc compat only. not used internally. #define DPCONTENTS_SOLID 1 // hit a bmodel, not a bounding box #define DPCONTENTS_WATER 2 diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 70b51e40..9c0fba07 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -183,8 +183,6 @@ qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out); #define Host_Error SV_Error #endif -extern qbyte *mod_base; - #define capsuledist(dist,plane,mins,maxs) \ case shape_iscapsule: \ dist = DotProduct(trace_up, plane->normal); \ @@ -317,6 +315,12 @@ typedef struct cminfo_s //and this is the state that is actually changed. booleans. qbyte q2portalopen[MAX_Q2MAP_AREAPORTALS]; //memset will work if it's a qbyte, really it should be a qboolean #endif +#ifdef HL2BSPS + mplane_t **portalplane; + qbyte portalquerying[MAX_Q2MAP_AREAPORTALS]; + mesh_t *portalpoly; //[numq2areaportals] + int *occlusionqueries; //[numq2areaportals] +#endif //list of mesh surfaces within the leaf @@ -1156,6 +1160,27 @@ static void CMod_SetParent (mnode_t *node, mnode_t *parent) } #ifdef Q2BSPS +static void CModQ2_FindBrushRange (cminfo_t *prv, mnode_t *node, size_t *firstbrush, size_t *lastbrush) +{ + size_t u, b; + mleaf_t *leaf; + while (node->contents == -1) + { //walk every node to find every leaf... + CModQ2_FindBrushRange(prv, node->children[0], firstbrush, lastbrush); + node = node->children[1]; + } + + leaf = (mleaf_t*)node; + for (u = 0; u < leaf->numleafbrushes; u++) + { + b = prv->leafbrushes[leaf->firstleafbrush+u]-prv->brushes; + if (*firstbrush > b) + *firstbrush = b; + if (*lastbrush < b+1) + *lastbrush = b+1; + } +} + /* ================= CMod_LoadSubmodels @@ -1167,6 +1192,7 @@ static qboolean CModQ2_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_ q2dmodel_t *in; cmodel_t *out; int i, j, count; + size_t firstbrush, lastbrush; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -1201,6 +1227,16 @@ static qboolean CModQ2_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_ out->headnode = loadmodel->nodes + LittleLong (in->headnode); out->firstsurface = LittleLong (in->firstface); out->numsurfaces = LittleLong (in->numfaces); + + + firstbrush = ~0u; + lastbrush = 0u; + CModQ2_FindBrushRange(prv, out->headnode, &firstbrush, &lastbrush); + if (lastbrush > firstbrush) + { + out->firstbrush = firstbrush; + out->num_brushes = lastbrush-firstbrush; + } } AddPointToBounds(prv->cmodels[0].mins, loadmodel->mins, loadmodel->maxs); @@ -1250,7 +1286,7 @@ static qboolean CModQ2_LoadSurfaces (model_t *mod, qbyte *mod_base, lump_t *l) return true; } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT static texture_t *Mod_LoadWall(model_t *loadmodel, char *mapname, char *texname, char *shadername, unsigned int imageflags) { char name[MAX_QPATH]; @@ -1766,7 +1802,7 @@ static qboolean CModQ2_LoadBrushes (model_t *mod, qbyte *mod_base, lump_t *l) } count = l->filelen / sizeof(*in); - if (count > SANITY_MAX_MAP_BRUSHES) + if (count > SANITY_LIMIT(*out)) { Con_Printf (CON_ERROR "Map has too many brushes"); return false; @@ -1947,7 +1983,7 @@ static qboolean CModQ2_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l return false; } // need to save space for box planes - if (count > SANITY_MAX_MAP_LEAFBRUSHES) + if (count > SANITY_LIMIT(**out)) { Con_Printf (CON_ERROR "Map has too many leafbrushes\n"); return false; @@ -4416,6 +4452,932 @@ static void CM_BuildBIH(model_t *mod, int submodel) BZ_Free(bihleaf); } +#ifdef HL2BSPS +enum hllumps_e +{ //note how this order matches q1 so well... + //and yet the format is disturbingly similar to q2... huh... :P + VLUMP_ENTITIES = LUMP_ENTITIES, + VLUMP_PLANES = LUMP_PLANES, + VLUMP_TEXTURES = LUMP_TEXTURES, + VLUMP_VERTEXES = LUMP_VERTEXES, + VLUMP_VISIBILITY = LUMP_VISIBILITY, + VLUMP_NODES = LUMP_NODES, + VLUMP_TEXINFO = LUMP_TEXINFO, + VLUMP_FACES = LUMP_FACES, + VLUMP_LIGHTING = LUMP_LIGHTING, +// VLUMP_FOO = 9,//LUMP_CLIPNODES + VLUMP_LEAFS = LUMP_LEAFS, +// VLUMP_FOO = 11,//LUMP_MARKSURFACES + VLUMP_EDGES = LUMP_EDGES, + VLUMP_SURFEDGES = LUMP_SURFEDGES, + VLUMP_MODELS = LUMP_MODELS, +// VLUMP_FOO = 15, + VLUMP_LEAFFACES = 16, + VLUMP_LEAFBRUSHES = 17, + VLUMP_BRUSHES = 18, + VLUMP_BRUSHSIDES = 19, + VLUMP_AREAS = 20, + VLUMP_AREAPORTALS = 21, +// VLUMP_FOO = 22, +// VLUMP_FOO = 23, +// VLUMP_FOO = 24, +// VLUMP_FOO = 25, +// VLUMP_FOO = 26, +// VLUMP_FOO = 27, +// VLUMP_FOO = 28, +// VLUMP_FOO = 29, +// VLUMP_FOO = 30, +// VLUMP_FOO = 31, +// VLUMP_FOO = 32, +// VLUMP_FOO = 33, +// VLUMP_FOO = 34, +// VLUMP_FOO = 35, +// VLUMP_FOO = 36, +// VLUMP_FOO = 37, +// VLUMP_FOO = 38, +// VLUMP_FOO = 39, + + VLUMP_ZIPFILE = 40, + VLUMP_AREAPORTALVERTS = 41, +// VLUMP_FOO = 42, + VLUMP_STRINGDATA = 43, + VLUMP_STRINGOFFSETS = 44, +// VLUMP_FOO = 45, +// VLUMP_FOO = 46, +// VLUMP_FOO = 47, +// VLUMP_FOO = 48, +// VLUMP_FOO = 49, +// VLUMP_FOO = 50, +// VLUMP_FOO = 51, +// VLUMP_FOO = 52, + VLUMP_LIGHTING_HDR = 53, +// VLUMP_FOO = 54, +// VLUMP_FOO = 55, +// VLUMP_FOO = 56, +// VLUMP_FOO = 57, +// VLUMP_FOO = 58, +// VLUMP_FOO = 59, +// VLUMP_FOO = 60, +// VLUMP_FOO = 61, +// VLUMP_FOO = 62, +// VLUMP_FOO = 63, + HL2_MAXLUMPS = 64 +}; + +typedef struct +{ + float vecs[2][4]; // [s/t][xyz offset] + float lmvecs[2][4]; //well that's awkward + int flags; // miptex flags + overrides + int textureindex; +} hltexinfo_t; +static qboolean CModHL2_LoadSurfaces (model_t *mod, qbyte *mod_base, lump_t *l) +{ + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + hltexinfo_t *in; + q2mapsurface_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size\n"); + return false; + } + count = l->filelen / sizeof(*in); + if (count < 1) + { + Con_Printf (CON_ERROR "Map with no surfaces\n"); + return false; + } +// if (count > MAX_Q2MAP_TEXINFO) +// Host_Error ("Map has too many surfaces"); + + mod->numtexinfo = count; + out = prv->surfaces = ZG_Malloc(&mod->memgroup, count * sizeof(*prv->surfaces)); + + for ( i=0 ; ic.name, "FIXME", sizeof(out->c.name)); + Q_strncpyz (out->rname, "FIXME", sizeof(out->rname)); + out->c.flags = LittleLong (in->flags); + out->c.value = 0; + } + + return true; +} + +#ifdef HAVE_CLIENT +typedef struct +{ + vec3_t reflectivity; //not very useful to us. + unsigned int stringindex; + unsigned int width; + unsigned int height; + unsigned int width2; //no idea why there's two of these. + unsigned int height2; +} hltexture_t; +#define TIHL2_LIGHT TI_LIGHT +#define TIHL2_SKYBOX 0x2 +#define TIHL2_SKYROOM 0x4 +#define TIHL2_WARP TI_WARP + +#define TIHL2_TRANS TI_TRANS33 +#define TIHL2_NOPORTAL 0x20 +#define TIHL2_TRIGGER 0x40 +#define TIHL2_NODRAW TI_NODRAW +//#define TIHL2_HINT 0x100 +//#define TIHL2_SKIP 0x200 +#define TIHL2_NOLIGHT 0x400 +//#define TIHL2_BUMPLIGHT 0x800 +//#define TIHL2_NOSHADOWS 0x1000 +//#define TIHL2_NODECALS 0x2000 +//#define TIHL2_NOCHOP 0x4000 +//#define TIHL2_HITBOX 0x8000 + +static qboolean CModHL2_LoadTexInfo (model_t *mod, qbyte *mod_base, lump_t *lumps, char *mapname) +{ //texinfo->textures->stringoffsets->strings. gah, so many lumps just to find the texture name to use! + hltexinfo_t *in; + mtexinfo_t *out; + int i, j, count; + char sname[256]; + int texcount; + hltexture_t *textures = (void*)(mod_base + lumps[VLUMP_TEXTURES].fileofs); + unsigned int *stringoffsets = (void*)(mod_base + lumps[VLUMP_STRINGOFFSETS].fileofs); + char *strings = mod_base + lumps[VLUMP_STRINGDATA].fileofs; + unsigned int flags; + + in = (void *)(mod_base + lumps[VLUMP_TEXINFO].fileofs); + if (lumps[VLUMP_TEXINFO].filelen % sizeof(*in)) + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s\n", mod->name); + return false; + } + count = lumps[VLUMP_TEXINFO].filelen / sizeof(*in); + out = ZG_Malloc(&mod->memgroup, count*sizeof(*out)); + + mod->textures = ZG_Malloc(&mod->memgroup, sizeof(texture_t *)*count); + texcount = 0; + + mod->texinfo = out; + mod->numtexinfo = count; + + for ( i=0 ; itextureindex>=0)?textures + in->textureindex:NULL); + char *texturename = (texture?strings + stringoffsets[texture->stringindex]:"INVALID"); + flags = LittleLong (in->flags); + + for (j=0 ; j<4 ; j++) + out->vecs[0][j] = LittleFloat (in->vecs[0][j]); + for (j=0 ; j<4 ; j++) + out->vecs[1][j] = LittleFloat (in->vecs[1][j]); + out->vecscale[0] = 1.0/Length (out->vecs[0]); + out->vecscale[1] = 1.0/Length (out->vecs[1]); + + for (j=0 ; j<4 ; j++) + out->lmvecs[0][j] = LittleFloat (in->lmvecs[0][j]); + for (j=0 ; j<4 ; j++) + out->lmvecs[1][j] = LittleFloat (in->lmvecs[1][j]); + + if (flags & (TIHL2_SKYBOX|TIHL2_SKYROOM)) + Q_snprintfz(sname, sizeof(sname), "sky/%s", texturename); + else + Q_snprintfz(sname, sizeof(sname), "%s", texturename); + if (flags & (TIHL2_WARP)) + Q_strncatz(sname, "#WARP", sizeof(sname)); +// if (out->flags & TIHL2_FLOWING) +// Q_strncatz(sname, "#FLOW", sizeof(sname)); +// if (out->flags & TIHL2_TRANS66) +// Q_strncatz(sname, "#ALPHA=0.66", sizeof(sname)); + else if (out->flags & TIHL2_TRANS) + Q_strncatz(sname, "#ALPHA=1", sizeof(sname)); +// else if (out->flags & (TIHL2_WARP)) +// Q_strncatz(sname, "#ALPHA=1", sizeof(sname)); + + out->flags = 0; + if (flags & TIHL2_NOLIGHT) + out->flags |= TEX_SPECIAL; + + //compact the textures. + for (j=0; j < texcount; j++) + { + if (!Q_strcasecmp(sname, mod->textures[j]->name)) + { + out->texture = mod->textures[j]; + break; + } + } + if (j == texcount) //load a new one + { + out->texture = ZG_Malloc(&mod->memgroup, sizeof(texture_t)); + Q_strncpyz(out->texture->name, sname, sizeof(out->texture->name)); + Q_strlwr(out->texture->name); + if (texture) + { + out->texture->vwidth = texture->width; + out->texture->vheight = texture->height; + } + else + { + out->texture->vwidth = out->texture->vheight = 128; + } + + mod->textures[texcount++] = out->texture; + } + } + + mod->numtextures = texcount; + + return true; +} +#endif +typedef struct +{ + //shared with q2dnode_t + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides + + //new for hl2 + unsigned short area; + unsigned short pad; +} hl2dnode_t; +static qboolean CModHL2_LoadNodes (model_t *mod, qbyte *mod_base, lump_t *l) +{ + hl2dnode_t *in; + int child; + mnode_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size\n"); + return false; + } + count = l->filelen / sizeof(*in); + + if (count < 1) + { + Con_Printf (CON_ERROR "Map has no nodes\n"); + return false; + } + if (count > SANITY_LIMIT(*out)) + { + Con_Printf (CON_ERROR "Map has too many nodes\n"); + return false; + } + + out = ZG_Malloc(&mod->memgroup, sizeof(mnode_t)*count); + + mod->nodes = out; + mod->numnodes = count; + + for (i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + out->plane = mod->planes + LittleLong(in->planenum); + + out->firstsurface = (unsigned short)LittleShort (in->firstface); + out->numsurfaces = (unsigned short)LittleShort (in->numfaces); + out->contents = -1; // differentiate from leafs + + for (j=0 ; j<2 ; j++) + { + child = LittleLong (in->children[j]); + out->childnum[j] = child; + if (child < 0) + out->children[j] = (mnode_t *)(mod->leafs + -1-child); + else + out->children[j] = mod->nodes + child; + } + } + + CMod_SetParent (mod->nodes, NULL); // sets nodes and leafs + + return true; +} +typedef struct +{ + //copied from q2dleaf_t + int contents; // OR of all brushes (NOTE: hl2 doesn't seem to have these all set properly, at least for detail brushes) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; + + //new for hl2 + short leafwaterid; + short pad; +} hl2dleaf_t; +static qboolean CModHL2_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l, int ver) +{ + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + int i, j; + mleaf_t *out; + hl2dleaf_t *in; + int count; + size_t insize = sizeof(*in); + if (ver == 19) + insize = 56; //older maps have some lighting info here. + else + insize = 32; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % insize) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size\n"); + return false; + } + count = l->filelen / insize; + + if (count < 1) + { + Con_Printf (CON_ERROR "Map with no leafs\n"); + return false; + } + // need to save space for box planes + if (count > SANITY_LIMIT(*out)) + { + Con_Printf (CON_ERROR "Map has too many leafs\n"); + return false; + } + + out = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); + mod->numclusters = 0; + + mod->leafs = out; + mod->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + out->contents = LittleLong (in->contents); + out->cluster = (unsigned short)LittleShort (in->cluster); + if (out->cluster == 0xffff) + out->cluster = -1; + + out->area = (unsigned short)LittleShort (in->area); + out->area &= 0x1ff; //upper part is flags. + out->firstleafbrush = (unsigned short)LittleShort (in->firstleafbrush); + out->numleafbrushes = (unsigned short)LittleShort (in->numleafbrushes); + + //the leaf contents above appears to be set incorrectly... recompute it. + for (out->contents = 0, j = 0; j < out->numleafbrushes; j++) + out->contents |= prv->leafbrushes[out->firstleafbrush+j]->contents; + + out->firstmarksurface = mod->marksurfaces + + (unsigned short)LittleShort(in->firstleafface); + out->nummarksurfaces = (unsigned short)LittleShort(in->numleaffaces); + + if (out->cluster >= mod->numclusters) + mod->numclusters = out->cluster + 1; + } + out = mod->leafs; + mod->pvsbytes = ((mod->numclusters + 31)>>3)&~3; + + return true; +} + +#if defined(HAVE_CLIENT) && defined(GLQUAKE) +//for each area that we recurse, follow the neighbouring areas and check their area portals too. +//if a portal is closed, we switch to using a solid opaque shader, to avoid any HOM glitches. +static qboolean CModHL2_DrawAreaPortalsArea(model_t *mod, int areaidx, qbyte visited[MAX_CM_AREAS], shader_t *shaders[2]) +{ + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + q2carea_t *area = &prv->q2areas[areaidx]; + size_t portal; + qboolean changed = false; + float dist; + + //don't recurse infinitely. + if (visited[areaidx]) + return changed; + visited[areaidx] = true; + + for (portal = area->firstareaportal; portal < area->firstareaportal+area->numareaportals; portal++) + { + GLuint avail; + GLuint isopen, wasopen; + if (!prv->portalpoly[portal].numindexes) + continue; //no portal polies defined... we'll need to use the gamecode to set whether the portal is open or not. + + wasopen = prv->q2portalopen[prv->q2areaportals[portal].portalnum]; + //if the camera is near the portal, just assume that its open. + //this avoids depth problems with the near clip plane. + dist = DotProduct(r_origin, prv->portalplane[portal]->normal)-prv->portalplane[portal]->dist; + if (map_noareas.ival || fabs(dist) < 4) + { + avail = false; + isopen = true; + prv->portalquerying[portal] = avail; + } + else if (!prv->portalquerying[portal]) + { //didn't actually run it last frame. don't change it yet but do requery + avail = true; + isopen = wasopen; + prv->portalquerying[portal] = avail; + } + else + { + qglGetQueryObjectuivARB(prv->occlusionqueries[portal], GL_QUERY_RESULT_AVAILABLE_ARB, &avail); + if (avail) + { + qglGetQueryObjectuivARB(prv->occlusionqueries[portal], GL_QUERY_RESULT_ARB, &isopen); + isopen = !!isopen; //make true/false instead of sample counts. + } + else + { //query still running. use previous state still. + isopen = wasopen; + } + prv->portalquerying[portal] = true; + } + + //change it as applicable + if (wasopen != isopen) + { + prv->q2portalopen[prv->q2areaportals[portal].portalnum] = isopen; + changed = true; + } + + if (avail) + { //recompute again + qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, prv->occlusionqueries[portal]); + BE_DrawMesh_Single(shaders[!!wasopen], &prv->portalpoly[portal], NULL, 0); + qglEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + else if (!wasopen) //still computing but believed to be blocked. mask it out still. + BE_DrawMesh_Single(shaders[!!wasopen], &prv->portalpoly[portal], NULL, 0); + + if (isopen) + changed |= CModHL2_DrawAreaPortalsArea(mod, prv->q2areaportals[portal].otherarea, visited, shaders); + } + return changed; +} +void CModHL2_DrawAreaPortals(model_t *mod) +{ + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + shader_t *shaders[2]; + qbyte visited[MAX_CM_AREAS]; + + if (!prv->occlusionqueries) + if (qrenderer == QR_OPENGL && qglGenQueriesARB) + { + prv->occlusionqueries = ZG_Malloc(&mod->memgroup, sizeof(*prv->occlusionqueries)*prv->numq2areaportals); + qglGenQueriesARB(prv->numq2areaportals, prv->occlusionqueries); + } + + if (prv->occlusionqueries) + { + //closed (opaque, black) + shaders[0] = R_RegisterShader("portalshader_closed", SUF_NONE, + "{\n" + "polygonoffset\n" //try to avoid z-fighting + "cull disable\n" //lame + "{\n" + "map $blackimage\n" + "}\n" + "}\n" + ); + //open (invisible, test only) + shaders[1] = R_RegisterShader("portalshader_open", SUF_NONE, + "{\n" + "polygonoffset\n" //try to avoid z-fighting + "cull disable\n" //lame + "{\n" + "map $whiteimage\n" + "maskcolor\n" //don't draw colour + "maskalpha\n" //don't draw alpha + "nodepth\n" //don't draw depth... + "}\n" + "}\n" + ); + memset(visited, 0, sizeof(visited)); + if (CModHL2_DrawAreaPortalsArea(mod, r_viewarea, visited, shaders)) + FloodAreaConnections (prv); //something changed, reflood areas for next frame. + } +} +#endif +typedef struct +{ + unsigned short portalnum; + unsigned short otherarea; + + unsigned short firstvert; + unsigned short numverts; + unsigned int planenum; +} hl2dareaportal_t; +static qboolean CModHL2_LoadAreaPortals (model_t *mod, qbyte *mod_base, lump_t *l, lump_t *lump_verts) +{ + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + int i; + q2dareaportal_t *out; + hl2dareaportal_t *in; + int count, vcount; + vec3_t *inverts; + mesh_t mesh; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size\n"); + return false; + } + count = l->filelen / sizeof(*in); + + inverts = (void *)(mod_base + lump_verts->fileofs); + if (lump_verts->filelen % sizeof(*inverts)) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size\n"); + return false; + } + vcount = lump_verts->filelen / sizeof(*inverts); + + if (count > MAX_Q2MAP_AREAS) + { + Con_Printf (CON_ERROR "Map has too many areas\n"); + return false; + } + + out = prv->q2areaportals = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); + prv->portalpoly = ZG_Malloc(&mod->memgroup, sizeof(*prv->portalpoly)*count); + prv->portalplane = ZG_Malloc(&mod->memgroup, sizeof(*prv->portalplane)*count); + prv->numq2areaportals = count; + + mesh.xyz_array = ZG_Malloc(&mod->memgroup, sizeof(*mesh.xyz_array)*vcount); + for (i=0 ; imemgroup, sizeof(*mesh.indexes)*64*3); + mesh.st_array = ZG_Malloc(&mod->memgroup, sizeof(*mesh.st_array)*64); + for (i=0 ; i<64 ; i++) + { + Vector2Set(mesh.st_array[i], 0,0); + mesh.indexes[i*3+0] = 0; + mesh.indexes[i*3+1] = i+1; + mesh.indexes[i*3+2] = i+2; + } + + for (i=0 ; iportalnum = LittleShort (in->portalnum); + out->otherarea = LittleShort (in->otherarea); + + prv->portalplane[i] = mod->planes + LittleLong (in->planenum); + + prv->portalpoly[i].xyz_array = mesh.xyz_array+LittleLong(in->firstvert); + prv->portalpoly[i].st_array = mesh.st_array; + prv->portalpoly[i].numvertexes = LittleLong(in->numverts); + + if (prv->portalpoly[i].numvertexes>2) + { + prv->portalpoly[i].istrifan = true; + prv->portalpoly[i].indexes = mesh.indexes; + prv->portalpoly[i].numindexes = (prv->portalpoly[i].numvertexes-2)*3; + } + } + + return true; +} + +#ifdef HAVE_CLIENT +typedef struct +{ + short planenum; + qbyte side; + qbyte onnode; //o.O + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + + short dispinfo; + short fogvolume; + +// lighting info + qbyte styles[4]; + int lightofs; // start of [numstyles*surfsize] samples + float surfacearea; + int extents_min[2]; + int extents_size[2]; + + int origface; + unsigned short numprims; + unsigned short firstprim; + unsigned int smoothinggroup; +} hl2dface_t; +static qboolean CModHL2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *lumps, int version) +{ + lump_t *l = &lumps[VLUMP_FACES]; + lump_t *l2 = &lumps[58]; + hl2dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum; + int ti, st; + int lumpsize = sizeof(*in); + + if (l2->filelen) + l = l2; + + if (version == 18) + { //this version seems to have rgbx*4 prefixed + in = (void *)(mod_base + l->fileofs + 4*4); + lumpsize += 4*4; + } + else + in = (void *)(mod_base + l->fileofs); + if (l->filelen % lumpsize) + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s\n",mod->name); + return false; + } + count = l->filelen / lumpsize; + out = ZG_Malloc(&mod->memgroup, (count+6)*sizeof(*out)); //spare for skybox + + mod->surfaces = out; + mod->numsurfaces = count; + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = (unsigned short)LittleShort(in->numedges); + out->flags = 0; + + planenum = (unsigned short)LittleShort(in->planenum); + if (in->side) + out->flags |= SURF_PLANEBACK; + if (in->onnode) + out->flags |= SURF_ONNODE; + + out->plane = mod->planes + planenum; + + ti = (unsigned short)LittleShort (in->texinfo); + if (ti < 0 || ti >= mod->numtexinfo) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: bad texinfo number\n"); + return false; + } + out->texinfo = mod->texinfo + ti; + + if (out->texinfo->flags & TI_SKY) + { + out->flags |= SURF_DRAWSKY; + } + if (out->texinfo->flags & TI_WARP) + { + out->flags |= SURF_DRAWTURB|SURF_DRAWTILED; + } + + out->lmshift = 0; + out->texturemins[0] = in->extents_min[0]; + out->texturemins[1] = in->extents_min[1]; + out->extents[0] = in->extents_size[0]; + out->extents[1] = in->extents_size[1]; + + // lighting info + + for (i=0 ; istyles[i]; + if (st == 255) + st = INVALID_LIGHTSTYLE; + else if (mod->lightmaps.maxstyle < st) + mod->lightmaps.maxstyle = st; + out->styles[i] = st; + } + for (; istyles[i] = INVALID_LIGHTSTYLE; + for (i = 0; ivlstyles[i] = INVALID_VLIGHTSTYLE; + i = LittleLong(in->lightofs); + if (i == -1 || !mod->lightdata) + out->samples = NULL; + else + out->samples = mod->lightdata + i; + + // set the drawing flags + + if (out->texinfo->flags & TI_WARP) + out->flags |= SURF_DRAWTURB; + } + + return true; +} + +static void CModHL2_LoadLighting (model_t *mod, qbyte *mod_base, lump_t *oldl, lump_t *newl) +{ + if (newl->filelen) + { //this data is screwy. it LOOKS like e8bgr8, but we still get weird results. + mod->lightmaps.fmt = LM_E8BGR8; + mod->lightdatasize = newl->filelen; + mod->lightdata = ZG_Malloc(&mod->memgroup, mod->lightdatasize); + memcpy(mod->lightdata, (void *)(mod_base + newl->fileofs), mod->lightdatasize); + } + else if (oldl->filelen) + { + mod->lightmaps.fmt = LM_E8BGR8; + mod->lightdatasize = oldl->filelen; + mod->lightdata = ZG_Malloc(&mod->memgroup, mod->lightdatasize); + memcpy(mod->lightdata, (void *)(mod_base + oldl->fileofs), mod->lightdatasize); + } +} +#endif + +typedef struct +{ + unsigned short planenum; + short texinfo; + unsigned short dispinfo; + short bevel; +} hl2dbrushside_t; +static qboolean CModHL2_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) +{ + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + unsigned int i, j; + q2cbrushside_t *out; + hl2dbrushside_t *in; + int count; + int num; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size\n"); + return false; + } + count = l->filelen / sizeof(*in); + + // need to save space for box planes + if (count > SANITY_MAX_MAP_BRUSHSIDES) + { + Con_Printf (CON_ERROR "Map has too many brushsides (%i)\n", count); + return false; + } + + out = prv->brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); + prv->numbrushsides = count; + + for ( i=0 ; iplanenum); + out->plane = &mod->planes[num]; + j = (unsigned short)LittleShort (in->texinfo); + if (j >= mod->numtexinfo) + out->surface = &nullsurface; + else + out->surface = &prv->surfaces[j]; + } + + return true; +} + +static qboolean VBSP_LoadModel(model_t *mod, qbyte *mod_base, size_t filelen, char *loadname) +{ + struct { + unsigned int magic; + unsigned int version; + struct vlump_s + { + unsigned int fileofs; + unsigned int filelen; + unsigned int foo[2]; + } lumps[HL2_MAXLUMPS]; + } *srcheader = (void*)mod_base; + q2dheader_t header; + cminfo_t *prv = mod->meshinfo; + size_t i; + qboolean noerrors = true; + + mod->lightmaps.width = LMBLOCK_SIZE_MAX; + mod->lightmaps.height = LMBLOCK_SIZE_MAX; + + prv->mapisq3 = false; + mod->fromgame = fg_halflife2; + mod->engineflags |= MDLF_NEEDOVERBRIGHT; + header.version = LittleLong(srcheader->version); + for (i=0 ; ilumps[i].filelen); + header.lumps[i].fileofs = LittleLong (srcheader->lumps[i].fileofs); + //fixme: truncate lumps if they go off the end + } + BSPX_Setup(mod, mod_base, filelen, header.lumps, i); + + switch(qrenderer) + { + case QR_NONE: //dedicated only + noerrors = noerrors && CModHL2_LoadSurfaces (mod, mod_base, &header.lumps[VLUMP_TEXINFO]); + noerrors = noerrors && CModQ2_LoadPlanes (mod, mod_base, &header.lumps[VLUMP_PLANES]); + noerrors = noerrors && CModQ2_LoadVisibility (mod, mod_base, &header.lumps[VLUMP_VISIBILITY]); + noerrors = noerrors && CModHL2_LoadBrushSides (mod, mod_base, &header.lumps[VLUMP_BRUSHSIDES]); + noerrors = noerrors && CModQ2_LoadBrushes (mod, mod_base, &header.lumps[VLUMP_BRUSHES]); + noerrors = noerrors && CModQ2_LoadLeafBrushes (mod, mod_base, &header.lumps[VLUMP_LEAFBRUSHES]); + noerrors = noerrors && CModHL2_LoadLeafs (mod, mod_base, &header.lumps[VLUMP_LEAFS], header.version); + noerrors = noerrors && CModHL2_LoadNodes (mod, mod_base, &header.lumps[VLUMP_NODES]); + noerrors = noerrors && CModQ2_LoadSubmodels (mod, mod_base, &header.lumps[VLUMP_MODELS]); + 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]); + if (noerrors) + Mod_LoadEntities (mod, mod_base, &header.lumps[VLUMP_ENTITIES]); + +#ifdef HAVE_SERVER + mod->funcs.FatPVS = Q23BSP_FatPVS; + mod->funcs.EdictInFatPVS = Q23BSP_EdictInFatPVS; + mod->funcs.FindTouchedLeafs = Q23BSP_FindTouchedLeafs; +#endif + mod->funcs.LightPointValues = NULL; + mod->funcs.StainNode = NULL; + mod->funcs.MarkLights = NULL; + mod->funcs.ClusterPVS = CM_ClusterPVS; + mod->funcs.ClusterForPoint = CM_PointCluster; + mod->funcs.PointContents = Q2BSP_PointContents; + mod->funcs.NativeTrace = CM_NativeTrace; + mod->funcs.NativeContents = CM_NativeContents; + + break; +#ifdef HAVE_CLIENT + default: + // load into heap + noerrors = noerrors && Mod_LoadVertexes (mod, mod_base, &header.lumps[VLUMP_VERTEXES]); +// if (header.version == BSPVERSION_Q2W) +// /*noerrors = noerrors &&*/ Mod_LoadVertexNormals(mod, mod_base, &header.lumps[19]); + noerrors = noerrors && Mod_LoadEdges (mod, mod_base, &header.lumps[VLUMP_EDGES], false); + noerrors = noerrors && Mod_LoadSurfedges (mod, mod_base, &header.lumps[VLUMP_SURFEDGES]); + if (noerrors) + CModHL2_LoadLighting (mod, mod_base, &header.lumps[VLUMP_LIGHTING], &header.lumps[VLUMP_LIGHTING_HDR]); + noerrors = noerrors && CModHL2_LoadSurfaces (mod, mod_base, &header.lumps[VLUMP_TEXINFO]); + noerrors = noerrors && CModQ2_LoadPlanes (mod, mod_base, &header.lumps[VLUMP_PLANES]); + noerrors = noerrors && CModHL2_LoadTexInfo (mod, mod_base, header.lumps, loadname); + if (noerrors) + Mod_LoadEntities (mod, mod_base, &header.lumps[VLUMP_ENTITIES]); + noerrors = noerrors && CModHL2_LoadFaces (mod, mod_base, header.lumps, header.version); + noerrors = noerrors && Mod_LoadMarksurfaces (mod, mod_base, &header.lumps[VLUMP_LEAFFACES], false); + noerrors = noerrors && CModQ2_LoadVisibility (mod, mod_base, &header.lumps[VLUMP_VISIBILITY]); + noerrors = noerrors && CModHL2_LoadBrushSides (mod, mod_base, &header.lumps[VLUMP_BRUSHSIDES]); + noerrors = noerrors && CModQ2_LoadBrushes (mod, mod_base, &header.lumps[VLUMP_BRUSHES]); + noerrors = noerrors && CModQ2_LoadLeafBrushes (mod, mod_base, &header.lumps[VLUMP_LEAFBRUSHES]); + noerrors = noerrors && CModHL2_LoadLeafs (mod, mod_base, &header.lumps[VLUMP_LEAFS], header.version); + noerrors = noerrors && CModHL2_LoadNodes (mod, mod_base, &header.lumps[VLUMP_NODES]); + noerrors = noerrors && CModQ2_LoadSubmodels (mod, mod_base, &header.lumps[VLUMP_MODELS]); + 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]); + + if (!noerrors) + return false; +#ifdef HAVE_SERVER + mod->funcs.FatPVS = Q23BSP_FatPVS; + mod->funcs.EdictInFatPVS = Q23BSP_EdictInFatPVS; + mod->funcs.FindTouchedLeafs = Q23BSP_FindTouchedLeafs; +#endif + mod->funcs.LightPointValues = GLQ2BSP_LightPointValues; + mod->funcs.StainNode = GLR_Q2BSP_StainNode; + mod->funcs.MarkLights = Q2BSP_MarkLights; + mod->funcs.ClusterPVS = CM_ClusterPVS; + mod->funcs.ClusterForPoint = CM_PointCluster; + mod->funcs.PointContents = Q2BSP_PointContents; + mod->funcs.NativeTrace = CM_NativeTrace; + mod->funcs.NativeContents = CM_NativeContents; + break; +#endif + } + +// if (noerrors) +// CM_CreatePatchesForLeafs (mod, prv); + + return true; +} +#endif + /* ================== CM_LoadMap @@ -4487,6 +5449,20 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole switch(header.version) { +#ifdef HL2BSPS + //case 17: // + case 18: //beta + case 19: //hl2,cs:s,hl2dm + case 20: //portal, l4d, hl2ep2 + case 21: //cs:go, portal 2, l4d2 + //case 22: //dota 2 + //case 23: //dota 2 + //case 27: //'contagion' + //case 29: //'titanfall' + if (!VBSP_LoadModel(mod, filein, filelen, loadname)) + return NULL; + break; +#endif default: Con_Printf (CON_ERROR "Quake 2 or Quake 3 based BSP with unknown header (%s: %i should be %i or %i)\n" , mod->name, header.version, BSPVERSION_Q2, BSPVERSION_Q3); @@ -4854,6 +5830,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole break; #endif } + break; #endif } @@ -6387,6 +7364,7 @@ return; CM_RecursiveHullCheck (mod, node->childnum[side^1], midf, p2f, mid, p2); } + //====================================================================== /* @@ -6806,7 +7784,11 @@ qbyte *CM_ClusterPVS (model_t *mod, int cluster, pvsbuffer_t *buffer, pvsmerge_t if (buffer->buffersize < mod->pvsbytes) buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=mod->pvsbytes); - if (mod->fromgame == fg_quake2) + if (mod->fromgame == fg_quake2 +#ifdef HL2BSPS + || mod->fromgame == fg_halflife2 +#endif + ) { if (cluster == -1) memset (buffer->buffer, 0, (mod->numclusters+7)>>3); @@ -6850,7 +7832,11 @@ qbyte *CM_ClusterPHS (model_t *mod, int cluster, pvsbuffer_t *buffer) buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=mod->pvsbytes); #ifdef Q3BSPS - if (mod->fromgame != fg_quake2) + if (mod->fromgame != fg_quake2 +#ifdef HL2BSPS + && mod->fromgame != fg_halflife2 +#endif + ) { if (cluster != -1 && prv->q3phs->numclusters) { @@ -6935,7 +7921,7 @@ unsigned int Q23BSP_FatPVS(model_t *mod, const vec3_t org, pvsbuffer_t *fte_rest qboolean Q23BSP_EdictInFatPVS(model_t *mod, const pvscache_t *ent, const qbyte *pvs, const int *areas) { int i,l; - int nullarea = (mod->fromgame == fg_quake2)?0:-1; + int nullarea = (mod->fromgame != fg_quake3)?-1:0; if (areas) { for (i = 1; ; i++) diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index bae9d415..128350ca 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -683,6 +683,9 @@ void Mod_Init (qboolean initial) Mod_RegisterModelFormatMagic(NULL, "Raven Map (bsp)", ('R'<<0)+('B'<<8)+('S'<<16)+('P'<<24), Mod_LoadQ2BrushModel); Mod_RegisterModelFormatMagic(NULL, "QFusion Map (bsp)", ('F'<<0)+('B'<<8)+('S'<<16)+('P'<<24), Mod_LoadQ2BrushModel); #endif +#ifdef HL2BSPS + Mod_RegisterModelFormatMagic(NULL, "HL2/'Source' Map (bsp)", ('V'<<0)+('B'<<8)+('S'<<16)+('P'<<24), Mod_LoadQ2BrushModel); +#endif //doom maps #ifdef MAP_DOOM @@ -774,7 +777,11 @@ mleaf_t *Mod_PointInLeaf (model_t *model, vec3_t p) if (!model->nodes) return NULL; #if defined(Q2BSPS) || defined(Q3BSPS) - if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3) + if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3 +#ifdef HL2BSPS + || model->fromgame == fg_halflife2 +#endif + ) { return model->leafs + CM_PointLeafnum(model, p); } @@ -2463,6 +2470,20 @@ void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, builddata_t *co } } +#ifdef HL2BSPS + if (mod->fromgame == fg_halflife2) + { + s = DotProduct (vec, surf->texinfo->lmvecs[0]) + surf->texinfo->lmvecs[0][3]; + t = DotProduct (vec, surf->texinfo->lmvecs[1]) + surf->texinfo->lmvecs[1][3]; + for (sty = 0; sty < 1; sty++) + { + mesh->lmst_array[sty][i][0] = (s - surf->texturemins[0] + surf->light_s[sty] + 0.5) / (mod->lightmaps.width); + mesh->lmst_array[sty][i][1] = (t - surf->texturemins[1] + surf->light_t[sty] + 0.5) / (mod->lightmaps.height); + } + } +#endif + + //figure out the texture directions, for bumpmapping and stuff if (mod->normals && (surf->texinfo->flags & 0x800) && (mod->normals[vertidx][0] || mod->normals[vertidx][1] || mod->normals[vertidx][2])) { @@ -2820,6 +2841,9 @@ static int Mod_Batches_Generate(model_t *mod) { #ifdef Q2BSPS case fg_quake2: +#ifdef HL2BSPS + case fg_halflife2: +#endif batch->buildmeshes = Mod_UpdateBatchShader_Q2; break; #endif @@ -4074,6 +4098,9 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *m switch(loadmodel->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: +#endif case LM_E5BGR9: lofsscale = 4; break; @@ -5022,7 +5049,12 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b) else #endif #ifdef Q2BSPS - if (mod->fromgame == fg_quake2) + if (mod->fromgame == fg_quake2 + +#ifdef HL2BSPS + || mod->fromgame == fg_halflife2 +#endif + ) { COM_FileBase (mod->name, loadname, sizeof(loadname)); for(a = 0; a < mod->numtextures; a++) diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 0b293eee..cf3b145e 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -389,6 +389,9 @@ typedef struct #define SURF_NOFLAT 0x08000 #define SURF_DRAWALPHA 0x10000 #define SURF_NODRAW 0x20000 //set on non-vertical halflife water submodel surfaces +#ifdef HL2BSPS +#define SURF_ONNODE 0x40000 //o.O +#endif // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct @@ -403,8 +406,12 @@ typedef struct mtexinfo_s texture_t *texture; int flags; +#ifdef HL2BSPS + float lmvecs[2][4]; +#endif + //it's a q2 thing. - int numframes; +// int numframes; struct mtexinfo_s *next; } mtexinfo_t; @@ -874,7 +881,12 @@ typedef struct { // typedef enum {mod_brush, mod_sprite, mod_alias, mod_dummy, mod_halflife, mod_heightmap} modtype_t; -typedef enum {fg_quake, fg_quake2, fg_quake3, fg_halflife, fg_new, fg_doom, fg_doom3} fromgame_t; //useful when we have very similar model types. (eg quake/halflife bsps) + +typedef enum {fg_quake, fg_quake2, fg_quake3, fg_halflife, +#ifdef HL2BSPS +fg_halflife2, //these should probably be switched to bits, so that I can easily check multiple (and define to 0 to easily no-op code). +#endif +fg_new, fg_doom, fg_doom3} fromgame_t; //useful when we have very similar model types. (eg quake/halflife bsps) #define MF_ROCKET (1u<<0) // leave a trail #define MF_GRENADE (1u<<1) // leave a trail @@ -1068,7 +1080,10 @@ typedef struct model_s //internally, we still use integers for lighting, with .7 bits of extra precision. LM_L8, LM_RGB8, - LM_E5BGR9 + LM_E5BGR9, +#ifdef HL2BSPS + LM_E8BGR8, //erk? +#endif } fmt; qboolean deluxemapping; //lightmaps are interleaved with deluxemap data (lightmap indicies should only be even values) qboolean deluxemapping_modelspace; //deluxemaps are in modelspace - we need different glsl. @@ -1183,5 +1198,9 @@ qofs_t CM_ReadPortalState (model_t *mod, qbyte *ptr, qofs_t ptrsize); #endif //Q2BSPS +#ifdef HL2BSPS +void CModHL2_DrawAreaPortals(model_t *mod); +#endif + void CategorizePlane ( mplane_t *plane ); void CalcSurfaceExtents (model_t *mod, msurface_t *s); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 1e0881d9..14b2a5cf 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -2543,6 +2543,21 @@ static int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) { switch(cl.worldmodel->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + unsigned int l = *(unsigned int*)lightmap; + scale = d_lightstylevalue[surf->styles[maps]]; + scale *= pow(2, (signed char)(l>>24)); + + r += max3(((l>> 0)&0xff), ((l>> 8)&0xff), ((l>>16)&0xff)) * scale; + + lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1)<<2; + } + break; +#endif case LM_E5BGR9: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) @@ -2637,7 +2652,11 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t float scale, overbright; int maps; - if (mod->fromgame == fg_quake2) + if (mod->fromgame == fg_quake2 +#ifdef HL2BSPS + || mod->fromgame == fg_halflife2 +#endif + ) { if (node->contents != -1) return NULL; // solid @@ -2681,8 +2700,18 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t tex = surf->texinfo; - s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; - t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3]; +#ifdef HL2BSPS + if (mod->fromgame == fg_halflife2) + { + s = DotProduct (mid, tex->lmvecs[0]) + tex->lmvecs[0][3]; + t = DotProduct (mid, tex->lmvecs[1]) + tex->lmvecs[1][3]; + } + else +#endif + { + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3]; + } if (s < surf->texturemins[0] || t < surf->texturemins[1]) @@ -2714,6 +2743,34 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t { switch(mod->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: //FIXME + deluxmap = ((surf->samples - mod->lightdata)>>2)*3 + mod->deluxdata; + + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; + deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<4; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + unsigned int lm = *(unsigned int*)lightmap; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; + //scale *= pow(2, (int)(lm>>27)-15-9+8); + scale *= pow(2, (signed char)(lm>>24)); + + l[0] += ((lm>> 0)&0xff) * scale * cl_lightstyle[surf->styles[maps]].colours[0]; + l[1] += ((lm>> 8)&0xff) * scale * cl_lightstyle[surf->styles[maps]].colours[1]; + l[2] += ((lm>>16)&0xff) * scale * cl_lightstyle[surf->styles[maps]].colours[2]; + + l[3] += (deluxmap[0]-127)*scale; + l[4] += (deluxmap[1]-127)*scale; + l[5] += (deluxmap[2]-127)*scale; + + lightmap += ((surf->extents[0]>>surf->lmshift)+1) * + ((surf->extents[1]>>surf->lmshift)+1)<<2; + deluxmap += ((surf->extents[0]>>surf->lmshift)+1) * + ((surf->extents[1]>>surf->lmshift)+1) * 3; + } + break; +#endif case LM_E5BGR9: deluxmap = ((surf->samples - mod->lightdata)>>2)*3 + mod->deluxdata; @@ -2792,6 +2849,25 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t { switch(mod->lightmaps.fmt) { +#ifdef HL2BSPS + case LM_E8BGR8: //FIXME + lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + { + unsigned int lm = *(unsigned int*)lightmap; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; + //scale *= pow(2, (int)(lm>>27)-15-9+8); + scale *= pow(2, (signed char)(lm>>24)); + + l[0] += ((lm>> 0)&0xff) * scale * cl_lightstyle[surf->styles[maps]].colours[0]; + l[1] += ((lm>> 8)&0xff) * scale * cl_lightstyle[surf->styles[maps]].colours[1]; + l[2] += ((lm>>16)&0xff) * scale * cl_lightstyle[surf->styles[maps]].colours[2]; + + lightmap += ((surf->extents[0]>>surf->lmshift)+1) * + ((surf->extents[1]>>surf->lmshift)+1)<<2; + } + break; +#endif case LM_E5BGR9: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++)