From 54e7c2ab8e1ac450a2b01dfa442aa72bb7acd96d Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 27 Apr 2015 00:17:14 -0600 Subject: [PATCH] light: fence texture tracing --- include/light/light.h | 5 + light/light.c | 20 ++++ light/ltface.c | 2 +- light/trace.c | 206 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 223 insertions(+), 10 deletions(-) diff --git a/include/light/light.h b/include/light/light.h index 0291c5b3..d00c6485 100644 --- a/include/light/light.h +++ b/include/light/light.h @@ -144,4 +144,9 @@ extern qboolean write_litfile; void SetupDirt(); +/* Used by fence texture sampling */ +void WorldToTexCoord(const vec3_t world, const texinfo_t *tex, vec_t coord[2]); + +extern qboolean testFenceTextures; + #endif /* __LIGHT_LIGHT_H__ */ diff --git a/light/light.c b/light/light.c index e0dd87cf..6127930a 100644 --- a/light/light.c +++ b/light/light.c @@ -51,6 +51,8 @@ qboolean dirtDepthSetOnCmdline = false; qboolean dirtScaleSetOnCmdline = false; qboolean dirtGainSetOnCmdline = false; +qboolean testFenceTextures = false; + byte *filebase; // start of lightmap data static byte *file_p; // start of free space after data static byte *file_end; // end of free space for lightmap data @@ -224,6 +226,22 @@ LightWorld(bsp2_t *bsp) logprint("lightdatasize: %i\n", bsp->lightdatasize); } +static void +CheckFenceTextures(bsp2_t *bsp) +{ + int i; + for (i = 0; i < bsp->numfaces; i++) { + const bsp2_dface_t *face = &bsp->dfaces[i]; + const texinfo_t *tex = &bsp->texinfo[face->texinfo]; + const int offset = bsp->dtexdata.header->dataofs[tex->miptex]; + const miptex_t *miptex = (const miptex_t *)(bsp->dtexdata.base + offset); + if (miptex->name[0] == '{') { + logprint("Fence texture detected, enabling fence texture tracing on bmodels\n"); + testFenceTextures = true; + break; + } + } +} /* * ================== @@ -370,6 +388,8 @@ main(int argc, const char **argv) if (dirty) SetupDirt(); + CheckFenceTextures(bsp); + MakeTnodes(bsp); modelinfo = malloc(bsp->nummodels * sizeof(*modelinfo)); FindModelInfo(bsp); diff --git a/light/ltface.c b/light/ltface.c index fd888529..7078588c 100644 --- a/light/ltface.c +++ b/light/ltface.c @@ -309,7 +309,7 @@ TexCoordToWorld(vec_t s, vec_t t, const texorg_t *texorg, vec3_t world) Solve3(&texorg->transform, rhs, world); } -static void +void WorldToTexCoord(const vec3_t world, const texinfo_t *tex, vec_t coord[2]) { int i; diff --git a/light/trace.c b/light/trace.c index dda24036..8e4d1b5c 100644 --- a/light/trace.c +++ b/light/trace.c @@ -25,10 +25,13 @@ typedef struct tnode_s { int type; int children[2]; const dplane_t *plane; + const bsp2_dleaf_t *childleafs[2]; + const bsp2_dnode_t *node; } tnode_t; static tnode_t *tnodes; static tnode_t *tnode_p; +static const bsp2_t *bsp_static; /* * ============== @@ -42,11 +45,13 @@ MakeTnodes_r(int nodenum, const bsp2_t *bsp) tnode_t *tnode; int i; bsp2_dnode_t *node; + bsp2_dleaf_t *leaf; tnode = tnode_p++; node = bsp->dnodes + nodenum; tnode->plane = bsp->dplanes + node->planenum; + tnode->node = node; tnode->type = tnode->plane->type; VectorCopy(tnode->plane->normal, tnode->normal); @@ -54,7 +59,9 @@ MakeTnodes_r(int nodenum, const bsp2_t *bsp) for (i = 0; i < 2; i++) { if (node->children[i] < 0) { - tnode->children[i] = bsp->dleafs[-node->children[i] - 1].contents; + leaf = &bsp->dleafs[-node->children[i] - 1]; + tnode->children[i] = leaf->contents; + tnode->childleafs[i] = leaf; } else { tnode->children[i] = tnode_p - tnodes; MakeTnodes_r(node->children[i], bsp); @@ -66,12 +73,165 @@ void MakeTnodes(const bsp2_t *bsp) { int i; - + bsp_static = bsp; tnode_p = tnodes = malloc(bsp->numnodes * sizeof(tnode_t)); for (i = 0; i < bsp->nummodels; i++) MakeTnodes_r(bsp->dmodels[i].headnode[0], bsp); } +/* + * ============================================================================ + * FENCE TEXTURE TESTING + * ============================================================================ + */ + +static qboolean +PointInTri(const vec3_t v0, + const vec3_t v1, + const vec3_t v2, + const vec3_t point, + const vec3_t facenormal) +{ + vec3_t temp; + vec3_t normal[3]; + vec_t dist[3]; + + VectorSubtract (v1, v0, temp); + VectorNormalize (temp); + CrossProduct (temp, facenormal, normal[0]); + dist[0] = DotProduct (v0, normal[0]); + + VectorSubtract (v2, v1, temp); + VectorNormalize (temp); + CrossProduct (temp, facenormal, normal[1]); + dist[1] = DotProduct (v1, normal[1]); + + VectorSubtract (v0, v2, temp); + VectorNormalize (temp); + CrossProduct (temp, facenormal, normal[2]); + dist[2] = DotProduct (v2, normal[2]); + + // check each plane + + if (DotProduct (normal[0], point) - dist[0] < 0) return false; + if (DotProduct (normal[1], point) - dist[1] < 0) return false; + if (DotProduct (normal[2], point) - dist[2] < 0) return false; + + return true; +} + +static qboolean +PointInFace(const bsp2_dface_t *face, const bsp2_t *bsp, const vec3_t point) +{ + int i, edgenum; + dvertex_t *v0, *v1, *v2; + + edgenum = bsp->dsurfedges[face->firstedge]; + if (edgenum >= 0) + v0 = bsp->dvertexes + bsp->dedges[edgenum].v[0]; + else + v0 = bsp->dvertexes + bsp->dedges[-edgenum].v[1]; + + for (i = 1; i < face->numedges - 1; i++) { + edgenum = bsp->dsurfedges[face->firstedge + i]; + if (edgenum >= 0) { + v1 = bsp->dvertexes + bsp->dedges[edgenum].v[0]; + v2 = bsp->dvertexes + bsp->dedges[edgenum].v[1]; + } else { + v1 = bsp->dvertexes + bsp->dedges[-edgenum].v[1]; + v2 = bsp->dvertexes + bsp->dedges[-edgenum].v[0]; + } + + vec3_t p0 = {v0->point[0], v0->point[1], v0->point[2]}; + vec3_t p1 = {v1->point[0], v1->point[1], v1->point[2]}; + vec3_t p2 = {v2->point[0], v2->point[1], v2->point[2]}; + + vec3_t facenormal; + VectorCopy(bsp->dplanes[face->planenum].normal, facenormal); + if (face->side) { + VectorSubtract(vec3_origin, facenormal, facenormal); + } + + if (PointInTri(p0, p1, p2, point, facenormal)) return true; + } + + return false; +} + +static miptex_t * +MiptexForFace(const bsp2_dface_t *face, const bsp2_t *bsp) +{ + const texinfo_t *tex; + dmiptexlump_t *miplump = bsp->dtexdata.header; + miptex_t *miptex; + tex = &bsp->texinfo[face->texinfo]; + + miptex = (miptex_t*)(bsp->dtexdata.base + miplump->dataofs[tex->miptex]); + return miptex; +} + +static int +SampleTexture(const bsp2_dface_t *face, const bsp2_t *bsp, const vec3_t point) +{ + vec_t texcoord[2]; + const texinfo_t *tex; + dmiptexlump_t *miplump = bsp->dtexdata.header; + miptex_t *miptex; + int x, y; + byte *data; + int sample; + + tex = &bsp->texinfo[face->texinfo]; + + WorldToTexCoord(point, tex, texcoord); + + if (miplump->dataofs[tex->miptex] == -1) { + return -1; + } + + miptex = (miptex_t*)(bsp->dtexdata.base + miplump->dataofs[tex->miptex]); + + x = (int)texcoord[0] % miptex->width; + y = (int)texcoord[1] % miptex->height; + + data = (byte*)miptex + miptex->offsets[0]; + sample = data[(miptex->width * y) + x]; + + return sample; +} + +static qboolean +TestHitFace(bsp2_dface_t *face, const vec3_t point) +{ + const dplane_t *plane; + vec_t d; + plane = &bsp_static->dplanes[face->planenum]; + d = DotProduct(point, plane->normal) - plane->dist; + if (d >= -ON_EPSILON && d <= ON_EPSILON) + { + int val = PointInFace(face, bsp_static, point); + if (val) + return true; + } + return false; +} + +static bsp2_dface_t * +SearchNodeForHitFace(const bsp2_dnode_t *bspnode, const vec3_t point) +{ + // search the faces on this node + int i; + for (i=0; inumfaces; i++) + { + bsp2_dface_t *face; + face = &bsp_static->dfaces[bspnode->firstface + i]; + if (TestHitFace(face, point)) { + return face; + } + } + return NULL; +} + /* * ============================================================================ * LINE TRACING @@ -105,11 +265,14 @@ TraceLine(const dmodel_t *model, const int traceflags, tracestack_t *tstack, *crossnode; tnode_t *tnode; const tracestack_t *const tstack_max = tracestack + MAX_TSTACK; - + qboolean isbmodel; + if (traceflags <= 0) Error("Internal error: %s - bad traceflags (%d)", __func__, traceflags); + isbmodel = (model != tracelist[0]); + VectorCopy(start, front); VectorCopy(stop, back); @@ -145,15 +308,40 @@ TraceLine(const dmodel_t *model, const int traceflags, break; } if (tracehit != TRACE_HIT_NONE) { + qboolean done = true; + /* If we haven't crossed, start was inside flagged contents */ if (!crossnode) return -tracehit; - if (hitpoint) { - hitpoint->dplane = crossnode->plane; - hitpoint->side = crossnode->side; - VectorCopy(crossnode->front, hitpoint->point); - } - return tracehit; + + if (isbmodel && testFenceTextures) { + const bsp2_dnode_t *bspnode = tnodes[crossnode->node].node; + bsp2_dface_t *face = SearchNodeForHitFace(bspnode, crossnode->front); + + if (face) { + miptex_t *mt = MiptexForFace(face, bsp_static); + if (mt && mt->name[0] == '{') { + int sample = SampleTexture(face, bsp_static, crossnode->front); + done = (sample != 255); + } else { + /* Non-fence texture was hit, we are done */ + done = true; + } + } else { + /* Continue tracing until we find the face we hit */ + done = false; + } + } + + if (done) { + if (hitpoint) { + hitpoint->dplane = crossnode->plane; + hitpoint->side = crossnode->side; + VectorCopy(crossnode->front, hitpoint->point); + } + + return tracehit; + } } /* If the stack is empty, no obstructions were hit */