From 45d467d748cfd4edd179d3f8e6fa7749f35a2de3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 24 Dec 2006 03:13:29 +0000 Subject: [PATCH] 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. --- include/QF/model.h | 1 + include/world.h | 12 +- libs/models/brush/model_brush.c | 7 +- nq/source/sv_pr_cmds.c | 2 +- nq/source/world.c | 319 +++++++++++++++++++++----------- qw/source/sv_pr_cmds.c | 2 +- qw/source/world.c | 6 +- tools/qfbsp/source/map.c | 2 +- 8 files changed, 224 insertions(+), 127 deletions(-) diff --git a/include/QF/model.h b/include/QF/model.h index 2d6203d25..1940ce0bc 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -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; diff --git a/include/world.h b/include/world.h index 6281f078d..9594e3bb7 100644 --- a/include/world.h +++ b/include/world.h @@ -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); diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 0c0e2ac9e..3dc84c7b2 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -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; diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index 984099e7a..7b4345192 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -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); } diff --git a/nq/source/world.c b/nq/source/world.c index 2972411d9..5958d7876 100644 --- a/nq/source/world.c +++ b/nq/source/world.c @@ -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); diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index e16a8fe78..bf74b6dc6 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -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); } diff --git a/qw/source/world.c b/qw/source/world.c index 66d5e2386..5eb8f4857 100644 --- a/qw/source/world.c +++ b/qw/source/world.c @@ -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); diff --git a/tools/qfbsp/source/map.c b/tools/qfbsp/source/map.c index 23c961cd3..62d0bffce 100644 --- a/tools/qfbsp/source/map.c +++ b/tools/qfbsp/source/map.c @@ -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];