mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 15:31:39 +00:00
Replaced SV_RecursiveHullCheck with a more numerically stable and faster alternative.
This commit is contained in:
parent
8d84bf8d2f
commit
706dc546a3
1 changed files with 130 additions and 89 deletions
219
Quake/world.c
219
Quake/world.c
|
@ -582,50 +582,72 @@ LINE TESTING IN HULLS
|
||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
rht_solid,
|
||||||
|
rht_empty,
|
||||||
|
rht_impact
|
||||||
|
};
|
||||||
|
struct rhtctx_s
|
||||||
|
{
|
||||||
|
vec3_t start, end;
|
||||||
|
mclipnode_t *clipnodes;
|
||||||
|
mplane_t *planes;
|
||||||
|
};
|
||||||
|
#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
|
||||||
|
#define FloatInterpolate(a, bness, b, c) ((c) = (a) + (b - a)*bness)
|
||||||
|
#define VectorInterpolate(a, bness, b, c) FloatInterpolate((a)[0], bness, (b)[0], (c)[0]),FloatInterpolate((a)[1], bness, (b)[1], (c)[1]),FloatInterpolate((a)[2], bness, (b)[2], (c)[2])
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
SV_RecursiveHullCheck
|
Q1BSP_RecursiveHullTrace
|
||||||
|
|
||||||
Spike -- note that the pointcontents in this function are completely redundant.
|
This does the core traceline/tracebox logic.
|
||||||
This function should instead return the state of the contents of the mid position.
|
This version is from FTE and attempts to be more numerically stable than vanilla.
|
||||||
This would avoid all redundant recursion.
|
This is achieved by recursing at the actual decision points instead of vanilla's habit of vanilla's habit of using points that are outside of the child's volume.
|
||||||
|
It also uses itself to test solidity on the other side of the node, which ensures consistent precision.
|
||||||
|
The actual collision point is (still) biased by an epsilon, so the end point shouldn't be inside walls either way.
|
||||||
|
FTE's version 'should' be more compatible with vanilla than DP's (which doesn't take care with allsolid).
|
||||||
|
ezQuake also has a version of this logic, but I trust mine more.
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
static int Q1BSP_RecursiveHullTrace (struct rhtctx_s *ctx, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
||||||
{
|
{
|
||||||
mclipnode_t *node; //johnfitz -- was dclipnode_t
|
mclipnode_t *node;
|
||||||
mplane_t *plane;
|
mplane_t *plane;
|
||||||
float t1, t2;
|
float t1, t2;
|
||||||
float frac;
|
|
||||||
int i;
|
|
||||||
vec3_t mid;
|
vec3_t mid;
|
||||||
int side;
|
int side;
|
||||||
float midf;
|
float midf;
|
||||||
|
int rht;
|
||||||
|
|
||||||
|
reenter:
|
||||||
|
|
||||||
// check for empty
|
|
||||||
if (num < 0)
|
if (num < 0)
|
||||||
{
|
{
|
||||||
if (num != CONTENTS_SOLID)
|
/*hit a leaf*/
|
||||||
|
if (num == CONTENTS_SOLID)
|
||||||
|
{
|
||||||
|
if (trace->allsolid)
|
||||||
|
trace->startsolid = true;
|
||||||
|
return rht_solid;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
trace->allsolid = false;
|
trace->allsolid = false;
|
||||||
if (num == CONTENTS_EMPTY)
|
if (num == CONTENTS_EMPTY)
|
||||||
trace->inopen = true;
|
trace->inopen = true;
|
||||||
else
|
else
|
||||||
trace->inwater = true;
|
trace->inwater = true;
|
||||||
|
return rht_empty;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
trace->startsolid = true;
|
|
||||||
return true; // empty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num < hull->firstclipnode || num > hull->lastclipnode)
|
/*its a node*/
|
||||||
Sys_Error ("SV_RecursiveHullCheck: bad node number");
|
|
||||||
|
|
||||||
//
|
/*get the node info*/
|
||||||
// find the point distances
|
node = ctx->clipnodes + num;
|
||||||
//
|
plane = ctx->planes + node->planenum;
|
||||||
node = hull->clipnodes + num;
|
|
||||||
plane = hull->planes + node->planenum;
|
|
||||||
|
|
||||||
if (plane->type < 3)
|
if (plane->type < 3)
|
||||||
{
|
{
|
||||||
|
@ -634,95 +656,114 @@ qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t1 = DoublePrecisionDotProduct (plane->normal, p1) - plane->dist;
|
t1 = DotProduct (plane->normal, p1) - plane->dist;
|
||||||
t2 = DoublePrecisionDotProduct (plane->normal, p2) - plane->dist;
|
t2 = DotProduct (plane->normal, p2) - plane->dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
/*if its completely on one side, resume on that side*/
|
||||||
if (t1 >= 0 && t2 >= 0)
|
if (t1 >= 0 && t2 >= 0)
|
||||||
return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
{
|
||||||
|
//return Q1BSP_RecursiveHullTrace (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
||||||
|
num = node->children[0];
|
||||||
|
goto reenter;
|
||||||
|
}
|
||||||
if (t1 < 0 && t2 < 0)
|
if (t1 < 0 && t2 < 0)
|
||||||
return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
|
|
||||||
#else
|
|
||||||
if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
|
|
||||||
return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
|
||||||
if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
|
|
||||||
return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// put the crosspoint DIST_EPSILON pixels on the near side
|
|
||||||
if (t1 < 0)
|
|
||||||
frac = (t1 + DIST_EPSILON)/(t1-t2);
|
|
||||||
else
|
|
||||||
frac = (t1 - DIST_EPSILON)/(t1-t2);
|
|
||||||
if (frac < 0)
|
|
||||||
frac = 0;
|
|
||||||
if (frac > 1)
|
|
||||||
frac = 1;
|
|
||||||
|
|
||||||
midf = p1f + (p2f - p1f)*frac;
|
|
||||||
for (i=0 ; i<3 ; i++)
|
|
||||||
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
|
|
||||||
|
|
||||||
side = (t1 < 0);
|
|
||||||
|
|
||||||
// move up to the node
|
|
||||||
if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#ifdef PARANOID
|
|
||||||
if (SV_HullPointContents (sv_hullmodel, mid, node->children[side])
|
|
||||||
== CONTENTS_SOLID)
|
|
||||||
{
|
{
|
||||||
Con_Printf ("mid PointInHullSolid\n");
|
//return Q1BSP_RecursiveHullTrace (hull, node->children[1], p1f, p2f, p1, p2, trace);
|
||||||
return false;
|
num = node->children[1];
|
||||||
|
goto reenter;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (SV_HullPointContents (hull, node->children[side^1], mid)
|
if (plane->type < 3)
|
||||||
!= CONTENTS_SOLID)
|
|
||||||
// go past the node
|
|
||||||
return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
|
|
||||||
|
|
||||||
if (trace->allsolid)
|
|
||||||
return false; // never got out of the solid area
|
|
||||||
|
|
||||||
//==================
|
|
||||||
// the other side of the node is solid, this is the impact point
|
|
||||||
//==================
|
|
||||||
if (!side)
|
|
||||||
{
|
{
|
||||||
VectorCopy (plane->normal, trace->plane.normal);
|
t1 = ctx->start[plane->type] - plane->dist;
|
||||||
trace->plane.dist = plane->dist;
|
t2 = ctx->end[plane->type] - plane->dist;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
|
t1 = DotProduct (plane->normal, ctx->start) - plane->dist;
|
||||||
|
t2 = DotProduct (plane->normal, ctx->end) - plane->dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
side = t1 < 0;
|
||||||
|
|
||||||
|
midf = t1 / (t1 - t2);
|
||||||
|
if (midf < p1f) midf = p1f;
|
||||||
|
if (midf > p2f) midf = p2f;
|
||||||
|
VectorInterpolate(ctx->start, midf, ctx->end, mid);
|
||||||
|
|
||||||
|
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side], p1f, midf, p1, mid, trace);
|
||||||
|
if (rht != rht_empty && !trace->allsolid)
|
||||||
|
return rht;
|
||||||
|
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side^1], midf, p2f, mid, p2, trace);
|
||||||
|
if (rht != rht_solid)
|
||||||
|
return rht;
|
||||||
|
|
||||||
|
if (side)
|
||||||
|
{
|
||||||
|
/*we impacted the back of the node, so flip the plane*/
|
||||||
trace->plane.dist = -plane->dist;
|
trace->plane.dist = -plane->dist;
|
||||||
|
VectorNegate(plane->normal, trace->plane.normal);
|
||||||
|
midf = (t1 + DIST_EPSILON) / (t1 - t2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*we impacted the front of the node*/
|
||||||
|
trace->plane.dist = plane->dist;
|
||||||
|
VectorCopy(plane->normal, trace->plane.normal);
|
||||||
|
midf = (t1 - DIST_EPSILON) / (t1 - t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (SV_HullPointContents (hull, hull->firstclipnode, mid)
|
t1 = DotProduct (trace->plane.normal, ctx->start) - trace->plane.dist;
|
||||||
== CONTENTS_SOLID)
|
t2 = DotProduct (trace->plane.normal, ctx->end) - trace->plane.dist;
|
||||||
{ // shouldn't really happen, but does occasionally
|
midf = (t1 - DIST_EPSILON) / (t1 - t2);
|
||||||
frac -= 0.1;
|
|
||||||
if (frac < 0)
|
|
||||||
{
|
|
||||||
trace->fraction = midf;
|
|
||||||
VectorCopy (mid, trace->endpos);
|
|
||||||
Con_DPrintf ("backup past 0\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
midf = p1f + (p2f - p1f)*frac;
|
|
||||||
for (i=0 ; i<3 ; i++)
|
|
||||||
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
midf = CLAMP(0, midf, 1);
|
||||||
trace->fraction = midf;
|
trace->fraction = midf;
|
||||||
VectorCopy (mid, trace->endpos);
|
VectorCopy (mid, trace->endpos);
|
||||||
|
VectorInterpolate(ctx->start, midf, ctx->end, trace->endpos);
|
||||||
|
|
||||||
return false;
|
return rht_impact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
SV_RecursiveHullCheck
|
||||||
|
|
||||||
|
Decides if its a simple point test, or does a slightly more expensive check.
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
||||||
|
{
|
||||||
|
if (p1[0]==p2[0] && p1[1]==p2[1] && p1[2]==p2[2])
|
||||||
|
{
|
||||||
|
/*points cannot cross planes, so do it faster*/
|
||||||
|
switch(SV_HullPointContents(hull, num, p1))
|
||||||
|
{
|
||||||
|
case CONTENTS_SOLID:
|
||||||
|
trace->startsolid = true;
|
||||||
|
break;
|
||||||
|
case CONTENTS_EMPTY:
|
||||||
|
trace->allsolid = false;
|
||||||
|
trace->inopen = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
trace->allsolid = false;
|
||||||
|
trace->inwater = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct rhtctx_s ctx;
|
||||||
|
VectorCopy(p1, ctx.start);
|
||||||
|
VectorCopy(p2, ctx.end);
|
||||||
|
ctx.clipnodes = hull->clipnodes;
|
||||||
|
ctx.planes = hull->planes;
|
||||||
|
return Q1BSP_RecursiveHullTrace(&ctx, num, p1f, p2f, p1, p2, trace) != rht_impact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
|
|
Loading…
Reference in a new issue