mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 04:42:32 +00:00
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:
parent
b3a2759e5b
commit
45d467d748
8 changed files with 224 additions and 127 deletions
|
@ -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;
|
||||
|
|
|
@ -39,15 +39,16 @@ 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
|
||||
struct edict_s *ent; // entity the surface is on
|
||||
} trace_t;
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static __attribute__ ((used)) const char rcsid[] =
|
||||
static __attribute__ ((used)) const char rcsid[] =
|
||||
"$Id$";
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
|
@ -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;
|
||||
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,19 +162,49 @@ 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
|
||||
VectorSubtract (hull->clip_mins, mins, offset);
|
||||
VectorAdd (offset, SVvector (ent, origin), offset);
|
||||
} else { // create a temp hull from bounding box sizes
|
||||
VectorSubtract (SVvector (ent, mins), maxs, hullmins);
|
||||
VectorSubtract (SVvector (ent, maxs), mins, hullmaxs);
|
||||
hull = SV_HullForBox (hullmins, hullmaxs);
|
||||
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
|
||||
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;
|
||||
|
@ -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)
|
||||
typedef struct {
|
||||
vec3_t backpt;
|
||||
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;
|
||||
int side, i;
|
||||
dclipnode_t *node;
|
||||
mplane_t *plane;
|
||||
vec3_t mid;
|
||||
vec_t t1, t2, frac, offset;
|
||||
vec3_t dist;
|
||||
|
||||
// check for empty
|
||||
if (num < 0) {
|
||||
if (num != CONTENTS_SOLID) {
|
||||
trace->allsolid = false;
|
||||
if (num == CONTENTS_EMPTY)
|
||||
trace->inopen = true;
|
||||
else
|
||||
trace->inwater = true;
|
||||
} else
|
||||
trace->startsolid = true;
|
||||
return true; // empty
|
||||
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]));
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (t1 < 0) {
|
||||
frac = (t1 + DIST_EPSILON) / (t1 - t2);
|
||||
// invert plane parameters;
|
||||
VectorNegate (plane->normal, trace->plane.normal);
|
||||
trace->plane.dist = -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) {
|
||||
frac = (t1 - DIST_EPSILON) / (t1 - t2);
|
||||
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);
|
||||
else
|
||||
frac = (t1 - DIST_EPSILON) / (t1 - t2);
|
||||
frac = bound (0, frac, 1);
|
||||
|
||||
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;
|
||||
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 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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue