From 0b4c044473bf6d2b8c3b25122a283a05efb0895e Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Fri, 4 Mar 2016 20:40:14 -0700 Subject: [PATCH] light: fix dirtmapping traces --- include/light/light.h | 8 +++++ light/ltface.c | 74 +++++++++++++++++++------------------------ light/trace.c | 54 ++++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 46 deletions(-) diff --git a/include/light/light.h b/include/light/light.h index 4e359c8a..57e66d6c 100644 --- a/include/light/light.h +++ b/include/light/light.h @@ -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; diff --git a/light/ltface.c b/light/ltface.c index 65919410..e7a0a927 100644 --- a/light/ltface.c +++ b/light/ltface.c @@ -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; } } diff --git a/light/trace.c b/light/trace.c index 1f6b1389..36a5a430 100644 --- a/light/trace.c +++ b/light/trace.c @@ -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; inumedges; 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; inumedges; 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.