mirror of
https://github.com/nzp-team/glquake.git
synced 2025-02-07 16:31:25 +00:00
Implement FTEQW's faster SV_RecursiveHullCheck
This commit is contained in:
parent
6cc9131eb9
commit
fcc75883c2
6 changed files with 172 additions and 120 deletions
|
@ -52,7 +52,7 @@ void TraceLine (vec3_t start, vec3_t end, vec3_t impact)
|
|||
trace_t trace;
|
||||
|
||||
memset (&trace, 0, sizeof(trace));
|
||||
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
|
||||
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, start, end, &trace);
|
||||
|
||||
VectorCopy (trace.endpos, impact);
|
||||
}
|
||||
|
|
|
@ -285,7 +285,7 @@ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
|
|||
trace_t trace;
|
||||
|
||||
memset (&trace, 0, sizeof(trace));
|
||||
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace))
|
||||
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, start, end, &trace))
|
||||
{
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
|
|
|
@ -3144,7 +3144,7 @@ void QMB_LaserSight (void)
|
|||
|
||||
memset (&trace, 0, sizeof(trace_t));
|
||||
trace.fraction = 1;
|
||||
SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, dest, &trace);
|
||||
SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, start, dest, &trace);
|
||||
|
||||
start[2]+=cl.crouch;
|
||||
AddParticle (p_streaktrail, start, 1, 2, 0.02, color, trace.endpos);// draw the line
|
||||
|
@ -3207,7 +3207,7 @@ void QMB_LightningBeam (vec3_t start, vec3_t end)
|
|||
if (qmb_initialized && r_part_sparks.value)
|
||||
{
|
||||
memset (&trace, 0, sizeof(trace_t));
|
||||
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace))
|
||||
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, start, end, &trace))
|
||||
{
|
||||
if (trace.fraction < 1)
|
||||
{
|
||||
|
|
|
@ -62,6 +62,15 @@ void _VectorCopy (vec3_t in, vec3_t out);
|
|||
|
||||
void vectoangles (vec3_t vec, vec3_t ang);
|
||||
|
||||
#define VectorInterpolate(v1, _frac, v2, v) \
|
||||
do { \
|
||||
_mathlib_temp_float1 = _frac; \
|
||||
\
|
||||
(v)[0] = (v1)[0] + _mathlib_temp_float1 * ((v2)[0] - (v1)[0]);\
|
||||
(v)[1] = (v1)[1] + _mathlib_temp_float1 * ((v2)[1] - (v1)[1]);\
|
||||
(v)[2] = (v1)[2] + _mathlib_temp_float1 * ((v2)[2] - (v1)[2]);\
|
||||
} while(0)
|
||||
|
||||
int VectorCompare (vec3_t v1, vec3_t v2);
|
||||
vec_t Length (vec3_t v);
|
||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
|
||||
|
|
272
source/world.c
272
source/world.c
|
@ -586,30 +586,165 @@ LINE TESTING IN HULLS
|
|||
===============================================================================
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
rht_solid,
|
||||
rht_empty,
|
||||
rht_impact
|
||||
};
|
||||
struct rhtctx_s
|
||||
{
|
||||
unsigned int hitcontents;
|
||||
vec3_t start, end;
|
||||
dclipnode_t *clipnodes;
|
||||
mplane_t *planes;
|
||||
};
|
||||
|
||||
// 1/32 epsilon to keep floating point happy
|
||||
#define DIST_EPSILON (0.03125)
|
||||
|
||||
/*
|
||||
==================
|
||||
Q1BSP_RecursiveHullTrace
|
||||
This does the core traceline/tracebox logic.
|
||||
This version is from FTE and attempts to be more numerically stable than vanilla.
|
||||
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.
|
||||
==================
|
||||
*/
|
||||
static int Q1BSP_RecursiveHullTrace (struct rhtctx_s *ctx, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
||||
{
|
||||
dclipnode_t *node;
|
||||
mplane_t *plane;
|
||||
float t1, t2;
|
||||
vec3_t mid;
|
||||
int side;
|
||||
float midf;
|
||||
int rht;
|
||||
|
||||
reenter:
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
/*hit a leaf*/
|
||||
if (num == CONTENTS_SOLID)
|
||||
{
|
||||
if (trace->allsolid)
|
||||
trace->startsolid = true;
|
||||
return rht_solid;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace->allsolid = false;
|
||||
if (num == CONTENTS_EMPTY)
|
||||
trace->inopen = true;
|
||||
else if (num != CONTENTS_SOLID)
|
||||
trace->inwater = true;
|
||||
return rht_empty;
|
||||
}
|
||||
}
|
||||
|
||||
/*its a node*/
|
||||
|
||||
/*get the node info*/
|
||||
node = ctx->clipnodes + num;
|
||||
plane = ctx->planes + node->planenum;
|
||||
|
||||
if (plane->type < 3)
|
||||
{
|
||||
t1 = p1[plane->type] - plane->dist;
|
||||
t2 = p2[plane->type] - plane->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = DoublePrecisionDotProduct (plane->normal, p1) - plane->dist;
|
||||
t2 = DoublePrecisionDotProduct (plane->normal, p2) - plane->dist;
|
||||
}
|
||||
|
||||
/*if its completely on one side, resume on that side*/
|
||||
if (t1 >= 0 && t2 >= 0)
|
||||
{
|
||||
//return Q1BSP_RecursiveHullTrace (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
||||
num = node->children[0];
|
||||
goto reenter;
|
||||
}
|
||||
if (t1 < 0 && t2 < 0)
|
||||
{
|
||||
//return Q1BSP_RecursiveHullTrace (hull, node->children[1], p1f, p2f, p1, p2, trace);
|
||||
num = node->children[1];
|
||||
goto reenter;
|
||||
}
|
||||
|
||||
if (plane->type < 3)
|
||||
{
|
||||
t1 = ctx->start[plane->type] - plane->dist;
|
||||
t2 = ctx->end[plane->type] - plane->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
t1 = DoublePrecisionDotProduct (trace->plane.normal, ctx->start) - trace->plane.dist;
|
||||
t2 = DoublePrecisionDotProduct (trace->plane.normal, ctx->end) - trace->plane.dist;
|
||||
midf = (t1 - DIST_EPSILON) / (t1 - t2);
|
||||
|
||||
midf = CLAMP(0, midf, 1);
|
||||
trace->fraction = midf;
|
||||
VectorCopy (mid, trace->endpos);
|
||||
VectorInterpolate(ctx->start, midf, ctx->end, trace->endpos);
|
||||
|
||||
return rht_impact;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_RecursiveHullCheck
|
||||
|
||||
==================
|
||||
*/
|
||||
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
||||
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, trace_t *trace)
|
||||
{
|
||||
dclipnode_t *node;
|
||||
mplane_t *plane;
|
||||
float t1, t2;
|
||||
float frac;
|
||||
int i;
|
||||
vec3_t mid;
|
||||
int side;
|
||||
float midf;
|
||||
|
||||
// check for empty
|
||||
if (num < 0)
|
||||
if (p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2])
|
||||
{
|
||||
if (num != CONTENTS_SOLID)
|
||||
/*points cannot cross planes, so do it faster*/
|
||||
int c = SV_HullPointContents(hull, hull->firstclipnode, p1);
|
||||
//trace->contents = c;
|
||||
|
||||
if (c != CONTENTS_SOLID)
|
||||
{
|
||||
trace->allsolid = false;
|
||||
if (num == CONTENTS_EMPTY)
|
||||
|
@ -619,112 +754,17 @@ qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec
|
|||
}
|
||||
else
|
||||
trace->startsolid = true;
|
||||
return true; // empty
|
||||
}
|
||||
|
||||
if (num < hull->firstclipnode || num > hull->lastclipnode)
|
||||
Sys_Error ("SV_RecursiveHullCheck: bad node number");
|
||||
|
||||
//
|
||||
// find the point distances
|
||||
//
|
||||
node = hull->clipnodes + num;
|
||||
plane = hull->planes + node->planenum;
|
||||
|
||||
if (plane->type < 3)
|
||||
{
|
||||
t1 = p1[plane->type] - plane->dist;
|
||||
t2 = p2[plane->type] - plane->dist;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = DotProduct (plane->normal, p1) - plane->dist;
|
||||
t2 = DotProduct (plane->normal, p2) - plane->dist;
|
||||
struct rhtctx_s ctx;
|
||||
VectorCopy(p1, ctx.start);
|
||||
VectorCopy(p2, ctx.end);
|
||||
ctx.clipnodes = hull->clipnodes;
|
||||
ctx.planes = hull->planes;
|
||||
return Q1BSP_RecursiveHullTrace(&ctx, hull->firstclipnode, 0, 1, p1, p2, trace) != rht_impact;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (t1 >= 0 && t2 >= 0)
|
||||
return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
||||
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 false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SV_HullPointContents (hull, node->children[side^1], mid)
|
||||
!= 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);
|
||||
trace->plane.dist = plane->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
|
||||
trace->plane.dist = -plane->dist;
|
||||
}
|
||||
|
||||
while (SV_HullPointContents (hull, hull->firstclipnode, mid)
|
||||
== CONTENTS_SOLID)
|
||||
{ // shouldn't really happen, but does occasionally
|
||||
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]);
|
||||
}
|
||||
|
||||
trace->fraction = midf;
|
||||
VectorCopy (mid, trace->endpos);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -779,7 +819,7 @@ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t max
|
|||
#endif
|
||||
|
||||
// trace a line through the apropriate clipping hull
|
||||
SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
|
||||
SV_RecursiveHullCheck (hull, hull->firstclipnode, start_l, end_l, &trace);
|
||||
|
||||
#ifdef QUAKE2
|
||||
// rotate endpos back to world frame of reference
|
||||
|
|
|
@ -64,6 +64,9 @@ int SV_TruePointContents (vec3_t p);
|
|||
|
||||
edict_t *SV_TestEntityPosition (edict_t *ent);
|
||||
|
||||
|
||||
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, trace_t *trace);
|
||||
|
||||
trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict);
|
||||
// mins and maxs are reletive
|
||||
|
||||
|
|
Loading…
Reference in a new issue