light: fix dirtmapping traces

This commit is contained in:
Eric Wasylishen 2016-03-04 20:40:14 -07:00
parent 98a020fde7
commit 0b4c044473
3 changed files with 90 additions and 46 deletions

View File

@ -45,8 +45,15 @@ extern "C" {
typedef struct traceinfo_s {
vec3_t point;
const bsp2_dface_t *face;
/* returns true if sky was hit. */
bool hitsky;
bool hitback;
// internal
vec3_t dir;
} traceinfo_t;
/* Stopped by solid and sky */
bool TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end);
@ -92,6 +99,7 @@ int TraceLine(const dmodel_t *model, const int traceflags,
*/
qboolean TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self);
qboolean TestLight(const vec3_t start, const vec3_t stop, const dmodel_t *self);
qboolean DirtTrace(const vec3_t start, const vec3_t stop, const dmodel_t *self, vec3_t hitpoint_out);
typedef struct {
vec_t light;

View File

@ -679,25 +679,18 @@ CalcPoints(const dmodel_t *model, const vec3_t offset, const texorg_t *texorg, l
VectorCopy(surf->plane.normal, norm);
}
for (i = 0; i < 6; i++) {
const int flags = TRACE_HIT_SOLID;
tracepoint_t hit;
int result;
vec_t dist;
result = TraceLine(model, flags, midpoint, point, &hit);
if (result == TRACE_HIT_NONE)
break;
if (result != TRACE_HIT_SOLID) {
WarnBadMidpoint(midpoint);
break;
}
/* Move the point 1 unit above the obstructing surface */
dist = DotProduct(point, hit.dplane->normal) - hit.dplane->dist;
dist = hit.side ? -dist - 1 : -dist + 1;
VectorScale(hit.dplane->normal, dist, move);
VectorAdd(point, move, point);
vec3_t tracedir;
VectorSubtract(point, midpoint, tracedir);
VectorNormalize(tracedir);
// trace 1 unit further than we need to go to ensure 1 unit clearance
vec3_t dest;
VectorMA(point, 1, tracedir, dest);
vec3_t hitpoint = {0};
if (DirtTrace(midpoint, dest, model, hitpoint)) {
// we hit a solid. pull back 1 unit from the hitpoint and hope that's in empty space.
VectorMA(hitpoint, -1, tracedir, point);
}
}
}
@ -1484,22 +1477,20 @@ qboolean
DirtTrace(const vec3_t start, const vec3_t stop, const dmodel_t *self, vec3_t hitpoint_out)
{
const dmodel_t *const *model;
const int traceflags = TRACE_HIT_SOLID | TRACE_HIT_SKY;
int result = TRACE_HIT_NONE;
tracepoint_t hitpoint;
traceinfo_t ti = {0};
VectorSubtract(stop, start, ti.dir);
VectorNormalize(ti.dir);
if (self) {
result = TraceLine(self, traceflags, start, stop, &hitpoint);
if (result == -TRACE_HIT_SOLID) {
/* We started in the void, which ideally wouldn't happen,
but does (say on e1m1). Return the start point as the hitpoint,
which will make fully black dirt.
*/
VectorCopy(start, hitpoint_out);
return true;
} else if (result == TRACE_HIT_SOLID) {
VectorCopy(hitpoint.point, hitpoint_out);
return true;
if (TraceFaces (&ti, self->headnode[0], start, stop)) {
VectorCopy(ti.point, hitpoint_out);
if (ti.hitback) {
VectorCopy(start, hitpoint_out);
}
return !ti.hitsky;
}
}
@ -1507,13 +1498,14 @@ DirtTrace(const vec3_t start, const vec3_t stop, const dmodel_t *self, vec3_t hi
for (model = tracelist; *model; model++) {
if (*model == self)
continue;
result = TraceLine(*model, traceflags, start, stop, &hitpoint);
if (result == -TRACE_HIT_SOLID) {
VectorCopy(start, hitpoint_out);
return true;
} else if (result == TRACE_HIT_SOLID) {
VectorCopy(hitpoint.point, hitpoint_out);
return true;
if (TraceFaces (&ti, (*model)->headnode[0], start, stop)) {
VectorCopy(ti.point, hitpoint_out);
if (ti.hitback) {
VectorCopy(start, hitpoint_out);
}
return !ti.hitsky;
}
}

View File

@ -37,6 +37,8 @@ typedef struct faceinfo_s {
vec3_t origin;
vec_t radiusSquared;
int content;
plane_t plane;
} faceinfo_t;
static tnode_t *tnodes;
@ -137,14 +139,43 @@ static inline bool SphereCullPoint(const faceinfo_t *info, const vec3_t point)
return deltaLengthSquared > info->radiusSquared;
}
static int
Face_Contents(const bsp2_t *bsp, const bsp2_dface_t *face)
{
if (face->texinfo < 0)
return CONTENTS_SOLID;
if (!(bsp->texinfo[face->texinfo].flags & TEX_SPECIAL))
return CONTENTS_SOLID;
int texnum = bsp->texinfo[face->texinfo].miptex;
const dmiptexlump_t *miplump = bsp->dtexdata.header;
const miptex_t *miptex;
if (!miplump->dataofs[texnum])
return CONTENTS_SOLID; //sometimes the texture just wasn't written. including its name.
miptex = (miptex_t*)(bsp->dtexdata.base + miplump->dataofs[texnum]);
if (!Q_strncasecmp(miptex->name, "sky", 3))
return CONTENTS_SKY;
else if (!Q_strncasecmp(miptex->name, "*lava", 5))
return CONTENTS_LAVA;
else if (!Q_strncasecmp(miptex->name, "*slime", 6))
return CONTENTS_SLIME;
else if (miptex->name[0] == '*')
return CONTENTS_WATER;
else
return CONTENTS_SOLID;
}
void
MakeFaceInfo(const bsp2_t *bsp, const bsp2_dface_t *face, faceinfo_t *info)
{
info->numedges = face->numedges;
info->edgeplanes = calloc(face->numedges, sizeof(plane_t));
plane_t surfplane;
GetFaceNormal(bsp, face, &surfplane);
GetFaceNormal(bsp, face, &info->plane);
// make edge planes
for (int i=0; i<face->numedges; i++)
@ -158,7 +189,7 @@ MakeFaceInfo(const bsp2_t *bsp, const bsp2_dface_t *face, faceinfo_t *info)
VectorSubtract(v1, v0, edgevec);
VectorNormalize(edgevec);
CrossProduct(edgevec, surfplane.normal, dest->normal);
CrossProduct(edgevec, info->plane.normal, dest->normal);
dest->dist = DotProduct(dest->normal, v0);
}
@ -187,6 +218,8 @@ MakeFaceInfo(const bsp2_t *bsp, const bsp2_dface_t *face, faceinfo_t *info)
}
info->radiusSquared = maxRadiusSq;
info->content = Face_Contents(bsp, face);
#if 0
//test
for (int i=0; i<face->numedges; i++)
@ -572,8 +605,19 @@ bool TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end
bsp2_dface_t *face = SearchNodeForHitFace(tnode->node, mid);
if (face) {
ti->face = face;
return true;
int facenum = face - bsp_static->dfaces;
const faceinfo_t *fi = &faceinfos[facenum];
// only solid and sky faces stop the trace.
if (fi->content == CONTENTS_SOLID || fi->content == CONTENTS_SKY) {
ti->face = face;
ti->hitsky = (fi->content == CONTENTS_SKY);
// check if we hit the back side
ti->hitback = (DotProduct(ti->dir, fi->plane.normal) >= 0);
return true;
}
}
//ericw -- no impact found on this node.