diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 8567ac86..afaad34f 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -4046,9 +4046,22 @@ void Surf_DrawWorld (void) } else { + size_t i; + dispinfo_t *disp; + msurface_t *surf; areas[0] = 1; areas[1] = r_viewarea; Surf_RecursiveHL2WorldNode (currentmodel->nodes); + for (i = 0; i < currentmodel->numdisplacements; i++) + { + disp = ¤tmodel->displacements[i]; + if (currentmodel->funcs.EdictInFatPVS(currentmodel, &disp->pvs, surfvis, areas)) + { + surf = disp->surf; + Surf_RenderDynamicLightmaps (surf); + surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh; + } + } } } #endif diff --git a/engine/common/com_bih.h b/engine/common/com_bih.h index caa57766..f23686bb 100644 --- a/engine/common/com_bih.h +++ b/engine/common/com_bih.h @@ -13,6 +13,7 @@ typedef struct { mplane_t *plane; q2mapsurface_t *surface; + struct dispinfo_s *dispinfo; } q2cbrushside_t; typedef struct q2cbrush_s { diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 9c0fba07..b1962725 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -42,6 +42,10 @@ cvar_t q3bsp_mergeq3lightmaps = CVARD("q3bsp_mergelightmaps", "1", "Specifies wh cvar_t q3bsp_ignorestyles = CVARD("q3bsp_ignorestyles", "0", "Ignores multiple lightstyles in Raven's q3bsp variant(and derivatives) for better batch/rendering performance."); cvar_t q3bsp_bihtraces = CVARFD("_q3bsp_bihtraces", /*FIXME: generate BIH leafs more carefully*/"0", CVAR_RENDERERLATCH, "Uses runtime-generated bih collision culling for faster traces."); +#ifdef HL2BSPS +static cvar_t hl2_displacement_scale = CVARFD("hl2_displacement_scale", "1", CVAR_RENDERERLATCH|CVAR_CHEAT, "Multiplier for how far displacements can move."); +#endif + #if Q3SURF_NODRAW != TI_NODRAW #error "nodraw isn't constant" #endif @@ -4385,14 +4389,20 @@ static void CM_BuildBIH(model_t *mod, int submodel) if (!q3bsp_bihtraces.ival) return; //skip this. fall back on other stuff. - if (mod->fromgame != fg_quake3) - return; +// if (mod->fromgame == fg_quake2) +// return; bihleafs = sub->num_brushes; for (i = 0; i < sub->num_patches; i++) bihleafs += prv->patches[sub->firstpatch + i].numfacets; for (i = 0; i < sub->num_cmeshes; i++) bihleafs += prv->cmeshes[sub->firstcmesh + i].numincidies/3; +#ifdef HL2BSPS + if (!submodel) + for (i = 0; i < mod->numdisplacements; i++) + bihleafs += mod->displacements[i].numindexes/3; +#endif + bihleaf = l = BZ_Malloc(sizeof(*bihleaf)*bihleafs); //now we have enough storage, spit them out providing bounds info. @@ -4407,6 +4417,31 @@ static void CM_BuildBIH(model_t *mod, int submodel) VectorCopy(b->absmaxs, l->maxs); l++; } +#ifdef HL2BSPS + if (!submodel) + for (i = 0; i < mod->numdisplacements; i++) + { + dispinfo_t *d = &mod->displacements[i]; + + size_t j; + for (j = 0; j < d->numindexes; j+=3) + { + index_t *v = d->idx+j; + vec_t *v1 = d->xyz[v[0]], *v2 = d->xyz[v[1]], *v3 = d->xyz[v[2]]; + + l->type = BIH_TRIANGLE; + l->data.tri.xyz = d->xyz; + l->data.tri.indexes = v; + + l->data.contents = d->contents; + VectorCopy(v1, l->mins); + VectorCopy(v1, l->maxs); + AddPointToBounds(v2, l->mins, l->maxs); + AddPointToBounds(v3, l->mins, l->maxs); + l++; + } + } +#endif #ifdef Q3BSPS for (i = 0; i < sub->num_patches; i++) { @@ -4482,16 +4517,16 @@ enum hllumps_e // VLUMP_FOO = 23, // VLUMP_FOO = 24, // VLUMP_FOO = 25, -// VLUMP_FOO = 26, + VLUMP_DISP_INFO = 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_DISP_LMALPHA = 32, + VLUMP_DISP_VERTS = 33, + VLUMP_DISP_LMCOORDS = 34, + VLUMP_GAMELUMP = 35, // VLUMP_FOO = 36, // VLUMP_FOO = 37, // VLUMP_FOO = 38, @@ -4505,7 +4540,7 @@ enum hllumps_e // VLUMP_FOO = 45, // VLUMP_FOO = 46, // VLUMP_FOO = 47, -// VLUMP_FOO = 48, + VLUMP_DISP_TRIFLAGS = 48, // VLUMP_FOO = 49, // VLUMP_FOO = 50, // VLUMP_FOO = 51, @@ -4566,7 +4601,6 @@ static qboolean CModHL2_LoadSurfaces (model_t *mod, qbyte *mod_base, lump_t *l) return true; } - #ifdef HAVE_CLIENT typedef struct { @@ -5069,6 +5103,183 @@ static qboolean CModHL2_LoadAreaPortals (model_t *mod, qbyte *mod_base, lump_t * return true; } +typedef struct +{ //the main displacement lump + vec3_t position; //not really sure how to use this. + int firstvert; //((1<surfaces index + unsigned int lightmapalphaoffset; //erk, rgba? that's going to restrict lightmap formats. + unsigned int lightofs; //extents? cabbage? oh noes we've gone mad again! or is this some special blend weights in addition to the surface's lighting? + struct + { //erk + unsigned short peer; + unsigned char orientation; + unsigned char span; + unsigned char peerspan; + } edgepeers[8]; //two per edge + struct + { //no idea how this works + unsigned short peer[4]; + unsigned char numpeers; + } cornerpeers[4]; + unsigned int allowedverts[10]; +} hl2ddisplacement_t; +typedef struct +{ + vec3_t norm; + float dist; + float alpha; //vertex alpha. +} hl2displacementvert_t; +static qboolean CModHL2_LoadDisplacements (model_t *mod, qbyte *mod_base, lump_t *lumps) +{ + lump_t *l = &lumps[VLUMP_DISP_INFO]; + lump_t *vl = &lumps[VLUMP_DISP_VERTS]; + hl2ddisplacement_t *in; + dispinfo_t *out; + int i, count, x, y; + hl2displacementvert_t *inv; + struct dispvert_s *verts; + vecV_t *xyz; + index_t *indexes; + size_t maxverts; + msurface_t *surf; + float *sverts[4]; + signed int e, idx; + float fx,fy; + vec3_t p, base; + size_t stride; + + int primary; + float pdist,dist; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + { + Con_Printf ("MOD_LoadBmodel: funny lump size in %s\n",mod->name); + return false; + } + count = l->filelen / sizeof(*in); + if (!count) + return true; //nothing to worry about. + out = ZG_Malloc(&mod->memgroup, count*sizeof(*out)); + + for (maxverts = 0, i = 0; i < count; i++) + maxverts += ((1<memgroup, maxverts*sizeof(*indexes)*6); + + for (maxverts = 0, i = 0; i < count; i++) + maxverts += ((1<memgroup, maxverts*sizeof(*verts)); + xyz = ZG_Malloc(&mod->memgroup, maxverts*sizeof(*xyz)); + + mod->displacements = out; + mod->numdisplacements = count; + for (i = 0; i < count; i++, out++, in++) + { + surf = mod->surfaces + in->faceidx; + if (surf->numedges != 4) + { + Con_Printf ("MOD_LoadBmodel: displacement surface doesn't have 4 edges in %s\n",mod->name); + return false; + } + + //find the 4 verts... messy. + for (x = 0; x < 4; x++) + { + e = mod->surfedges[surf->firstedge+x]; + idx = e < 0; + if (idx) + e = -e; + if (e < 0 || e >= mod->numedges) + sverts[x] = mod->vertexes[0].position; + else + sverts[x] = mod->vertexes[mod->edges[e].v[idx]].position; + } + + //this is just stupid and pointless. + //the in->position point tells us which point is the primary one, instead of just rotating the edges. + primary = 0; + pdist = FLT_MAX; + for (x = 0; x < 4; x++) + { + VectorSubtract(sverts[x], in->position, p); + dist = DotProduct(p,p); + if (dist < pdist) + { + pdist = dist; + primary = x; + } + } + + out->surf = surf; + surf->dispinfo = out; //the surface needs to be able to get its proper info when building vbos + ClearBounds(out->aamin, out->aamax); + out->contents = in->contents; + out->width = (1<power); + out->height = (1<power); + + out->idx = indexes; + stride = out->width+1; + for (y=0 ; yheight ; y++) + for (x=0 ; xwidth ; x++) + { + if ((x+y)&1) + { //a diamond pattern - flipping alternately + *indexes++ = (x+0)+(y+1)*stride; + *indexes++ = (x+1)+(y+1)*stride; + *indexes++ = (x+1)+(y+0)*stride; + *indexes++ = (x+0)+(y+1)*stride; + *indexes++ = (x+1)+(y+0)*stride; + *indexes++ = (x+0)+(y+0)*stride; + } + else + { + *indexes++ = (x+0)+(y+0)*stride; + *indexes++ = (x+0)+(y+1)*stride; + *indexes++ = (x+1)+(y+1)*stride; + *indexes++ = (x+0)+(y+0)*stride; + *indexes++ = (x+1)+(y+1)*stride; + *indexes++ = (x+1)+(y+0)*stride; + } + } + out->numindexes = indexes - out->idx; + + inv = (void *)(mod_base + vl->fileofs); + inv += in->firstvert; + out->verts = verts; + out->xyz = xyz; + for (y = 0; y <= out->height; y++) + for (x = 0; x <= out->width; x++) + { + //I have no idea if this is right. probably not. oh well. + fx = (float)x/out->width; + fy = (float)y/out->height; + VectorClear(base); + VectorMA(base, (1-fx)*(1-fy), sverts[(primary+0)&3], base); + VectorMA(base, (1-fx)*( fy), sverts[(primary+1)&3], base); + VectorMA(base, ( fx)*( fy), sverts[(primary+2)&3], base); + VectorMA(base, ( fx)*(1-fy), sverts[(primary+3)&3], base); + verts->st[0] = DotProduct(base, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; + verts->st[1] = DotProduct(base, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; + + VectorScale(inv->norm, inv->dist*hl2_displacement_scale.value, p); + VectorNormalize2(p, verts->norm); + VectorAdd(base, p, (*xyz)); + verts->alpha = inv->alpha; + AddPointToBounds((*xyz), out->aamin, out->aamax); + + inv++; + verts++; + xyz++; + } + } + return true; +} #ifdef HAVE_CLIENT typedef struct { @@ -5256,6 +5467,10 @@ static qboolean CModHL2_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l out->surface = &nullsurface; else out->surface = &prv->surfaces[j]; + if (in->dispinfo != 0xffff) + out->dispinfo = mod->displacements+in->dispinfo; + else + out->dispinfo = NULL; } return true; @@ -5341,6 +5556,7 @@ static qboolean VBSP_LoadModel(model_t *mod, qbyte *mod_base, size_t filelen, ch if (noerrors) Mod_LoadEntities (mod, mod_base, &header.lumps[VLUMP_ENTITIES]); noerrors = noerrors && CModHL2_LoadFaces (mod, mod_base, header.lumps, header.version); + noerrors = noerrors && CModHL2_LoadDisplacements(mod, mod_base, header.lumps); 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]); @@ -5371,6 +5587,9 @@ static qboolean VBSP_LoadModel(model_t *mod, qbyte *mod_base, size_t filelen, ch #endif } + //displacements suck + for (i = 0; i < mod->numdisplacements; i++) + mod->funcs.FindTouchedLeafs(mod, &mod->displacements[i].pvs, mod->displacements[i].aamin, mod->displacements[i].aamax); // if (noerrors) // CM_CreatePatchesForLeafs (mod, prv); @@ -6429,6 +6648,13 @@ static void CM_FinalizeBrush(q2cbrush_t *brush) } for (i = 0; i < brush->numsides; i++) { +#ifdef HL2BSPS + if (brush->brushside[i].dispinfo) + { + AddPointToBounds(brush->brushside[i].dispinfo->aamin, brush->absmins, brush->absmaxs); + AddPointToBounds(brush->brushside[i].dispinfo->aamax, brush->absmins, brush->absmaxs); + } +#endif //most brushes are axial, which can save some a little loadtime if (planes[i][0] == 1) brush->absmaxs[0] = planes[i][3]; @@ -7364,7 +7590,6 @@ return; CM_RecursiveHullCheck (mod, node->childnum[side^1], midf, p2f, mid, p2); } - //====================================================================== /* @@ -8287,6 +8512,10 @@ void CM_Init(void) //register cvars. Cvar_Register(&q3bsp_bihtraces, MAPOPTIONS); Cvar_Register(&r_subdivisions, MAPOPTIONS); +#ifdef HL2BSPS + Cvar_Register(&hl2_displacement_scale, MAPOPTIONS); +#endif + CM_InitBoxHull (); } #endif diff --git a/engine/common/world.h b/engine/common/world.h index 8e34e0a7..75b7c5f6 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -27,13 +27,6 @@ typedef struct plane_s float dist; } plane_t; -typedef struct csurface_s -{ - char name[16]; - int flags; - int value; -} q2csurface_t; - typedef struct cplane_s { vec3_t normal; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 128350ca..f89f189f 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2408,8 +2408,57 @@ void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, builddata_t *co mesh->colors4f_array[0] = (vec4_t*)(mesh->tnormals_array+mesh->numvertexes); mesh->indexes = (index_t*)(mesh->colors4f_array[0]+mesh->numvertexes); } - mesh->istrifan = true; +#ifdef HL2BSPS + if (surf->dispinfo) + { + dispinfo_t *d = surf->dispinfo; + struct dispvert_s *dv = d->verts; + + memcpy(mesh->indexes, d->idx, sizeof(index_t)*d->numindexes); + + //output the renderable verticies + for (i=0 ; inumvertexes ; i++, dv++) + { + //xyz + VectorCopy (d->xyz[i], mesh->xyz_array[i]); + + //st + mesh->st_array[i][0] = dv->st[0]; + mesh->st_array[i][1] = dv->st[1]; + if (surf->texinfo->texture->vwidth) + mesh->st_array[i][0] /= surf->texinfo->texture->vwidth; + if (surf->texinfo->texture->vheight) + mesh->st_array[i][1] /= surf->texinfo->texture->vheight; + + //lmst + s = (float)(i%(d->width+1))/d->width; + t = (float)(i/(d->width+1))/d->height; + for (sty = 0; sty < 1; sty++) + { + mesh->lmst_array[sty][i][0] = (s*surf->extents[0] + surf->light_s[sty] + 0.5) / (mod->lightmaps.width); + mesh->lmst_array[sty][i][1] = (t*surf->extents[1] + surf->light_t[sty] + 0.5) / (mod->lightmaps.height); + } + + //normals + VectorCopy(surf->plane->normal, mesh->normals_array[i]); + VectorCopy(surf->texinfo->vecs[0], mesh->snormals_array[i]); + VectorNegate(surf->texinfo->vecs[1], mesh->tnormals_array[i]); + + //rgba + for (sty = 0; sty < 1; sty++) + { + mesh->colors4f_array[sty][i][0] = 1; + mesh->colors4f_array[sty][i][1] = 1; + mesh->colors4f_array[sty][i][2] = 1; + mesh->colors4f_array[sty][i][3] = ((int)dv->alpha&255)/255.0; + } + } + return; + } +#endif + + mesh->istrifan = true; //output the mesh's indicies for (i=0 ; inumvertexes-2 ; i++) { @@ -3166,6 +3215,13 @@ static void Mod_Batches_Build(model_t *mod, builddata_t *bd) mesh = surf->mesh = &meshlist[i]; mesh->numvertexes = surf->numedges; mesh->numindexes = (surf->numedges-2)*3; +#ifdef HL2BSPS + if (surf->dispinfo) + { + mesh->numvertexes = (surf->dispinfo->width+1)*(surf->dispinfo->height+1); + mesh->numindexes = surf->dispinfo->numindexes; + } +#endif } else mesh = surf->mesh; diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index cf3b145e..2be65ecc 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -54,6 +54,13 @@ typedef enum { SHADER_SORT_COUNT } shadersort_t; +typedef struct csurface_s +{ + char name[16]; + int flags; + int value; +} q2csurface_t; + #ifdef FTE_TARGET_WEB #define MAX_BONES 256 #elif defined(IQMTOOL) @@ -446,6 +453,31 @@ typedef struct texid_t image; } menvmap_t; +#ifdef HL2BSPS +typedef struct dispinfo_s +{ + struct msurface_s *surf; + vec3_t aamin; + vec3_t aamax; + pvscache_t pvs; //which pvs clusters this displacement is visible in... + unsigned int contents; + unsigned int width; + unsigned int height; + vecV_t *xyz; //(width+1)*(height+1) + index_t *idx; //width*height*6; + size_t numindexes; + struct dispvert_s + { + vec3_t norm; + vec2_t st; + float alpha; + } *verts; + //unsigned short *flags; + + q2csurface_t csurface; //collision info for q2 gamecode. +} dispinfo_t; +#endif + #define LMSHIFT_DEFAULT 4 typedef struct msurface_s { @@ -467,6 +499,9 @@ typedef struct msurface_s batch_t *sbatch; mtexinfo_t *texinfo; +#ifdef HL2BSPS + dispinfo_t *dispinfo; +#endif int visframe; // should be drawn when node is crossed #ifdef RTLIGHTS int shadowframe; @@ -1095,6 +1130,11 @@ typedef struct model_s portal_t *portal; unsigned int numportals; +#ifdef HL2BSPS + dispinfo_t *displacements; + unsigned int numdisplacements; +#endif + modelfuncs_t funcs; // // additional model data