light: fence texture tracing

This commit is contained in:
Eric Wasylishen 2015-04-27 00:17:14 -06:00
parent a33c4b0136
commit 54e7c2ab8e
4 changed files with 223 additions and 10 deletions

View File

@ -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__ */

View File

@ -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);

View File

@ -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;

View File

@ -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; i<bspnode->numfaces; 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 */