entity_render_t *ent;
float tracemins[3], tracemaxs[3];
trace_t trace;
+ matrix4x4_t matrix, imatrix;
+ float tempnormal[3], starttransformed[3], endtransformed[3];
if (hitent)
*hitent = NULL;
Mod_CheckLoaded(cl.worldmodel);
if (cl.worldmodel && cl.worldmodel->brush.TraceBox)
- cl.worldmodel->brush.TraceBox(cl.worldmodel, vec3_origin, vec3_origin, &trace, NULL, start, vec3_origin, vec3_origin, end);
- else
- Collision_ClipTrace(&trace, NULL, cl.worldmodel, vec3_origin, vec3_origin, vec3_origin, vec3_origin, start, vec3_origin, vec3_origin, end);
+ cl.worldmodel->brush.TraceBox(cl.worldmodel, &trace, start, start, end, end);
if (impact)
- VectorCopy (trace.endpos, impact);
+ VectorLerp(start, trace.fraction, end, impact);
if (normal)
- VectorCopy (trace.plane.normal, normal);
+ VectorCopy(trace.plane.normal, normal);
cl_traceline_endcontents = trace.endcontents;
maxfrac = trace.fraction;
if (hitent && trace.fraction < 1)
if (ent->mins[0] > tracemaxs[0] || ent->maxs[0] < tracemins[0]
|| ent->mins[1] > tracemaxs[1] || ent->maxs[1] < tracemins[1]
|| ent->mins[2] > tracemaxs[2] || ent->maxs[2] < tracemins[2])
- continue;
+ continue;
+
+ Matrix4x4_CreateFromQuakeEntity(&matrix, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2], 1);
+ Matrix4x4_Invert_Simple(&imatrix, &matrix);
+ Matrix4x4_Transform(&imatrix, start, starttransformed);
+ Matrix4x4_Transform(&imatrix, end, endtransformed);
if (ent->model && ent->model->brush.TraceBox)
- ent->model->brush.TraceBox(ent->model, ent->origin, ent->angles, &trace, NULL, start, vec3_origin, vec3_origin, end);
- else
- Collision_ClipTrace(&trace, ent, ent->model, ent->origin, ent->angles, ent->mins, ent->maxs, start, vec3_origin, vec3_origin, end);
+ ent->model->brush.TraceBox(ent->model, &trace, starttransformed, starttransformed, endtransformed, endtransformed);
- if (trace.allsolid || trace.startsolid || trace.fraction < maxfrac)
+ if (trace.allsolid || trace.startsolid || maxfrac > trace.fraction)
{
- maxfrac = trace.fraction;
- if (impact)
- VectorCopy(trace.endpos, impact);
- if (normal)
- VectorCopy(trace.plane.normal, normal);
cl_traceline_endcontents = trace.endcontents;
if (hitent)
*hitent = ent;
+ if (maxfrac > trace.fraction)
+ {
+ maxfrac = trace.fraction;
+ if (impact)
+ VectorLerp(start, trace.fraction, end, impact);
+ if (normal)
+ {
+ VectorCopy(trace.plane.normal, tempnormal);
+ Matrix4x4_Transform3x3(&matrix, tempnormal, normal);
+ }
+ }
}
}
}
int CL_PointContents(const vec3_t p)
{
+ CL_TraceLine (p, p, NULL, NULL, 0, true, NULL);
+ return cl_traceline_endcontents;
+ /*
// FIXME: check multiple brush models
- if (cl.worldmodel && cl.worldmodel->brush.PointContents)
- return cl.worldmodel->brush.PointContents(cl.worldmodel, p);
- return CONTENTS_EMPTY;
+ if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1)
+ return cl.worldmodel->brush.PointContentsQ1(cl.worldmodel, p);
+ return 0;
+ */
}
#define HULLCHECKSTATE_SOLID 1
#define HULLCHECKSTATE_DONE 2
-static int RecursiveHullCheck (RecursiveHullCheckTraceInfo_t *t, int num, double p1f, double p2f, double p1[3], double p2[3])
+static int RecursiveHullCheck(RecursiveHullCheckTraceInfo_t *t, int num, double p1f, double p2f, double p1[3], double p2[3])
{
// status variables, these don't need to be saved on the stack when
// recursing... but are because this should be thread-safe
if (num < 0)
{
t->trace->endcontents = num;
- if (t->trace->startcontents)
+ if (t->trace->thiscontents)
{
- if (num == t->trace->startcontents)
+ if (num == t->trace->thiscontents)
t->trace->allsolid = false;
else
{
return HULLCHECKSTATE_DONE;
}
+#if 0
// used if start and end are the same
static void RecursiveHullCheckPoint (RecursiveHullCheckTraceInfo_t *t, int num)
{
// check for empty
t->trace->endcontents = num;
- if (t->trace->startcontents)
+ if (t->trace->thiscontents)
{
- if (num == t->trace->startcontents)
+ if (num == t->trace->thiscontents)
t->trace->allsolid = false;
else
{
}
}
}
+#endif
void Collision_RoundUpToHullSize(const model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs)
{
}
}
-
-static hull_t *HullForBBoxEntity (const vec3_t corigin, const vec3_t cmins, const vec3_t cmaxs, const vec3_t mins, const vec3_t maxs, vec3_t offset)
-{
- vec3_t hullmins, hullmaxs;
-
- // create a temp hull from bounding box sizes
- VectorCopy (corigin, offset);
- VectorSubtract (cmins, maxs, hullmins);
- VectorSubtract (cmaxs, mins, hullmaxs);
-
- //To keep everything totally uniform, bounding boxes are turned into small
- //BSP trees instead of being compared directly.
- box_planes[0].dist = hullmaxs[0];
- box_planes[1].dist = hullmins[0];
- box_planes[2].dist = hullmaxs[1];
- box_planes[3].dist = hullmins[1];
- box_planes[4].dist = hullmaxs[2];
- box_planes[5].dist = hullmins[2];
- return &box_hull;
-}
-
-static const hull_t *HullForBrushModel (const model_t *cmodel, const vec3_t corigin, const vec3_t mins, const vec3_t maxs, vec3_t offset)
-{
- vec3_t size;
- const hull_t *hull;
-
- // decide which clipping hull to use, based on the size
- // explicit hulls in the BSP model
- VectorSubtract (maxs, mins, size);
- // LordHavoc: FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- if (cmodel->brushq1.ishlbsp)
- {
- if (size[0] < 3)
- hull = &cmodel->brushq1.hulls[0]; // 0x0x0
- else if (size[0] <= 32)
- {
- if (size[2] < 54) // pick the nearest of 36 or 72
- hull = &cmodel->brushq1.hulls[3]; // 32x32x36
- else
- hull = &cmodel->brushq1.hulls[1]; // 32x32x72
- }
- else
- hull = &cmodel->brushq1.hulls[2]; // 64x64x64
- }
- else
- {
- if (size[0] < 3)
- hull = &cmodel->brushq1.hulls[0]; // 0x0x0
- else if (size[0] <= 32)
- hull = &cmodel->brushq1.hulls[1]; // 32x32x56
- else
- hull = &cmodel->brushq1.hulls[2]; // 64x64x88
- }
-
- // calculate an offset value to center the origin
- VectorSubtract (hull->clip_mins, mins, offset);
- VectorAdd (offset, corigin, offset);
-
- return hull;
-}
-
-void Collision_ClipTrace (trace_t *trace, const void *cent, const model_t *cmodel, const vec3_t corigin, const vec3_t cangles, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end)
+void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end)
{
RecursiveHullCheckTraceInfo_t rhc;
- vec3_t offset, forward, left, up;
- double startd[3], endd[3], tempd[3];
-
// fill in a default trace
- memset (&rhc, 0, sizeof(rhc));
- memset (trace, 0, sizeof(trace_t));
-
+ memset(&rhc, 0, sizeof(rhc));
+ memset(trace, 0, sizeof(trace_t));
+ //To keep everything totally uniform, bounding boxes are turned into small
+ //BSP trees instead of being compared directly.
+ // create a temp hull from bounding box sizes
+ box_planes[0].dist = cmaxs[0] - mins[0];
+ box_planes[1].dist = cmins[0] - maxs[0];
+ box_planes[2].dist = cmaxs[1] - mins[1];
+ box_planes[3].dist = cmins[1] - maxs[1];
+ box_planes[4].dist = cmaxs[2] - mins[2];
+ box_planes[5].dist = cmins[2] - maxs[2];
+ // trace a line through the generated clipping hull
+ rhc.hull = &box_hull;
rhc.trace = trace;
-
rhc.trace->fraction = 1;
rhc.trace->allsolid = true;
-
- if (cmodel && cmodel->type == mod_brush)
- {
- // brush model
-
- // get the clipping hull
- rhc.hull = HullForBrushModel (cmodel, corigin, mins, maxs, offset);
-
- VectorSubtract(start, offset, startd);
- VectorSubtract(end, offset, endd);
-
- // rotate start and end into the model's frame of reference
- if (cangles[0] || cangles[1] || cangles[2])
- {
- AngleVectorsFLU (cangles, forward, left, up);
- VectorCopy(startd, tempd);
- startd[0] = DotProduct (tempd, forward);
- startd[1] = DotProduct (tempd, left);
- startd[2] = DotProduct (tempd, up);
- VectorCopy(endd, tempd);
- endd[0] = DotProduct (tempd, forward);
- endd[1] = DotProduct (tempd, left);
- endd[2] = DotProduct (tempd, up);
- }
-
- // trace a line through the appropriate clipping hull
- VectorCopy(startd, rhc.start);
- VectorCopy(endd, rhc.end);
- VectorCopy(rhc.end, rhc.trace->endpos);
- VectorSubtract(rhc.end, rhc.start, rhc.dist);
- if (rhc.dist[0] || rhc.dist[1] || rhc.dist[2])
- RecursiveHullCheck (&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
- else
- RecursiveHullCheckPoint (&rhc, rhc.hull->firstclipnode);
- if (rhc.trace->fraction < 0 || rhc.trace->fraction > 1) Con_Printf("fraction out of bounds %f %s:%d\n", rhc.trace->fraction, __FILE__, __LINE__);
-
- // if we hit, unrotate endpos and normal, and store the entity we hit
- if (rhc.trace->fraction != 1)
- {
- // rotate endpos back to world frame of reference
- if (cangles[0] || cangles[1] || cangles[2])
- {
- VectorNegate (cangles, offset);
- AngleVectorsFLU (offset, forward, left, up);
-
- VectorCopy (rhc.trace->endpos, tempd);
- rhc.trace->endpos[0] = DotProduct (tempd, forward);
- rhc.trace->endpos[1] = DotProduct (tempd, left);
- rhc.trace->endpos[2] = DotProduct (tempd, up);
-
- VectorCopy (rhc.trace->plane.normal, tempd);
- rhc.trace->plane.normal[0] = DotProduct (tempd, forward);
- rhc.trace->plane.normal[1] = DotProduct (tempd, left);
- rhc.trace->plane.normal[2] = DotProduct (tempd, up);
- }
- rhc.trace->ent = (void *) cent;
- }
- else if (rhc.trace->allsolid || rhc.trace->startsolid)
- rhc.trace->ent = (void *) cent;
- // fix offset
- VectorAdd (rhc.trace->endpos, offset, rhc.trace->endpos);
- }
- else
- {
- // bounding box
-
- rhc.hull = HullForBBoxEntity (corigin, cmins, cmaxs, mins, maxs, offset);
-
- // trace a line through the generated clipping hull
- VectorSubtract(start, offset, rhc.start);
- VectorSubtract(end, offset, rhc.end);
- VectorCopy(rhc.end, rhc.trace->endpos);
- VectorSubtract(rhc.end, rhc.start, rhc.dist);
- if (rhc.dist[0] || rhc.dist[1] || rhc.dist[2])
- RecursiveHullCheck (&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
- else
- RecursiveHullCheckPoint (&rhc, rhc.hull->firstclipnode);
- if (rhc.trace->fraction < 0 || rhc.trace->fraction > 1) Con_Printf("fraction out of bounds %f %s:%d\n", rhc.trace->fraction, __FILE__, __LINE__);
-
- // if we hit, store the entity we hit
- if (rhc.trace->fraction != 1)
- {
- // fix offset
- VectorAdd (rhc.trace->endpos, offset, rhc.trace->endpos);
- rhc.trace->ent = (void *) cent;
- }
- else if (rhc.trace->allsolid || rhc.trace->startsolid)
- rhc.trace->ent = (void *) cent;
- }
+ VectorCopy(start, rhc.start);
+ VectorCopy(end, rhc.end);
+ VectorSubtract(rhc.end, rhc.start, rhc.dist);
+ RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
}
VectorCopy(end, trace->endpos);
}
+
+// LordHavoc: currently unused and not yet tested
+// note: this can be used for tracing a moving sphere vs a stationary sphere,
+// by simply adding the moving sphere's radius to the sphereradius parameter,
+// all the results are correct (impactpoint, impactnormal, and fraction)
+float Collision_ClipTrace_Line_Sphere(double *linestart, double *lineend, double *sphereorigin, double sphereradius, double *impactpoint, double *impactnormal)
+{
+ double dir[3], scale, v[3], deviationdist, impactdist, linelength;
+ // make sure the impactpoint and impactnormal are valid even if there is
+ // no collision
+ impactpoint[0] = lineend[0];
+ impactpoint[1] = lineend[1];
+ impactpoint[2] = lineend[2];
+ impactnormal[0] = 0;
+ impactnormal[1] = 0;
+ impactnormal[2] = 0;
+ // calculate line direction
+ dir[0] = lineend[0] - linestart[0];
+ dir[1] = lineend[1] - linestart[1];
+ dir[2] = lineend[2] - linestart[2];
+ // normalize direction
+ linelength = sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
+ if (linelength)
+ {
+ scale = 1.0 / linelength;
+ dir[0] *= scale;
+ dir[1] *= scale;
+ dir[2] *= scale;
+ }
+ // this dotproduct calculates the distance along the line at which the
+ // sphere origin is (nearest point to the sphere origin on the line)
+ impactdist = dir[0] * (sphereorigin[0] - linestart[0]) + dir[1] * (sphereorigin[1] - linestart[1]) + dir[2] * (sphereorigin[2] - linestart[2]);
+ // calculate point on line at that distance, and subtract the
+ // sphereorigin from it, so we have a vector to measure for the distance
+ // of the line from the sphereorigin (deviation, how off-center it is)
+ v[0] = linestart[0] + impactdist * dir[0] - sphereorigin[0];
+ v[1] = linestart[1] + impactdist * dir[1] - sphereorigin[1];
+ v[2] = linestart[2] + impactdist * dir[2] - sphereorigin[2];
+ deviationdist = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+ // if outside the radius, it's a miss for sure
+ // (we do this comparison using squared radius to avoid a sqrt)
+ if (deviationdist > sphereradius*sphereradius)
+ return 1; // miss (off to the side)
+ // nudge back to find the correct impact distance
+ impactdist += (sqrt(deviationdist) - sphereradius);
+ if (impactdist >= linelength)
+ return 1; // miss (not close enough)
+ if (impactdist < 0)
+ return 1; // miss (linestart is past or inside sphere)
+ // calculate new impactpoint
+ impactpoint[0] = linestart[0] + impactdist * dir[0];
+ impactpoint[1] = linestart[1] + impactdist * dir[1];
+ impactpoint[2] = linestart[2] + impactdist * dir[2];
+ // calculate impactnormal (surface normal at point of impact)
+ impactnormal[0] = impactpoint[0] - sphereorigin[0];
+ impactnormal[1] = impactpoint[1] - sphereorigin[1];
+ impactnormal[2] = impactpoint[2] - sphereorigin[2];
+ // normalize impactnormal
+ scale = impactnormal[0] * impactnormal[0] + impactnormal[1] * impactnormal[1] + impactnormal[2] * impactnormal[2];
+ if (scale)
+ {
+ scale = 1.0 / sqrt(scale);
+ impactnormal[0] *= scale;
+ impactnormal[1] *= scale;
+ impactnormal[2] *= scale;
+ }
+ // return fraction of movement distance
+ return impactdist / linelength;
+}
+
#ifndef COLLISION_H
#define COLLISION_H
-typedef struct
+typedef struct plane_s
{
vec3_t normal;
float dist;
-} plane_t;
+}
+plane_t;
-typedef struct
+typedef struct trace_s
{
// if true, the entire trace was in solid
int allsolid;
void *ent;
// if not zero, treats this value as empty, and all others as solid (impact
// on content change)
- int startcontents;
- // the contents that was hit at the end or impact point
+ int thiscontents;
+ // the contents at the impact or end point
int endcontents;
}
trace_t;
void Collision_RoundUpToHullSize(const model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs);
-void Collision_Init (void);
-void Collision_ClipTrace (trace_t *trace, const void *cent, const model_t *cmodel, const vec3_t corigin, const vec3_t cangles, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end);
+void Collision_Init(void);
+void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end);
typedef struct colpointf_s
{
float Collision_TraceBrushBModel(const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, model_t *model, float *impactnormal, int *startsolid, int *allsolid);
float Collision_TraceBrushBModelTransform(const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, model_t *model, float *impactnormal, const matrix4x4_t *modelmatrixstart, const matrix4x4_t *modelmatrixend, int *startsolid, int *allsolid);
-void Collision_PolygonClipTrace (trace_t *trace, const void *cent, model_t *cmodel, const vec3_t corigin, const vec3_t cangles, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end);
+void Collision_PolygonClipTrace(trace_t *trace, const void *cent, model_t *cmodel, const vec3_t corigin, const vec3_t cangles, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end);
#endif
return (mleaf_t *)node;
}
+/*
static int Mod_Q1BSP_PointContents(model_t *model, const vec3_t p)
{
mnode_t *node;
return ((mleaf_t *)node)->contents;
}
+*/
typedef struct findnonsolidlocationinfo_s
{
VectorCopy(info.center, out);
}
+typedef struct
+{
+ // the hull we're tracing through
+ const hull_t *hull;
+
+ // the trace structure to fill in
+ trace_t *trace;
+
+ // start, end, and end - start (in model space)
+ double start[3];
+ double end[3];
+ double dist[3];
+}
+RecursiveHullCheckTraceInfo_t;
+
+// 1/32 epsilon to keep floating point happy
+#define DIST_EPSILON (0.03125)
+
+#define HULLCHECKSTATE_EMPTY 0
+#define HULLCHECKSTATE_SOLID 1
+#define HULLCHECKSTATE_DONE 2
+
+static int Mod_Q1BSP_RecursiveHullCheck(RecursiveHullCheckTraceInfo_t *t, int num, double p1f, double p2f, double p1[3], double p2[3])
+{
+ // status variables, these don't need to be saved on the stack when
+ // recursing... but are because this should be thread-safe
+ // (note: tracing against a bbox is not thread-safe, yet)
+ int ret;
+ mplane_t *plane;
+ double t1, t2;
+
+ // variables that need to be stored on the stack when recursing
+ dclipnode_t *node;
+ int side;
+ double midf, mid[3];
+
+ // LordHavoc: a goto! everyone flee in terror... :)
+loc0:
+ // check for empty
+ if (num < 0)
+ {
+ t->trace->endcontents = num;
+ if (t->trace->thiscontents)
+ {
+ if (num == t->trace->thiscontents)
+ t->trace->allsolid = false;
+ else
+ {
+ // if the first leaf is solid, set startsolid
+ if (t->trace->allsolid)
+ t->trace->startsolid = true;
+ return HULLCHECKSTATE_SOLID;
+ }
+ return HULLCHECKSTATE_EMPTY;
+ }
+ else
+ {
+ if (num != CONTENTS_SOLID)
+ {
+ t->trace->allsolid = false;
+ if (num == CONTENTS_EMPTY)
+ t->trace->inopen = true;
+ else
+ t->trace->inwater = true;
+ }
+ else
+ {
+ // if the first leaf is solid, set startsolid
+ if (t->trace->allsolid)
+ t->trace->startsolid = true;
+ return HULLCHECKSTATE_SOLID;
+ }
+ return HULLCHECKSTATE_EMPTY;
+ }
+ }
+
+ // find the point distances
+ node = t->hull->clipnodes + num;
+
+ plane = t->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)
+ {
+ if (t2 < 0)
+ {
+ num = node->children[1];
+ goto loc0;
+ }
+ side = 1;
+ }
+ else
+ {
+ if (t2 >= 0)
+ {
+ num = node->children[0];
+ goto loc0;
+ }
+ side = 0;
+ }
+
+ // the line intersects, find intersection point
+ // LordHavoc: this uses the original trace for maximum accuracy
+ if (plane->type < 3)
+ {
+ t1 = t->start[plane->type] - plane->dist;
+ t2 = t->end[plane->type] - plane->dist;
+ }
+ else
+ {
+ t1 = DotProduct (plane->normal, t->start) - plane->dist;
+ t2 = DotProduct (plane->normal, t->end) - plane->dist;
+ }
+
+ midf = t1 / (t1 - t2);
+ midf = bound(p1f, midf, p2f);
+ VectorMA(t->start, midf, t->dist, mid);
+
+ // recurse both sides, front side first
+ ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[side], p1f, midf, p1, mid);
+ // if this side is not empty, return what it is (solid or done)
+ if (ret != HULLCHECKSTATE_EMPTY)
+ return ret;
+
+ ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[side ^ 1], midf, p2f, mid, p2);
+ // if other side is not solid, return what it is (empty or done)
+ if (ret != HULLCHECKSTATE_SOLID)
+ return ret;
+
+ // front is air and back is solid, this is the impact point...
+ if (side)
+ {
+ t->trace->plane.dist = -plane->dist;
+ VectorNegate (plane->normal, t->trace->plane.normal);
+ }
+ else
+ {
+ t->trace->plane.dist = plane->dist;
+ VectorCopy (plane->normal, t->trace->plane.normal);
+ }
+
+ // bias away from surface a bit
+ t1 = DotProduct(t->trace->plane.normal, t->start) - (t->trace->plane.dist + DIST_EPSILON);
+ t2 = DotProduct(t->trace->plane.normal, t->end) - (t->trace->plane.dist + DIST_EPSILON);
+
+ midf = t1 / (t1 - t2);
+ t->trace->fraction = bound(0.0f, midf, 1.0);
+
+ return HULLCHECKSTATE_DONE;
+}
+
+static void Mod_Q1BSP_TraceBox(struct model_s *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs)
+{
+ // this function currently only supports same size start and end
+ double boxsize[3];
+ RecursiveHullCheckTraceInfo_t rhc;
+
+ memset(&rhc, 0, sizeof(rhc));
+ memset(trace, 0, sizeof(trace_t));
+ rhc.trace = trace;
+ rhc.trace->fraction = 1;
+ rhc.trace->allsolid = true;
+ VectorSubtract(boxstartmaxs, boxstartmins, boxsize);
+ if (boxsize[0] < 3)
+ rhc.hull = &model->brushq1.hulls[0]; // 0x0x0
+ else if (model->brushq1.ishlbsp)
+ {
+ if (boxsize[0] <= 32)
+ {
+ if (boxsize[2] < 54) // pick the nearest of 36 or 72
+ rhc.hull = &model->brushq1.hulls[3]; // 32x32x36
+ else
+ rhc.hull = &model->brushq1.hulls[1]; // 32x32x72
+ }
+ else
+ rhc.hull = &model->brushq1.hulls[2]; // 64x64x64
+ }
+ else
+ {
+ if (boxsize[0] <= 32)
+ rhc.hull = &model->brushq1.hulls[1]; // 32x32x56
+ else
+ rhc.hull = &model->brushq1.hulls[2]; // 64x64x88
+ }
+ VectorSubtract(boxstartmins, rhc.hull->clip_mins, rhc.start);
+ VectorSubtract(boxendmins, rhc.hull->clip_mins, rhc.end);
+ VectorSubtract(rhc.end, rhc.start, rhc.dist);
+ Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
+}
+
static qbyte *Mod_Q1BSP_DecompressVis(model_t *model, qbyte *in)
{
static qbyte decompressed[MAX_MAP_LEAFS/8];
mod->brushq1.ishlbsp = i == 30;
mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation;
- mod->brush.PointContents = Mod_Q1BSP_PointContents;
+ mod->brush.TraceBox = Mod_Q1BSP_TraceBox;
mod->brushq1.PointInLeaf = Mod_Q1BSP_PointInLeaf;
mod->brushq1.LeafPVS = Mod_Q1BSP_LeafPVS;
mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains;
}
model_sprite_t;
+struct trace_s;
+
typedef struct model_brush_s
{
char *entities;
void (*FindNonSolidLocation)(struct model_s *model, const vec3_t in, vec3_t out, vec_t radius);
- int (*PointContents)(struct model_s *model, const float *p);
- void (*TraceBox)(struct model_s *model, const vec3_t corigin, const vec3_t cangles, void *trace, const void *cent, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end);
+ void (*TraceBox)(struct model_s *model, struct trace_s *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs);
}
model_brush_t;
edict_t *ent;
eval_t *val;
entity_state_t *baseline; // LordHavoc: delta or startup baseline
- trace_t trace;
model_t *model;
Mod_CheckLoaded(sv.worldmodel);
testorigin[1] = lhrandom(entmins[1], entmaxs[1]);
testorigin[2] = lhrandom(entmins[2], entmaxs[2]);
- if (sv.worldmodel && sv.worldmodel->brush.TraceBox)
- sv.worldmodel->brush.TraceBox(sv.worldmodel, vec3_origin, vec3_origin, &trace, testeye, vec3_origin, vec3_origin, testorigin);
- else
- Collision_ClipTrace(&trace, NULL, sv.worldmodel, vec3_origin, vec3_origin, vec3_origin, testeye, vec3_origin, vec3_origin, testorigin);
-
- if (trace.fraction == 1)
+ if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1)
client->visibletime[e] = realtime + 1;
else
{
testorigin[1] = bound(entmins[1], testeye[1], entmaxs[1]);
testorigin[2] = bound(entmins[2], testeye[2], entmaxs[2]);
- if (sv.worldmodel && sv.worldmodel->brush.TraceBox)
- sv.worldmodel->brush.TraceBox(sv.worldmodel, vec3_origin, vec3_origin, &trace, testeye, vec3_origin, vec3_origin, testorigin);
- else
- Collision_ClipTrace(&trace, NULL, sv.worldmodel, vec3_origin, vec3_origin, vec3_origin, testeye, vec3_origin, vec3_origin, testorigin);
-
- if (trace.fraction == 1)
+ if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1)
client->visibletime[e] = realtime + 1;
else if (realtime > client->visibletime[e])
{
vec3_t origin, angles, entmins, entmaxs, lightmins, lightmaxs, testorigin, testeye;
edict_t *ent;
eval_t *val;
- trace_t trace;
model_t *model;
entity_state_t *s;
testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f;
testorigin[1] = (entmins[1] + entmaxs[1]) * 0.5f;
testorigin[2] = (entmins[2] + entmaxs[2]) * 0.5f;
- if (sv.worldmodel && sv.worldmodel->brush.TraceBox)
- sv.worldmodel->brush.TraceBox(sv.worldmodel, vec3_origin, vec3_origin, &trace, NULL, testeye, vec3_origin, vec3_origin, testorigin);
- else
- Collision_ClipTrace(&trace, NULL, sv.worldmodel, vec3_origin, vec3_origin, vec3_origin, vec3_origin, testeye, vec3_origin, vec3_origin, testorigin);
- if (trace.fraction == 1)
+ if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1)
client->visibletime[e] = realtime + 1;
else
{
testorigin[0] = lhrandom(entmins[0], entmaxs[0]);
testorigin[1] = lhrandom(entmins[1], entmaxs[1]);
testorigin[2] = lhrandom(entmins[2], entmaxs[2]);
- if (sv.worldmodel && sv.worldmodel->brush.TraceBox)
- sv.worldmodel->brush.TraceBox(sv.worldmodel, vec3_origin, vec3_origin, &trace, NULL, testeye, vec3_origin, vec3_origin, testorigin);
- else
- Collision_ClipTrace(&trace, NULL, sv.worldmodel, vec3_origin, vec3_origin, vec3_origin, vec3_origin, testeye, vec3_origin, vec3_origin, testorigin);
- if (trace.fraction == 1)
+ if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1)
client->visibletime[e] = realtime + 1;
else
{
testorigin[0] = lhrandom(lightmins[0], lightmaxs[0]);
testorigin[1] = lhrandom(lightmins[1], lightmaxs[1]);
testorigin[2] = lhrandom(lightmins[2], lightmaxs[2]);
- if (sv.worldmodel && sv.worldmodel->brush.TraceBox)
- sv.worldmodel->brush.TraceBox(sv.worldmodel, vec3_origin, vec3_origin, &trace, NULL, testeye, vec3_origin, vec3_origin, testorigin);
- else
- Collision_ClipTrace(&trace, NULL, sv.worldmodel, vec3_origin, vec3_origin, vec3_origin, vec3_origin, testeye, vec3_origin, vec3_origin, testorigin);
- if (trace.fraction == 1)
+ if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1)
client->visibletime[e] = realtime + 1;
else
{
eventually rotation) of the end points
==================
*/
-trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+trace_t SV_ClipMoveToEntity(edict_t *ent, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end)
{
int i;
trace_t trace;
model_t *model = NULL;
+ matrix4x4_t matrix, imatrix;
+ float tempnormal[3], starttransformed[3], endtransformed[3];
+ float starttransformedmins[3], starttransformedmaxs[3], endtransformedmins[3], endtransformedmaxs[3];
if ((int) ent->v->solid == SOLID_BSP)
{
Host_Error ("SV_ClipMoveToEntity: SOLID_BSP without MOVETYPE_PUSH");
}
- if (model && model->brush.TraceBox)
- model->brush.TraceBox(model, ent->v->origin, ent->v->angles, &trace, ent, start, mins, maxs, end);
- // FIXME: these should go away
- else if (sv_polygoncollisions.integer && (mins[0] != maxs[0] || mins[1] != maxs[1] || mins[2] != maxs[2]))
- Collision_PolygonClipTrace(&trace, ent, model, ent->v->origin, ent->v->angles, ent->v->mins, ent->v->maxs, start, mins, maxs, end);
+ Matrix4x4_CreateFromQuakeEntity(&matrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], 1);
+ Matrix4x4_Invert_Simple(&imatrix, &matrix);
+ Matrix4x4_Transform(&imatrix, start, starttransformed);
+ Matrix4x4_Transform(&imatrix, end, endtransformed);
+ VectorAdd(starttransformed, maxs, starttransformedmaxs);
+ VectorAdd(endtransformed, maxs, endtransformedmaxs);
+ VectorAdd(starttransformed, mins, starttransformedmins);
+ VectorAdd(endtransformed, mins, endtransformedmins);
+
+ // FIXME: the PolygonClipTrace should go away (should all be done in model code)
+ if (sv_polygoncollisions.integer == 1)
+ Collision_PolygonClipTrace(&trace, ent, model, vec3_origin, vec3_origin, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed);
+ else if (model && model->brush.TraceBox)
+ model->brush.TraceBox(model, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs);
else
- Collision_ClipTrace(&trace, ent, model, ent->v->origin, ent->v->angles, ent->v->mins, ent->v->maxs, start, mins, maxs, end);
+ Collision_ClipTrace_Box(&trace, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed);
+
+ if (trace.fraction < 1 || trace.startsolid)
+ trace.ent = ent;
+ VectorLerp(start, trace.fraction, end, trace.endpos);
+ VectorCopy(trace.plane.normal, tempnormal);
+ Matrix4x4_Transform3x3(&matrix, tempnormal, trace.plane.normal);
+ // FIXME: should recalc trace.plane.dist
return trace;
}
if (clip->passedict)
{
- if (clip->passedict->v->size[0] && !touch->v->size[0])
+ if (!clip->passedict->v->size[0] && !touch->v->size[0])
continue; // points never interact
if (PROG_TO_EDICT(touch->v->owner) == clip->passedict)
continue; // don't clip against own missiles
clip->trace.fraction = trace.fraction;
VectorCopy(trace.endpos, clip->trace.endpos);
clip->trace.plane = trace.plane;
+ //clip->trace.endcontents = trace.endcontents;
+ clip->trace.ent = touch;
+ }
+ // FIXME: the handling of endcontents is really broken but works well enough for point checks
+ if (trace.endcontents < clip->trace.endcontents || trace.endcontents == CONTENTS_SOLID)
+ {
+ // lower numbered (lava is lower than water, for example)
+ // contents override higher numbered contents, except for
+ // CONTENTS_SOLID which overrides everything
clip->trace.endcontents = trace.endcontents;
- clip->trace.ent = trace.ent;
}
if (clip->trace.allsolid)
return;
}
}
-/*
-====================
-SV_ClipToAreaGrid
-
-Mins and maxs enclose the entire area swept by the move
-====================
-*/
-void SV_ClipToAreaGrid(moveclip_t *clip)
-{
- areagrid_t *grid;
- int igrid[3], igridmins[3], igridmaxs[3];
-
- if (clip->trace.allsolid)
- return;
-
- sv_areagrid_stats_calls++;
- sv_areagrid_marknumber++;
- igridmins[0] = (int) ((clip->boxmins[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]);
- igridmins[1] = (int) ((clip->boxmins[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]);
- //igridmins[2] = (int) ((clip->boxmins[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]);
- igridmaxs[0] = (int) ((clip->boxmaxs[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]) + 1;
- igridmaxs[1] = (int) ((clip->boxmaxs[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]) + 1;
- //igridmaxs[2] = (int) ((clip->boxmaxs[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]) + 1;
- igridmins[0] = max(0, igridmins[0]);
- igridmins[1] = max(0, igridmins[1]);
- //igridmins[2] = max(0, igridmins[2]);
- igridmaxs[0] = min(AREA_GRID, igridmaxs[0]);
- igridmaxs[1] = min(AREA_GRID, igridmaxs[1]);
- //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]);
-
- if (sv_areagrid_outside.solid_edicts.next != &sv_areagrid_outside.solid_edicts)
- SV_ClipToNode(clip, &sv_areagrid_outside.solid_edicts);
-
- for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
- for (grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0], igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
- if (grid->solid_edicts.next != &grid->solid_edicts)
- SV_ClipToNode(clip, &grid->solid_edicts);
-}
-
-
-/*
-==================
-SV_MoveBounds
-==================
-*/
-void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
-{
- if (!sv_debugmove.integer)
- {
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if (end[i] > start[i])
- {
- boxmins[i] = start[i] + mins[i] - 1;
- boxmaxs[i] = end[i] + maxs[i] + 1;
- }
- else
- {
- boxmins[i] = end[i] + mins[i] - 1;
- boxmaxs[i] = start[i] + maxs[i] + 1;
- }
- }
- }
- else
- {
- // debug to test against everything
- boxmins[0] = boxmins[1] = boxmins[2] = -999999999;
- boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 999999999;
- }
-}
-
/*
==================
SV_Move
==================
*/
-trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
+trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict)
{
- moveclip_t clip;
- vec3_t bigmins, bigmaxs;
- int i;
+ moveclip_t clip;
+ vec3_t bigmins, bigmaxs;
+ areagrid_t *grid;
+ int i, igrid[3], igridmins[3], igridmaxs[3];
- memset ( &clip, 0, sizeof ( moveclip_t ) );
+ memset(&clip, 0, sizeof(moveclip_t));
VectorCopy(start, clip.start);
VectorCopy(end, clip.end);
Collision_RoundUpToHullSize(sv.worldmodel, clip.mins, clip.maxs, clip.hullmins, clip.hullmaxs);
- if (type == MOVE_MISSILE)
+ // clip to world
+ clip.trace = SV_ClipMoveToEntity(sv.edicts, clip.start, clip.hullmins, clip.hullmaxs, clip.end);
+ //if (clip.trace.allsolid)
+ // return clip.trace;
+
+ if (clip.type == MOVE_MISSILE)
{
// LordHavoc: modified this, was = -15, now = clip.mins[i] - 15
for (i=0 ; i<3 ; i++)
bigmins[2] = min(clip.mins2[2], clip.hullmins[2]);
bigmaxs[2] = max(clip.maxs2[2], clip.hullmaxs[2]);
- // clip to world
- clip.trace = SV_ClipMoveToEntity (sv.edicts, start, mins, maxs, end);
-
- // clip to entities
// create the bounding box of the entire move
- SV_MoveBounds ( start, bigmins, bigmaxs, end, clip.boxmins, clip.boxmaxs );
+ if (!sv_debugmove.integer)
+ {
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (clip.trace.endpos[i] > clip.start[i])
+ {
+ clip.boxmins[i] = clip.start[i] + bigmins[i] - 1;
+ clip.boxmaxs[i] = clip.trace.endpos[i] + bigmaxs[i] + 1;
+ }
+ else
+ {
+ clip.boxmins[i] = clip.trace.endpos[i] + bigmins[i] - 1;
+ clip.boxmaxs[i] = clip.start[i] + bigmaxs[i] + 1;
+ }
+ }
+ }
+ else
+ {
+ // debug to test against everything
+ clip.boxmins[0] = clip.boxmins[1] = clip.boxmins[2] = -999999999;
+ clip.boxmaxs[0] = clip.boxmaxs[1] = clip.boxmaxs[2] = 999999999;
+ }
- SV_ClipToAreaGrid(&clip);
+ // clip to enttiies
+ sv_areagrid_stats_calls++;
+ sv_areagrid_marknumber++;
+ igridmins[0] = (int) ((clip.boxmins[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]);
+ igridmins[1] = (int) ((clip.boxmins[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]);
+ //igridmins[2] = (int) ((clip->boxmins[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]);
+ igridmaxs[0] = (int) ((clip.boxmaxs[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]) + 1;
+ igridmaxs[1] = (int) ((clip.boxmaxs[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]) + 1;
+ //igridmaxs[2] = (int) ((clip->boxmaxs[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]) + 1;
+ igridmins[0] = max(0, igridmins[0]);
+ igridmins[1] = max(0, igridmins[1]);
+ //igridmins[2] = max(0, igridmins[2]);
+ igridmaxs[0] = min(AREA_GRID, igridmaxs[0]);
+ igridmaxs[1] = min(AREA_GRID, igridmaxs[1]);
+ //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]);
+
+ if (sv_areagrid_outside.solid_edicts.next != &sv_areagrid_outside.solid_edicts)
+ SV_ClipToNode(&clip, &sv_areagrid_outside.solid_edicts);
+
+ for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
+ for (grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0], igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
+ if (grid->solid_edicts.next != &grid->solid_edicts)
+ SV_ClipToNode(&clip, &grid->solid_edicts);
return clip.trace;
}
int SV_PointContents(const vec3_t point)
{
+#if 1
+ return SV_Move(point, vec3_origin, vec3_origin, point, MOVE_NOMONSTERS, NULL).endcontents;
+#else
if (sv.worldmodel && sv.worldmodel->brush.PointContents)
return sv.worldmodel->brush.PointContents(sv.worldmodel, point);
return CONTENTS_SOLID;
+#endif
}
// shouldn't be considered solid objects
// passedict is explicitly excluded from clipping checks (normally NULL)
-trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict);
+trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict);
int SV_PointContents(const vec3_t point);