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; msurface_t **marksurfaces;
hull_t hulls[MAX_MAP_HULLS]; hull_t hulls[MAX_MAP_HULLS];
hull_t *hull_list[MAX_MAP_HULLS];
int numtextures; int numtextures;
texture_t **textures; texture_t **textures;

View file

@ -39,15 +39,16 @@ typedef struct
float dist; float dist;
} plane_t; } plane_t;
typedef struct trace_s typedef struct trace_s {
{
qboolean allsolid; // if true, plane is not valid qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area qboolean startsolid; // if true, the initial point was in a solid area
qboolean inopen, inwater; qboolean inopen, inwater;
float fraction; // time completed, 1.0 = didn't hit anything 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 vec3_t endpos; // final position
plane_t plane; // surface normal at impact plane_t plane; // surface normal at impact
struct edict_s *ent; // entity the surface is on struct edict_s *ent; // entity the surface is on
} trace_t; } trace_t;
// 1/32 epsilon to keep floating point happy // 1/32 epsilon to keep floating point happy
@ -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); int SV_HullPointContents (hull_t *hull, int num, const vec3_t p);
hull_t *SV_HullForEntity (struct edict_s *ent, const vec3_t mins, hull_t *SV_HullForEntity (struct edict_s *ent, const vec3_t mins,
const vec3_t maxs, vec3_t offset); const vec3_t maxs, vec3_t extents, 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);
qboolean MOD_TraceLine (hull_t *hull, int num, qboolean MOD_TraceLine (hull_t *hull, int num,
const vec3_t start, const vec3_t end, trace_t *trace); 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; loadmodel->numclipnodes = count;
hull = &loadmodel->hulls[1]; hull = &loadmodel->hulls[1];
loadmodel->hull_list[1] = hull;
hull->clipnodes = out; hull->clipnodes = out;
hull->firstclipnode = 0; hull->firstclipnode = 0;
hull->lastclipnode = count - 1; hull->lastclipnode = count - 1;
@ -663,6 +664,7 @@ Mod_LoadClipnodes (lump_t *l)
hull->clip_maxs[2] = 32; hull->clip_maxs[2] = 32;
hull = &loadmodel->hulls[2]; hull = &loadmodel->hulls[2];
loadmodel->hull_list[2] = hull;
hull->clipnodes = out; hull->clipnodes = out;
hull->firstclipnode = 0; hull->firstclipnode = 0;
hull->lastclipnode = count - 1; hull->lastclipnode = count - 1;
@ -691,7 +693,7 @@ Mod_LoadClipnodes (lump_t *l)
/* /*
Mod_MakeHull0 Mod_MakeHull0
Deplicate the drawing hull structure as a clipping hull Replicate the drawing hull structure as a clipping hull
*/ */
static void static void
Mod_MakeHull0 (void) Mod_MakeHull0 (void)
@ -702,6 +704,7 @@ Mod_MakeHull0 (void)
mnode_t *in, *child; mnode_t *in, *child;
hull = &loadmodel->hulls[0]; hull = &loadmodel->hulls[0];
loadmodel->hull_list[0] = hull;
in = loadmodel->nodes; in = loadmodel->nodes;
count = loadmodel->numnodes; count = loadmodel->numnodes;
@ -867,9 +870,11 @@ Mod_LoadBrushModel (model_t *mod, void *buffer)
bm = &mod->submodels[i]; bm = &mod->submodels[i];
mod->hulls[0].firstclipnode = bm->headnode[0]; mod->hulls[0].firstclipnode = bm->headnode[0];
mod->hull_list[0] = &mod->hulls[0];
for (j = 1; j < MAX_MAP_HULLS; j++) { for (j = 1; j < MAX_MAP_HULLS; j++) {
mod->hulls[j].firstclipnode = bm->headnode[j]; mod->hulls[j].firstclipnode = bm->headnode[j];
mod->hulls[j].lastclipnode = mod->numclipnodes - 1; mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
mod->hull_list[j] = &mod->hulls[j];
} }
mod->firstmodelsurface = bm->firstface; mod->firstmodelsurface = bm->firstface;

View file

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

View file

@ -28,7 +28,7 @@
# include "config.h" # include "config.h"
#endif #endif
static __attribute__ ((used)) const char rcsid[] = static __attribute__ ((used)) const char rcsid[] =
"$Id$"; "$Id$";
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
@ -141,29 +141,17 @@ SV_HullForBox (const vec3_t mins, const vec3_t maxs)
*/ */
hull_t * hull_t *
SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, 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; int hull_index = 0;
hull_t *hull = 0; hull_t *hull = 0, **hull_list = 0;
model_t *model; model_t *model;
vec3_t hullmins, hullmaxs, size; 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 if (sv_fields.rotated_bbox != -1
&& SVinteger (ent, rotated_bbox)) { && SVinteger (ent, rotated_bbox)) {
int h = SVinteger (ent, rotated_bbox) - 1; 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) { } if (SVfloat (ent, solid) == SOLID_BSP) {
// explicit hulls in the BSP model // explicit hulls in the BSP model
if (SVfloat (ent, movetype) != MOVETYPE_PUSH) if (SVfloat (ent, movetype) != MOVETYPE_PUSH)
@ -174,19 +162,49 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs,
if (!model || model->type != mod_brush) if (!model || model->type != mod_brush)
Sys_Error ("SOLID_BSP with a non bsp model"); 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) { if (hull) {
// calculate an offset value to center the origin // calculate an offset value to center the origin
VectorSubtract (hull->clip_mins, mins, offset); if (extents) {
VectorAdd (offset, SVvector (ent, origin), offset); VectorAdd (extents, mins, offset);
} else { // create a temp hull from bounding box sizes VectorSubtract (SVvector (ent, origin), offset, offset);
VectorSubtract (SVvector (ent, mins), maxs, hullmins); } else {
VectorSubtract (SVvector (ent, maxs), mins, hullmaxs); VectorSubtract (hull->clip_mins, mins, offset);
hull = SV_HullForBox (hullmins, hullmaxs); VectorAdd (offset, SVvector (ent, origin), offset);
}
} else {
// create a temp hull from bounding box sizes
if (extents) {
VectorCopy (SVvector (ent, mins), hullmins);
VectorCopy (SVvector (ent, maxs), hullmaxs);
VectorCopy (SVvector (ent, origin), offset); //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);
VectorCopy (SVvector (ent, origin), offset);
}
hull = SV_HullForBox (hullmins, hullmaxs);
} }
return hull; return hull;
@ -487,101 +505,175 @@ SV_TestEntityPosition (edict_t *ent)
// 1/32 epsilon to keep floating point happy // 1/32 epsilon to keep floating point happy
#define DIST_EPSILON (0.03125) #define DIST_EPSILON (0.03125)
qboolean typedef struct {
SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t backpt;
const vec3_t p1, const vec3_t p2, trace_t *trace) int side;
int num;
mplane_t *plane;
} tracestack_t;
static inline void
calc_impact (trace_t *trace, const vec3_t start, const vec3_t end,
const mplane_t *plane)
{ {
float frac, midf, t1, t2; vec_t t1, t2, frac, offset;
int side, i; vec3_t dist;
dclipnode_t *node;
mplane_t *plane;
vec3_t mid;
// check for empty t1 = PlaneDiff (start, plane);
if (num < 0) { t2 = PlaneDiff (end, plane);
if (num != CONTENTS_SOLID) { offset = 0;
trace->allsolid = false; if (trace->isbox) {
if (num == CONTENTS_EMPTY) if (plane->type < 3)
trace->inopen = true; offset = trace->extents[plane->type];
else else
trace->inwater = true; offset = (fabs (trace->extents[0] * plane->normal[0])
} else + fabs (trace->extents[1] * plane->normal[1])
trace->startsolid = true; + fabs (trace->extents[2] * plane->normal[2]));
return true; // empty
} }
// find the point distances if (t1 < 0) {
node = hull->clipnodes + num; frac = (t1 + DIST_EPSILON) / (t1 - t2);
plane = hull->planes + node->planenum; // invert plane parameters;
VectorNegate (plane->normal, trace->plane.normal);
if (plane->type < 3) { trace->plane.dist = -plane->dist;
t1 = p1[plane->type] - plane->dist;
t2 = p2[plane->type] - plane->dist;
} else { } else {
t1 = DotProduct (plane->normal, p1) - plane->dist; frac = (t1 - DIST_EPSILON) / (t1 - t2);
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); VectorCopy (plane->normal, trace->plane.normal);
trace->plane.dist = plane->dist; 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);
else
frac = (t1 - DIST_EPSILON) / (t1 - t2);
frac = bound (0, frac, 1); frac = bound (0, frac, 1);
trace->fraction = frac;
midf = p1f + (p2f - p1f) * frac; VectorSubtract (end, start, dist);
for (i = 0; i < 3; i++) VectorMultAdd (start, frac, dist, trace->endpos);
mid[i] = p1[i] + frac * (p2[i] - p1[i]);
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
return false;
} }
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 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];
}
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
offset = 0;
front = PlaneDiff (frontpt, plane);
back = PlaneDiff (backpt, plane);
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]));
}
// 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;
}
tstack->num = num;
tstack->side = side;
tstack->plane = plane;
VectorCopy (backpt, tstack->backpt);
tstack++;
VectorSubtract (backpt, frontpt, dist);
VectorMultAdd (frontpt, frac, dist, backpt);
num = node->children[side];
}
}
/* /*
SV_ClipMoveToEntity SV_ClipMoveToEntity
@ -601,17 +693,18 @@ SV_ClipMoveToEntity (edict_t *touched, edict_t *mover, const vec3_t start,
trace.fraction = 1; trace.fraction = 1;
trace.allsolid = true; trace.allsolid = true;
//trace.isbox = true;
VectorCopy (end, trace.endpos); VectorCopy (end, trace.endpos);
// get the clipping hull // 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 (start, offset, start_l);
VectorSubtract (end, offset, end_l); VectorSubtract (end, offset, end_l);
// trace a line through the apropriate clipping hull // trace a line through the apropriate clipping hull
SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, SV_RecursiveHullCheck (hull, hull->firstclipnode, start_l, end_l, &trace);
&trace);
// fix trace up by the offset // fix trace up by the offset
if (trace.fraction != 1) if (trace.fraction != 1)
@ -805,7 +898,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin)
// get the clipping hull // get the clipping hull
hull = SV_HullForEntity (check, SVvector (ent, mins), hull = SV_HullForEntity (check, SVvector (ent, mins),
SVvector (ent, maxs), offset); SVvector (ent, maxs), 0, offset);
VectorSubtract (origin, offset, offset); VectorSubtract (origin, offset, offset);

View file

@ -1662,7 +1662,7 @@ PF_hullpointcontents (progs_t *pr)
hull_t *hull; hull_t *hull;
vec3_t offset; vec3_t offset;
hull = SV_HullForEntity (edict, mins, maxs, offset); hull = SV_HullForEntity (edict, mins, maxs, 0, offset);
VectorSubtract (point, offset, offset); VectorSubtract (point, offset, offset);
R_INT (pr) = SV_HullPointContents (hull, 0, 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 * hull_t *
SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, 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; hull_t *hull = 0;
int hull_index = 0; int hull_index = 0;
@ -503,7 +503,7 @@ SV_ClipMoveToEntity (edict_t *touched, const vec3_t start,
VectorCopy (end, trace.endpos); VectorCopy (end, trace.endpos);
// get the clipping hull // 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 (start, offset, start_l);
VectorSubtract (end, offset, end_l); VectorSubtract (end, offset, end_l);
@ -704,7 +704,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin)
// get the clipping hull // get the clipping hull
hull = SV_HullForEntity (check, SVvector (ent, mins), hull = SV_HullForEntity (check, SVvector (ent, mins),
SVvector (ent, maxs), offset); SVvector (ent, maxs), 0, offset);
VectorSubtract (origin, offset, offset); VectorSubtract (origin, offset, offset);

View file

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