light: rewrite light tracing function and update callers
Substantial changes to TestLineOrSky which now becomes TraceLine to more conveniently trace lines through the BSP and, terminate the trace on specific contents and return information about the termination point. TraceLine also more correcly handles the cases where points are close enough to the node planes to be considered "on-node" to ensure we get a good intersection point back, when requested. Finally, the algorithm for making the small adjustments to surface points in CalcPoints has been changed so if the surface point can't see the midpoint, we find the obscuring surface and move the surface point just above that. Seems to work better and eliminates some (but not quite all - midpoint is still not quite the ideal point to use) random black spots. Signed-off-by: Kevin Shanahan <kmshanah@disenchant.net>
This commit is contained in:
parent
f208efcfa0
commit
cc36d8eadc
|
|
@ -32,10 +32,48 @@
|
|||
|
||||
#define MAXLIGHTS 1024
|
||||
|
||||
qboolean TestSky(const vec3_t start, const vec3_t dirn, vec3_t skypoint);
|
||||
qboolean TestLine(const vec3_t start, const vec3_t stop);
|
||||
qboolean TestLineModel(const dmodel_t *model,
|
||||
const vec3_t start, const vec3_t stop);
|
||||
|
||||
#define TRACE_HIT_NONE 0
|
||||
#define TRACE_HIT_SOLID (1 << 0)
|
||||
#define TRACE_HIT_WATER (1 << 1)
|
||||
#define TRACE_HIT_SLIME (1 << 2)
|
||||
#define TRACE_HIT_LAVA (1 << 3)
|
||||
#define TRACE_HIT_SKY (1 << 4)
|
||||
|
||||
typedef struct {
|
||||
const dplane_t *dplane;
|
||||
int side;
|
||||
vec3_t point;
|
||||
} tracepoint_t;
|
||||
|
||||
/*
|
||||
* ---------
|
||||
* TraceLine
|
||||
* ---------
|
||||
* Generic BSP model ray tracing function. Traces a ray from start towards
|
||||
* stop. If the trace line hits one of the flagged contents along the way, the
|
||||
* corresponding TRACE flag will be returned. Furthermore, if hitpoint is
|
||||
* non-null, information about the point the ray hit will be filled in.
|
||||
*
|
||||
* model - The bsp model to trace against
|
||||
* flags - contents which will stop the trace (must be > 0)
|
||||
* start - coordinates to start trace
|
||||
* stop - coordinates to end the trace
|
||||
* hitpoint - filled in if result > 0 and hitpoint is non-NULL
|
||||
*
|
||||
* TraceLine will return a negative traceflag if the point 'start' resides
|
||||
* inside a leaf with one of the contents types which stop the trace.
|
||||
*/
|
||||
int TraceLine(const dmodel_t *model, const int traceflags,
|
||||
const vec3_t start, const vec3_t end, tracepoint_t *hitpoint);
|
||||
|
||||
/*
|
||||
* Convenience functions TestLight and TestSky will test against all shadow
|
||||
* casting bmodels and self-shadow the model 'self' if self != NULL. Returns
|
||||
* true if sky or light is visible, respectively.
|
||||
*/
|
||||
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);
|
||||
|
||||
typedef struct {
|
||||
vec_t light;
|
||||
|
|
|
|||
136
light/ltface.c
136
light/ltface.c
|
|
@ -336,6 +336,29 @@ CalcFaceExtents(const dface_t *face, const vec3_t offset, lightsurf_t *surf)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print warning for CalcPoint where the midpoint of a polygon, one
|
||||
* unit above the surface is covered by a solid brush.
|
||||
*/
|
||||
static void
|
||||
WarnBadMidpoint(const vec3_t point)
|
||||
{
|
||||
#if 0
|
||||
static qboolean warned = false;
|
||||
|
||||
if (warned)
|
||||
return;
|
||||
|
||||
warned = true;
|
||||
logprint("WARNING: unable to lightmap surface near (%s)\n"
|
||||
" This is usually caused by an unintentional tiny gap between\n"
|
||||
" two solid brushes which doesn't leave enough room for the\n"
|
||||
" lightmap to fit (one world unit). Further instances of this\n"
|
||||
" warning during this compile will be supressed.\n",
|
||||
VecStr(point));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* =================
|
||||
* CalcPoints
|
||||
|
|
@ -348,66 +371,50 @@ CalcPoints(const dmodel_t *model, const texorg_t *texorg, lightsurf_t *surf)
|
|||
{
|
||||
int i;
|
||||
int s, t;
|
||||
int w, h, step;
|
||||
int width, height, step;
|
||||
vec_t starts, startt, us, ut;
|
||||
vec_t *point;
|
||||
vec_t mids, midt;
|
||||
vec3_t facemid, move;
|
||||
vec3_t midpoint, move;
|
||||
|
||||
/* fill in surforg */
|
||||
/* the points are biased towards the center of the surface */
|
||||
/* to help avoid edge cases just inside walls */
|
||||
/*
|
||||
* Fill in the surface points. The points are biased towards the center of
|
||||
* the surface to help avoid edge cases just inside walls
|
||||
*/
|
||||
TexCoordToWorld(surf->exactmid[0], surf->exactmid[1], texorg, midpoint);
|
||||
|
||||
point = surf->points[0];
|
||||
mids = surf->exactmid[0];
|
||||
midt = surf->exactmid[1];
|
||||
|
||||
TexCoordToWorld(mids, midt, texorg, facemid);
|
||||
|
||||
h = (surf->texsize[1] + 1) * oversample;
|
||||
w = (surf->texsize[0] + 1) * oversample;
|
||||
width = (surf->texsize[0] + 1) * oversample;
|
||||
height = (surf->texsize[1] + 1) * oversample;
|
||||
starts = (surf->texmins[0] - 0.5 + (0.5 / oversample)) * 16;
|
||||
startt = (surf->texmins[1] - 0.5 + (0.5 / oversample)) * 16;
|
||||
step = 16 / oversample;
|
||||
|
||||
surf->numpoints = w * h;
|
||||
for (t = 0; t < h; t++) {
|
||||
for (s = 0; s < w; s++, point += 3) {
|
||||
point = surf->points[0];
|
||||
surf->numpoints = width * height;
|
||||
for (t = 0; t < height; t++) {
|
||||
for (s = 0; s < width; s++, point += 3) {
|
||||
us = starts + s * step;
|
||||
ut = startt + t * step;
|
||||
|
||||
/* if a line can be traced from surf to facemid, point is good */
|
||||
TexCoordToWorld(us, ut, texorg, point);
|
||||
for (i = 0; i < 6; i++) {
|
||||
TexCoordToWorld(us, ut, texorg, point);
|
||||
const int flags = TRACE_HIT_SOLID;
|
||||
tracepoint_t hit;
|
||||
int result;
|
||||
vec_t dist;
|
||||
|
||||
if (TestLineModel(model, facemid, point))
|
||||
break; /* got it */
|
||||
if (i & 1) { // i is odd
|
||||
if (us > mids) {
|
||||
us -= 8;
|
||||
if (us < mids)
|
||||
us = mids;
|
||||
} else {
|
||||
us += 8;
|
||||
if (us > mids)
|
||||
us = mids;
|
||||
}
|
||||
} else {
|
||||
if (ut > midt) {
|
||||
ut -= 8;
|
||||
if (ut < midt)
|
||||
ut = midt;
|
||||
} else {
|
||||
ut += 8;
|
||||
if (ut > midt)
|
||||
ut = midt;
|
||||
}
|
||||
result = TraceLine(model, flags, midpoint, point, &hit);
|
||||
if (result == TRACE_HIT_NONE)
|
||||
break;
|
||||
if (result != TRACE_HIT_SOLID) {
|
||||
WarnBadMidpoint(midpoint);
|
||||
break;
|
||||
}
|
||||
|
||||
/* move surf 8 pixels towards the center */
|
||||
VectorSubtract(facemid, point, move);
|
||||
VectorNormalize(move);
|
||||
VectorMA(point, 8, move, point);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -502,12 +509,13 @@ SingleLightFace(const entity_t *entity, const lightsample_t *light,
|
|||
{
|
||||
const modelinfo_t *modelinfo = lightsurf->modelinfo;
|
||||
const plane_t *plane = &lightsurf->plane;
|
||||
const dmodel_t *shadowself;
|
||||
const vec_t *surfpoint;
|
||||
vec_t dist;
|
||||
vec_t angle, spotscale;
|
||||
vec_t add;
|
||||
qboolean newmap, hit;
|
||||
int i, mapnum;
|
||||
const vec_t *surfpoint;
|
||||
lightsample_t *sample;
|
||||
lightmap_t newlightmap;
|
||||
|
||||
|
|
@ -544,6 +552,7 @@ SingleLightFace(const entity_t *entity, const lightsample_t *light,
|
|||
* Check it for real
|
||||
*/
|
||||
hit = false;
|
||||
shadowself = modelinfo->shadowself ? modelinfo->model : NULL;
|
||||
surfpoint = lightsurf->points[0];
|
||||
for (i = 0; i < lightsurf->numpoints; i++, sample++, surfpoint += 3) {
|
||||
vec3_t ray;
|
||||
|
|
@ -571,12 +580,8 @@ SingleLightFace(const entity_t *entity, const lightsample_t *light,
|
|||
}
|
||||
}
|
||||
|
||||
/* Test for line of sight */
|
||||
if (!TestLine(entity->origin, surfpoint))
|
||||
if (!TestLight(entity->origin, surfpoint, shadowself))
|
||||
continue;
|
||||
if (modelinfo->shadowself)
|
||||
if (!TestLineModel(modelinfo->model, entity->origin, surfpoint))
|
||||
continue;
|
||||
|
||||
angle = (1.0 - scalecos) + scalecos * angle;
|
||||
add = GetLightValue(light, entity, dist) * angle * spotscale;
|
||||
|
|
@ -614,6 +619,7 @@ SkyLightFace(const lightsample_t *light, const lightsurf_t *lightsurf,
|
|||
{
|
||||
const modelinfo_t *modelinfo = lightsurf->modelinfo;
|
||||
const plane_t *plane = &lightsurf->plane;
|
||||
const dmodel_t *shadowself;
|
||||
const vec_t *surfpoint;
|
||||
int i, mapnum;
|
||||
vec3_t incoming;
|
||||
|
|
@ -642,15 +648,12 @@ SkyLightFace(const lightsample_t *light, const lightsurf_t *lightsurf,
|
|||
angle = (1.0 - scalecos) + scalecos * angle;
|
||||
|
||||
/* Check each point... */
|
||||
shadowself = modelinfo->shadowself ? modelinfo->model : NULL;
|
||||
sample = lightmaps[mapnum].samples;
|
||||
surfpoint = lightsurf->points[0];
|
||||
for (i = 0; i < lightsurf->numpoints; i++, sample++, surfpoint += 3) {
|
||||
vec3_t skypoint;
|
||||
if (!TestSky(surfpoint, sunvec, skypoint))
|
||||
if (!TestSky(surfpoint, sunvec, shadowself))
|
||||
continue;
|
||||
if (modelinfo->shadowself)
|
||||
if (!TestLineModel(modelinfo->model, surfpoint, skypoint))
|
||||
continue;
|
||||
sample->light += angle * light->light;
|
||||
if (colored)
|
||||
VectorMA(sample->color, angle * light->light / 255.0f, light->color,
|
||||
|
|
@ -668,10 +671,11 @@ FixMinlight(const lightsample_t *minlight, const lightsurf_t *lightsurf,
|
|||
lightmap_t *lightmaps)
|
||||
{
|
||||
const modelinfo_t *modelinfo = lightsurf->modelinfo;
|
||||
int mapnum, i, j, k;
|
||||
lightsample_t *sample;
|
||||
const dmodel_t *shadowself;
|
||||
const entity_t *entity;
|
||||
const vec_t *surfpoint;
|
||||
int mapnum, i, j, k;
|
||||
lightsample_t *sample;
|
||||
|
||||
/* Find a style 0 lightmap */
|
||||
for (mapnum = 0; mapnum < MAXLIGHTMAPS; mapnum++) {
|
||||
|
|
@ -699,6 +703,7 @@ FixMinlight(const lightsample_t *minlight, const lightsurf_t *lightsurf,
|
|||
}
|
||||
|
||||
/* Cast rays for local minlight entities */
|
||||
shadowself = modelinfo->shadowself ? modelinfo->model : NULL;
|
||||
for (i = 0, entity = entities; i < num_entities; i++, entity++) {
|
||||
if (entity->formula != LF_LOCALMIN)
|
||||
continue;
|
||||
|
|
@ -708,14 +713,9 @@ FixMinlight(const lightsample_t *minlight, const lightsurf_t *lightsurf,
|
|||
for (j = 0; j < lightsurf->numpoints; j++, sample++, surfpoint += 3) {
|
||||
qboolean trace = false;
|
||||
if (sample->light < entity->light.light) {
|
||||
trace = TestLine(entity->origin, surfpoint);
|
||||
trace = TestLight(entity->origin, surfpoint, shadowself);
|
||||
if (!trace)
|
||||
continue;
|
||||
if (modelinfo->shadowself) {
|
||||
trace = TestLineModel(modelinfo->model, entity->origin, surfpoint);
|
||||
if (!trace)
|
||||
continue;
|
||||
}
|
||||
sample->light = entity->light.light;
|
||||
}
|
||||
if (!colored)
|
||||
|
|
@ -723,15 +723,9 @@ FixMinlight(const lightsample_t *minlight, const lightsurf_t *lightsurf,
|
|||
for (k = 0; k < 3; k++) {
|
||||
if (sample->color[k] < entity->light.color[k]) {
|
||||
if (!trace) {
|
||||
trace = TestLine(entity->origin, surfpoint);
|
||||
trace = TestLight(entity->origin, surfpoint, shadowself);
|
||||
if (!trace)
|
||||
break;
|
||||
if (modelinfo->shadowself) {
|
||||
trace = TestLineModel(modelinfo->model,
|
||||
entity->origin, surfpoint);
|
||||
if (!trace)
|
||||
break;
|
||||
}
|
||||
}
|
||||
sample->color[k] = entity->light.color[k];
|
||||
}
|
||||
|
|
|
|||
202
light/trace.c
202
light/trace.c
|
|
@ -82,9 +82,10 @@ MakeTnodes(void)
|
|||
*/
|
||||
|
||||
typedef struct {
|
||||
vec3_t backpt;
|
||||
int side;
|
||||
vec3_t back;
|
||||
vec3_t front;
|
||||
int node;
|
||||
int side;
|
||||
} tracestack_t;
|
||||
|
||||
/*
|
||||
|
|
@ -93,52 +94,81 @@ typedef struct {
|
|||
* ==============
|
||||
*/
|
||||
#define MAX_TSTACK 128
|
||||
static qboolean
|
||||
TestLineOrSky(const dmodel_t *model, const vec3_t start, const vec3_t stop,
|
||||
qboolean skytest, vec3_t skypoint)
|
||||
int
|
||||
TraceLine(const dmodel_t *model, const int traceflags,
|
||||
const vec3_t start, const vec3_t stop, tracepoint_t *hitpoint)
|
||||
{
|
||||
int node, side;
|
||||
int node, side, tracehit;
|
||||
vec3_t front, back;
|
||||
vec_t frontdist, backdist;
|
||||
tracestack_t tracestack[MAX_TSTACK];
|
||||
tracestack_t *tstack;
|
||||
tracestack_t *tstack, *crossnode;
|
||||
tnode_t *tnode;
|
||||
const tracestack_t *const tstack_max = tracestack + MAX_TSTACK;
|
||||
|
||||
if (traceflags <= 0)
|
||||
Error("Internal error: %s - bad traceflags (%d)",
|
||||
__func__, traceflags);
|
||||
|
||||
VectorCopy(start, front);
|
||||
VectorCopy(stop, back);
|
||||
|
||||
tstack = tracestack;
|
||||
node = model->headnode[0];
|
||||
crossnode = NULL;
|
||||
tracehit = TRACE_HIT_NONE;
|
||||
|
||||
while (1) {
|
||||
while (node < 0 && node != CONTENTS_SOLID) {
|
||||
if (skytest && node == CONTENTS_SKY)
|
||||
while (node < 0) {
|
||||
switch (node) {
|
||||
case CONTENTS_SOLID:
|
||||
if (traceflags & TRACE_HIT_SOLID)
|
||||
tracehit = TRACE_HIT_SOLID;
|
||||
break;
|
||||
case CONTENTS_WATER:
|
||||
if (traceflags & TRACE_HIT_WATER)
|
||||
tracehit = TRACE_HIT_WATER;
|
||||
break;
|
||||
case CONTENTS_SLIME:
|
||||
if (traceflags & TRACE_HIT_SLIME)
|
||||
tracehit = TRACE_HIT_SLIME;
|
||||
break;
|
||||
case CONTENTS_LAVA:
|
||||
if (traceflags & TRACE_HIT_LAVA)
|
||||
tracehit = TRACE_HIT_LAVA;
|
||||
break;
|
||||
case CONTENTS_SKY:
|
||||
if (traceflags & TRACE_HIT_SKY)
|
||||
tracehit = TRACE_HIT_SKY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (tracehit != TRACE_HIT_NONE) {
|
||||
/* If we haven't crossed, start was inside flagged contents */
|
||||
if (!crossnode)
|
||||
return -tracehit;
|
||||
if (hitpoint) {
|
||||
const int planenum = dnodes[crossnode->node].planenum;
|
||||
hitpoint->dplane = dplanes + planenum;
|
||||
hitpoint->side = crossnode->side;
|
||||
VectorCopy(crossnode->back, hitpoint->point);
|
||||
}
|
||||
return tracehit;
|
||||
}
|
||||
|
||||
/* If the stack is empty, not obstructions were hit */
|
||||
/* If the stack is empty, no obstructions were hit */
|
||||
if (tstack == tracestack)
|
||||
return !skytest;
|
||||
return TRACE_HIT_NONE;
|
||||
|
||||
/*
|
||||
* pop the stack, set the hit point for this plane and
|
||||
* go down the back side
|
||||
*/
|
||||
tstack--;
|
||||
VectorCopy(back, front);
|
||||
VectorCopy(tstack->backpt, back);
|
||||
/* Pop the stack and go down the back side */
|
||||
crossnode = --tstack;
|
||||
VectorCopy(tstack->front, front);
|
||||
VectorCopy(tstack->back, back);
|
||||
node = tnodes[tstack->node].children[!tstack->side];
|
||||
}
|
||||
|
||||
if (node == CONTENTS_SOLID)
|
||||
return false;
|
||||
if (node == CONTENTS_SKY && skytest) {
|
||||
VectorCopy(front, skypoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
tnode = &tnodes[node];
|
||||
|
||||
switch (tnode->type) {
|
||||
case PLANE_X:
|
||||
frontdist = front[0] - tnode->dist;
|
||||
|
|
@ -158,74 +188,116 @@ TestLineOrSky(const dmodel_t *model, const vec3_t start, const vec3_t stop,
|
|||
break;
|
||||
}
|
||||
|
||||
if (frontdist > -ON_EPSILON && backdist > -ON_EPSILON) {
|
||||
if (frontdist > ON_EPSILON && backdist > ON_EPSILON) {
|
||||
node = tnode->children[0];
|
||||
continue;
|
||||
}
|
||||
if (frontdist < ON_EPSILON && backdist < ON_EPSILON) {
|
||||
if (frontdist < -ON_EPSILON && backdist < -ON_EPSILON) {
|
||||
node = tnode->children[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tstack == tstack_max)
|
||||
Error("%s: tstack overflow\n", __func__);
|
||||
if (frontdist >= -ON_EPSILON && frontdist <= ON_EPSILON) {
|
||||
if (backdist >= -ON_EPSILON && backdist <= ON_EPSILON) {
|
||||
/* Front and back on-node, go down both sides */
|
||||
if (tstack == tstack_max)
|
||||
Error("%s: tstack overflow\n", __func__);
|
||||
tstack->node = node;
|
||||
tstack->side = 0;
|
||||
VectorCopy(front, tstack->front);
|
||||
VectorCopy(back, tstack->back);
|
||||
crossnode = tstack++;
|
||||
node = tnode->children[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
side = frontdist < 0.0f ? 1 : 0;
|
||||
/* If only front is on-node, go down the side containing back */
|
||||
side = back < 0;
|
||||
node = tnode->children[side];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (backdist >= -ON_EPSILON && backdist <= ON_EPSILON) {
|
||||
/* If only back is on-node, record a cross point but continue */
|
||||
if (tstack == tstack_max)
|
||||
Error("%s: tstack overflow\n", __func__);
|
||||
side = frontdist < 0;
|
||||
tstack->node = node;
|
||||
tstack->side = side;
|
||||
VectorCopy(front, tstack->front);
|
||||
VectorCopy(back, tstack->back);
|
||||
crossnode = tstack;
|
||||
node = tnode->children[side];
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here, we have a clean split with front and back on
|
||||
* opposite sides. The new back is the intersection point with the
|
||||
* node plane. Push the other segment onto the stack and continue.
|
||||
*/
|
||||
side = frontdist < 0;
|
||||
tstack->node = node;
|
||||
tstack->side = side;
|
||||
VectorCopy(back, tstack->backpt);
|
||||
tstack++;
|
||||
|
||||
/* The new back is the intersection point with the node plane */
|
||||
VectorCopy(back, tstack->back);
|
||||
VectorSubtract(back, front, back);
|
||||
VectorMA(front, frontdist / (frontdist - backdist), back, back);
|
||||
|
||||
VectorCopy(back, tstack->front);
|
||||
crossnode = tstack++;
|
||||
node = tnode->children[side];
|
||||
}
|
||||
}
|
||||
|
||||
qboolean
|
||||
TestLine(const vec3_t start, const vec3_t stop)
|
||||
TestLight(const vec3_t start, const vec3_t stop, const dmodel_t *self)
|
||||
{
|
||||
const dmodel_t *const *model;
|
||||
const int traceflags = TRACE_HIT_SOLID;
|
||||
int result = TRACE_HIT_NONE;
|
||||
|
||||
for (model = tracelist; *model; model++)
|
||||
if (!TestLineModel(*model, start, stop))
|
||||
/* Check against the list of global shadow casters */
|
||||
for (model = tracelist; *model; model++) {
|
||||
result = TraceLine(*model, traceflags, start, stop, NULL);
|
||||
if (result != TRACE_HIT_NONE)
|
||||
break;
|
||||
}
|
||||
|
||||
return !*model;
|
||||
/* If not yet obscured, check against the self-shadow model */
|
||||
if (result == TRACE_HIT_NONE && self)
|
||||
result = TraceLine(self, traceflags, start, stop, NULL);
|
||||
|
||||
return (result == TRACE_HIT_NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper functions for testing LOS between two points (TestLine)
|
||||
* and testing LOS to a sky brush along a direction vector (TestSky)
|
||||
*/
|
||||
qboolean
|
||||
TestLineModel(const dmodel_t *model, const vec3_t start, const vec3_t stop)
|
||||
{
|
||||
return TestLineOrSky(model, start, stop, false, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* =======
|
||||
* TestSky
|
||||
* =======
|
||||
* Returns true if the ray cast from point 'start' in the
|
||||
* direction of vector 'dirn' hits a CONTENTS_SKY node before
|
||||
* a CONTENTS_SOLID node.
|
||||
*/
|
||||
qboolean
|
||||
TestSky(const vec3_t start, const vec3_t dirn, vec3_t skypoint)
|
||||
TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self)
|
||||
{
|
||||
const dmodel_t *const *model;
|
||||
int traceflags = TRACE_HIT_SKY | TRACE_HIT_SOLID;
|
||||
int result = TRACE_HIT_NONE;
|
||||
vec3_t stop;
|
||||
tracepoint_t hit;
|
||||
|
||||
VectorAdd(dirn, start, skypoint);
|
||||
if (!TestLineOrSky(tracelist[0], start, skypoint, true, skypoint))
|
||||
/* Trace towards the sunlight for a sky brush */
|
||||
VectorAdd(dirn, start, stop);
|
||||
result = TraceLine(tracelist[0], traceflags, start, stop, &hit);
|
||||
if (result != TRACE_HIT_SKY)
|
||||
return false;
|
||||
|
||||
for (model = tracelist + 1; *model; model++)
|
||||
if (!TestLineModel(*model, start, skypoint))
|
||||
break;
|
||||
/* If good, check it isn't shadowed by another model */
|
||||
traceflags = TRACE_HIT_SOLID;
|
||||
for (model = tracelist + 1; *model; model++) {
|
||||
result = TraceLine(*model, traceflags, start, hit.point, NULL);
|
||||
if (result != TRACE_HIT_NONE)
|
||||
return false;
|
||||
}
|
||||
|
||||
return !*model;
|
||||
/* Check for self-shadowing */
|
||||
if (self) {
|
||||
result = TraceLine(self, traceflags, start, hit.point, NULL);
|
||||
if (result != TRACE_HIT_NONE)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue