box tracing (instead of point). Currently disabled because it doesn't work right just yet. However, when it is working, it will let us do things like crouching, crawling, arbitrary sized objects (including players), etc.

This commit is contained in:
Bill Currie 2006-12-24 03:13:29 +00:00 committed by Jeff Teunissen
parent b3a2759e5b
commit 45d467d748
8 changed files with 224 additions and 127 deletions

View file

@ -403,6 +403,7 @@ typedef struct model_s
msurface_t **marksurfaces;
hull_t hulls[MAX_MAP_HULLS];
hull_t *hull_list[MAX_MAP_HULLS];
int numtextures;
texture_t **textures;

View file

@ -39,12 +39,13 @@ typedef struct
float dist;
} plane_t;
typedef struct trace_s
{
typedef struct trace_s {
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
qboolean inopen, inwater;
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t extents; // 1/2 size of traced box
qboolean isbox; // box or point
vec3_t endpos; // final position
plane_t plane; // surface normal at impact
struct edict_s *ent; // entity the surface is on
@ -113,10 +114,7 @@ struct edict_s *SV_TestPlayerPosition (struct edict_s *ent,
int SV_HullPointContents (hull_t *hull, int num, const vec3_t p);
hull_t *SV_HullForEntity (struct edict_s *ent, const vec3_t mins,
const vec3_t maxs, vec3_t offset);
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f,
const vec3_t p1, const vec3_t p2,
trace_t *trace);
const vec3_t maxs, vec3_t extents, vec3_t offset);
qboolean MOD_TraceLine (hull_t *hull, int num,
const vec3_t start, const vec3_t end, trace_t *trace);

View file

@ -651,6 +651,7 @@ Mod_LoadClipnodes (lump_t *l)
loadmodel->numclipnodes = count;
hull = &loadmodel->hulls[1];
loadmodel->hull_list[1] = hull;
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count - 1;
@ -663,6 +664,7 @@ Mod_LoadClipnodes (lump_t *l)
hull->clip_maxs[2] = 32;
hull = &loadmodel->hulls[2];
loadmodel->hull_list[2] = hull;
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count - 1;
@ -691,7 +693,7 @@ Mod_LoadClipnodes (lump_t *l)
/*
Mod_MakeHull0
Deplicate the drawing hull structure as a clipping hull
Replicate the drawing hull structure as a clipping hull
*/
static void
Mod_MakeHull0 (void)
@ -702,6 +704,7 @@ Mod_MakeHull0 (void)
mnode_t *in, *child;
hull = &loadmodel->hulls[0];
loadmodel->hull_list[0] = hull;
in = loadmodel->nodes;
count = loadmodel->numnodes;
@ -867,9 +870,11 @@ Mod_LoadBrushModel (model_t *mod, void *buffer)
bm = &mod->submodels[i];
mod->hulls[0].firstclipnode = bm->headnode[0];
mod->hull_list[0] = &mod->hulls[0];
for (j = 1; j < MAX_MAP_HULLS; j++) {
mod->hulls[j].firstclipnode = bm->headnode[j];
mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
mod->hull_list[j] = &mod->hulls[j];
}
mod->firstmodelsurface = bm->firstface;

View file

@ -1214,7 +1214,7 @@ PF_hullpointcontents (progs_t *pr)
hull_t *hull;
vec3_t offset;
hull = SV_HullForEntity (edict, mins, maxs, offset);
hull = SV_HullForEntity (edict, mins, maxs, 0, offset);
VectorSubtract (point, offset, offset);
R_INT (pr) = SV_HullPointContents (hull, 0, offset);
}

View file

@ -141,29 +141,17 @@ SV_HullForBox (const vec3_t mins, const vec3_t maxs)
*/
hull_t *
SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs,
vec3_t offset)
vec3_t extents, vec3_t offset)
{
int hull_index = 0;
hull_t *hull = 0;
hull_t *hull = 0, **hull_list = 0;
model_t *model;
vec3_t hullmins, hullmaxs, size;
if ((sv_fields.rotated_bbox != -1
&& SVinteger (ent, rotated_bbox))
|| SVfloat (ent, solid) == SOLID_BSP) {
VectorSubtract (maxs, mins, size);
if (size[0] < 3)
hull_index = 0;
else if (size[0] <= 32)
hull_index = 1;
else
hull_index = 2;
}
// decide which clipping hull to use, based on the size
if (sv_fields.rotated_bbox != -1
&& SVinteger (ent, rotated_bbox)) {
int h = SVinteger (ent, rotated_bbox) - 1;
hull = pf_hull_list[h]->hulls[hull_index];
hull_list = pf_hull_list[h]->hulls;
} if (SVfloat (ent, solid) == SOLID_BSP) {
// explicit hulls in the BSP model
if (SVfloat (ent, movetype) != MOVETYPE_PUSH)
@ -174,20 +162,50 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs,
if (!model || model->type != mod_brush)
Sys_Error ("SOLID_BSP with a non bsp model");
hull = &model->hulls[hull_index];
hull_list = model->hull_list;
}
if (hull_list) {
// decide which clipping hull to use, based on the size
VectorSubtract (maxs, mins, size);
if (extents) {
VectorScale (size, 0.5, extents);
} else {
if (size[0] < 3)
hull_index = 0;
else if (size[0] <= 32)
hull_index = 1;
else
hull_index = 2;
}
hull = hull_list[hull_index];
}
if (hull) {
// calculate an offset value to center the origin
if (extents) {
VectorAdd (extents, mins, offset);
VectorSubtract (SVvector (ent, origin), offset, offset);
} else {
VectorSubtract (hull->clip_mins, mins, offset);
VectorAdd (offset, SVvector (ent, origin), offset);
} else { // create a temp hull from bounding box sizes
}
} else {
// create a temp hull from bounding box sizes
if (extents) {
VectorCopy (SVvector (ent, mins), hullmins);
VectorCopy (SVvector (ent, maxs), hullmaxs);
//FIXME broken for map models (ie, origin always 0, 0, 0)
VectorAdd (extents, mins, offset);
VectorSubtract (SVvector (ent, origin), offset, offset);
} else {
VectorSubtract (SVvector (ent, mins), maxs, hullmins);
VectorSubtract (SVvector (ent, maxs), mins, hullmaxs);
hull = SV_HullForBox (hullmins, hullmaxs);
VectorCopy (SVvector (ent, origin), offset);
}
hull = SV_HullForBox (hullmins, hullmaxs);
}
return hull;
}
@ -487,101 +505,175 @@ SV_TestEntityPosition (edict_t *ent)
// 1/32 epsilon to keep floating point happy
#define DIST_EPSILON (0.03125)
qboolean
SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f,
const vec3_t p1, const vec3_t p2, trace_t *trace)
{
float frac, midf, t1, t2;
int side, i;
dclipnode_t *node;
typedef struct {
vec3_t backpt;
int side;
int num;
mplane_t *plane;
vec3_t mid;
} tracestack_t;
// check for empty
if (num < 0) {
if (num != CONTENTS_SOLID) {
trace->allsolid = false;
static inline void
calc_impact (trace_t *trace, const vec3_t start, const vec3_t end,
const mplane_t *plane)
{
vec_t t1, t2, frac, offset;
vec3_t dist;
t1 = PlaneDiff (start, plane);
t2 = PlaneDiff (end, plane);
offset = 0;
if (trace->isbox) {
if (plane->type < 3)
offset = trace->extents[plane->type];
else
offset = (fabs (trace->extents[0] * plane->normal[0])
+ fabs (trace->extents[1] * plane->normal[1])
+ fabs (trace->extents[2] * plane->normal[2]));
}
if (t1 < 0) {
frac = (t1 + DIST_EPSILON) / (t1 - t2);
// invert plane parameters;
VectorNegate (plane->normal, trace->plane.normal);
trace->plane.dist = -plane->dist;
} else {
frac = (t1 - DIST_EPSILON) / (t1 - t2);
VectorCopy (plane->normal, trace->plane.normal);
trace->plane.dist = plane->dist;
}
frac = bound (0, frac, 1);
trace->fraction = frac;
VectorSubtract (end, start, dist);
VectorMultAdd (start, frac, dist, trace->endpos);
}
static qboolean
SV_RecursiveHullCheck (hull_t *hull, int num,
const vec3_t start, const vec3_t end, trace_t *trace)
{
vec_t front, back, offset, frac, idist;
vec3_t frontpt, backpt, dist;
int side, empty, solid;
tracestack_t *tstack;
tracestack_t tracestack[256];
dclipnode_t *node;
mplane_t *plane, *split_plane;
VectorCopy (start, frontpt);
VectorCopy (end, backpt);
tstack = tracestack;
empty = 0;
solid = 0;
split_plane = 0;
while (1) {
while (num < 0) {
if (!solid && num != CONTENTS_SOLID) {
empty = 1;
if (num == CONTENTS_EMPTY)
trace->inopen = true;
else
trace->inwater = true;
} else
trace->startsolid = true;
return true; // empty
} else if (!empty && num == CONTENTS_SOLID) {
solid = 1;
} else if (empty || solid) {
// DONE!
// trace->allsolid = solid & (num == CONTENTS_SOLID);
trace->allsolid = false;
trace->startsolid = solid;
calc_impact (trace, start, end, split_plane);
return false;
}
// pop up the sta ck for a back side
if (tstack-- == tracestack) {
trace->allsolid = solid & (num == CONTENTS_SOLID);
trace->startsolid = solid;
return true;
}
// set the hit point for this plane
VectorCopy (backpt, frontpt);
// go doun the back side
VectorCopy (tstack->backpt, backpt);
side = tstack->side;
split_plane = tstack->plane;
num = hull->clipnodes[tstack->num].children[side ^ 1];
}
// 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;
} else {
t1 = DotProduct (plane->normal, p1) - plane->dist;
t2 = DotProduct (plane->normal, p2) - plane->dist;
}
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);
side = (t1 < 0);
frac = t1 / (t1 - t2);
// frac = bound (0, frac, 1); // is this needed?
midf = p1f + (p2f - p1f) * frac;
for (i = 0; i < 3; i++)
mid[i] = p1[i] + frac * (p2[i] - p1[i]);
// move up to the node
if (!SV_RecursiveHullCheck (hull, node->children[side],
p1f, midf, p1, mid, trace))
return false;
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 {
// invert plane paramterers
trace->plane.normal[0] = -plane->normal[0];
trace->plane.normal[1] = -plane->normal[1];
trace->plane.normal[2] = -plane->normal[2];
trace->plane.dist = -plane->dist;
}
// put the crosspoint DIST_EPSILON pixels on the near side to guarantee
// mid is on the correct side of the plane
if (side)
frac = (t1 + DIST_EPSILON) / (t1 - t2);
offset = 0;
front = PlaneDiff (frontpt, plane);
back = PlaneDiff (backpt, plane);
if (trace->isbox) {
if (plane->type < 3)
offset = trace->extents[plane->type];
else
frac = (t1 - DIST_EPSILON) / (t1 - t2);
offset = (fabs (trace->extents[0] * plane->normal[0])
+ fabs (trace->extents[1] * plane->normal[1])
+ fabs (trace->extents[2] * plane->normal[2]));
}
// when offset is 0, the following is equivalent to:
// if (front >= 0 && back >= 0) ...
// if (front < 0 && back < 0) ...
// due to the order of operations
// however, when (front == offset && back == offset) or
// (front == -offset && back == -offset), the trace will go down
// the /correct/ side of the plane: ie, the side the box is actually
// on
if (front >= offset && back >= offset) {
num = node->children[0];
continue;
}
if (front <= -offset && back <= -offset) {
num = node->children[1];
continue;
}
if (front >= offset || front <= -offset
|| back >= offset || back <= -offset) {
// either:
// back is guaranteed to be < offset or > -offset
// or
// front is guaranteed to be < offset or > -offset
// so splitting is needed, on the offset plane closes to front
side = front < back;
idist = 1.0 / (front - back);
if (front < 0) {
frac = (front + offset) * idist;
} else {
frac = (front - offset) * idist;
}
frac = bound (0, frac, 1);
} else {
// both:
// front is guaranteed to be < offset and > -offset
// and
// back is guaranteed to be < offset and > -offset
frac = 1;
side = front < back;
}
midf = p1f + (p2f - p1f) * frac;
for (i = 0; i < 3; i++)
mid[i] = p1[i] + frac * (p2[i] - p1[i]);
tstack->num = num;
tstack->side = side;
tstack->plane = plane;
VectorCopy (backpt, tstack->backpt);
tstack++;
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
VectorSubtract (backpt, frontpt, dist);
VectorMultAdd (frontpt, frac, dist, backpt);
return false;
num = node->children[side];
}
}
/*
SV_ClipMoveToEntity
@ -601,17 +693,18 @@ SV_ClipMoveToEntity (edict_t *touched, edict_t *mover, const vec3_t start,
trace.fraction = 1;
trace.allsolid = true;
//trace.isbox = true;
VectorCopy (end, trace.endpos);
// get the clipping hull
hull = SV_HullForEntity (touched, mins, maxs, offset);
//hull = SV_HullForEntity (touched, mins, maxs, trace.extents, offset);
hull = SV_HullForEntity (touched, mins, maxs, 0, offset);
VectorSubtract (start, offset, start_l);
VectorSubtract (end, offset, end_l);
// 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);
// fix trace up by the offset
if (trace.fraction != 1)
@ -805,7 +898,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin)
// get the clipping hull
hull = SV_HullForEntity (check, SVvector (ent, mins),
SVvector (ent, maxs), offset);
SVvector (ent, maxs), 0, offset);
VectorSubtract (origin, offset, offset);

View file

@ -1662,7 +1662,7 @@ PF_hullpointcontents (progs_t *pr)
hull_t *hull;
vec3_t offset;
hull = SV_HullForEntity (edict, mins, maxs, offset);
hull = SV_HullForEntity (edict, mins, maxs, 0, offset);
VectorSubtract (point, offset, offset);
R_INT (pr) = SV_HullPointContents (hull, 0, offset);
}

View file

@ -141,7 +141,7 @@ SV_HullForBox (const vec3_t mins, const vec3_t maxs)
*/
hull_t *
SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs,
vec3_t offset)
vec3_t extents, vec3_t offset)
{
hull_t *hull = 0;
int hull_index = 0;
@ -503,7 +503,7 @@ SV_ClipMoveToEntity (edict_t *touched, const vec3_t start,
VectorCopy (end, trace.endpos);
// get the clipping hull
hull = SV_HullForEntity (touched, mins, maxs, offset);
hull = SV_HullForEntity (touched, mins, maxs, 0, offset);
VectorSubtract (start, offset, start_l);
VectorSubtract (end, offset, end_l);
@ -704,7 +704,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin)
// get the clipping hull
hull = SV_HullForEntity (check, SVvector (ent, mins),
SVvector (ent, maxs), offset);
SVvector (ent, maxs), 0, offset);
VectorSubtract (origin, offset, offset);

View file

@ -396,7 +396,7 @@ ParseBrush (void)
nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
vecs[i][sv] = ns;
vecs[i][tv] = nt;
// cale and store into texinfo
// scale and store into texinfo
for (j = 0; j < 3; j++)
tx.vecs[i][j] = vecs[i][j] / scale[i];
tx.vecs[i][3] = vecs[i][3];