2004-11-02 08:40:00 +00:00
|
|
|
/*
|
|
|
|
trace.c
|
|
|
|
|
|
|
|
BSP line tracing
|
|
|
|
|
|
|
|
Copyright (C) 2004 Bill Currie
|
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2004/9/25
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2005-08-04 15:27:09 +00:00
|
|
|
static __attribute__ ((used)) const char rcsid[] =
|
2004-11-02 08:40:00 +00:00
|
|
|
"$Id$";
|
|
|
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "QF/model.h"
|
2006-12-25 01:21:52 +00:00
|
|
|
#include "QF/sys.h"
|
2011-11-20 00:33:57 +00:00
|
|
|
#include "QF/winding.h"
|
2004-11-02 08:40:00 +00:00
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
#include "world.h"
|
|
|
|
|
|
|
|
/* LINE TESTING IN HULLS */
|
|
|
|
|
2010-12-05 05:56:32 +00:00
|
|
|
// 1/32 epsilon to keep floating point happy
|
2010-12-06 06:30:56 +00:00
|
|
|
#ifndef DIST_EPSILON
|
2010-12-05 05:56:32 +00:00
|
|
|
#define DIST_EPSILON (0.03125)
|
2010-12-06 06:30:56 +00:00
|
|
|
#endif
|
2010-12-05 05:56:32 +00:00
|
|
|
|
2010-12-05 05:52:20 +00:00
|
|
|
typedef struct {
|
2011-11-12 11:42:44 +00:00
|
|
|
vec3_t start;
|
2010-12-05 05:52:20 +00:00
|
|
|
vec3_t end;
|
2011-11-13 01:13:10 +00:00
|
|
|
vec_t start_frac;
|
2010-12-05 05:52:20 +00:00
|
|
|
int side;
|
|
|
|
int num;
|
2011-11-14 02:18:22 +00:00
|
|
|
plane_t *plane;
|
2010-12-05 05:52:20 +00:00
|
|
|
} tracestack_t;
|
|
|
|
|
2011-10-02 12:06:56 +00:00
|
|
|
static inline float
|
2011-11-14 02:18:22 +00:00
|
|
|
calc_offset (trace_t *trace, plane_t *plane)
|
2011-10-02 12:06:56 +00:00
|
|
|
{
|
2011-10-06 11:09:10 +00:00
|
|
|
vec_t d = 0;
|
|
|
|
vec3_t Rn;
|
|
|
|
|
|
|
|
switch (trace->type) {
|
|
|
|
case tr_point:
|
|
|
|
break;
|
|
|
|
case tr_box:
|
|
|
|
if (plane->type < 3)
|
|
|
|
d = trace->extents[plane->type];
|
|
|
|
else
|
|
|
|
d = (fabs (trace->extents[0] * plane->normal[0])
|
|
|
|
+ fabs (trace->extents[1] * plane->normal[1])
|
|
|
|
+ fabs (trace->extents[2] * plane->normal[2]));
|
|
|
|
break;
|
|
|
|
case tr_ellipsoid:
|
|
|
|
VectorSet (trace->extents[0] * plane->normal[0],
|
|
|
|
trace->extents[1] * plane->normal[1],
|
|
|
|
trace->extents[2] * plane->normal[2], Rn);
|
|
|
|
d = sqrt(DotProduct (Rn, Rn)); //FIXME no sqrt
|
|
|
|
break;
|
2011-10-02 12:06:56 +00:00
|
|
|
}
|
2011-10-06 11:09:10 +00:00
|
|
|
return d;
|
2011-10-02 12:06:56 +00:00
|
|
|
}
|
|
|
|
|
2011-11-20 00:33:57 +00:00
|
|
|
static int
|
|
|
|
check_in_leaf (hull_t *hull, trace_t *trace, clipleaf_t *leaf, plane_t *plane,
|
|
|
|
const vec3_t vel, const vec3_t org)
|
|
|
|
{
|
|
|
|
clipport_t *portal;
|
|
|
|
int side;
|
|
|
|
int miss = 0;
|
|
|
|
int i;
|
|
|
|
int planenum;
|
|
|
|
plane_t cutplane;
|
|
|
|
vec_t offset, dist, v_n;
|
|
|
|
vec_t *point, *edge;
|
|
|
|
|
|
|
|
planenum = plane - hull->planes;
|
|
|
|
cutplane.type = 3; // generic plane
|
|
|
|
v_n = DotProduct (vel, plane->normal);
|
|
|
|
|
|
|
|
for (portal = leaf->portals; portal; portal = portal->next[side]) {
|
|
|
|
side = portal->leafs[1] == leaf;
|
|
|
|
if (portal->planenum != planenum)
|
|
|
|
continue;
|
|
|
|
for (i = 0; !miss && i < portal->winding->numpoints; i++) {
|
|
|
|
point = portal->winding->points[i];
|
|
|
|
edge = portal->edges->points[i];
|
|
|
|
// so long as the plane distance and offset are calculated using
|
|
|
|
// the same normal vector, the normal vector length does not
|
|
|
|
// matter.
|
|
|
|
CrossProduct (vel, edge, cutplane.normal);
|
2011-11-20 05:14:42 +00:00
|
|
|
cutplane.dist = DotProduct (cutplane.normal, point);
|
2011-11-20 00:33:57 +00:00
|
|
|
dist = PlaneDiff (org, &cutplane);
|
|
|
|
offset = calc_offset (trace, &cutplane);
|
|
|
|
if (v_n >= 0)
|
|
|
|
miss = dist >= offset;
|
|
|
|
else
|
|
|
|
miss = dist <= -offset;
|
|
|
|
}
|
|
|
|
if (!miss)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-27 09:50:57 +00:00
|
|
|
typedef struct {
|
|
|
|
plane_t planes[3];
|
|
|
|
winding_t points[3];
|
|
|
|
winding_t edges[3];
|
|
|
|
clipport_t portals[3];
|
|
|
|
} clipbox_t;
|
|
|
|
|
|
|
|
/** Initialize the clipbox representing the faces that might hit the portal.
|
|
|
|
|
|
|
|
When a box is moving, at most three of its faces might hit the portal.
|
|
|
|
Those faces all face such that the dot product of their normal and the
|
|
|
|
box's velocity is positive (ie, n.v > 0). When the motion is in an axial
|
|
|
|
plane, only two faces might hit. For axial motion, only one face.
|
|
|
|
|
|
|
|
The faces are set up such that the first point of each winding is the
|
|
|
|
leading corner of the box, and the edges are set up such that testing
|
|
|
|
only the first three edges of each winding covers all nine edges (ie,
|
|
|
|
the forth edge of one face is the reverse of the first edge of the next
|
|
|
|
face).
|
|
|
|
|
|
|
|
The windings are clockwise when looking down the face's normal (ie, when
|
|
|
|
looking at the front of the face).
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_box (const trace_t *trace, clipbox_t *box, const vec3_t vel)
|
|
|
|
{
|
|
|
|
vec3_t p;
|
|
|
|
int u[3];
|
|
|
|
int i, j, k;
|
|
|
|
vec_t s[2] = {1, -1};
|
|
|
|
|
|
|
|
//FIXME rotated box
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
u[i] = (vel[i] >= 0 ? 1 : -1);
|
|
|
|
Vector3Scale (u, trace->extents, p);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
box->portals[i].planenum = i;
|
|
|
|
box->portals[i].next[0] = 0;
|
|
|
|
box->portals[i].next[0] = 0;
|
|
|
|
box->portals[i].leafs[0] = 0;
|
|
|
|
box->portals[i].leafs[0] = 0;
|
|
|
|
box->portals[i].winding = &box->points[i];
|
|
|
|
box->portals[i].edges = &box->edges[i];
|
|
|
|
|
|
|
|
VectorZero (box->planes[i].normal);
|
|
|
|
box->planes[i].normal[i] = u[i];
|
|
|
|
box->planes[i].dist = DotProduct (p, box->planes[i].normal);
|
|
|
|
box->planes[i].type = i;
|
|
|
|
|
|
|
|
box->points[i].numpoints = 4;
|
|
|
|
box->edges[i].numpoints = 4;
|
|
|
|
VectorCopy (u, box->points[i].points[0]);
|
|
|
|
VectorZero (box->edges[i].points[0]);
|
|
|
|
j = (i + (u[0]*u[1]*u[2] + 3) / 2) % 3;
|
|
|
|
box->edges[i].points[0][j] = -u[j];
|
|
|
|
for (j = 1; j < 4; j++) {
|
|
|
|
box->points[i].points[j][i] = box->points[i].points[j - 1][i];
|
|
|
|
box->edges[i].points[j][i] = box->edges[i].points[j - 1][i];
|
|
|
|
for (k = 0; k < 2; k++) {
|
|
|
|
int a, b;
|
|
|
|
a = (i + 1 + k) % 3;
|
|
|
|
b = (i + 2 - k) % 3;
|
|
|
|
box->points[i].points[j][a]
|
|
|
|
= s[k] * u[i] * box->points[i].points[j - 1][b];
|
|
|
|
box->edges[i].points[j][a]
|
|
|
|
= s[k] * u[i] * box->edges[i].points[j - 1][b];
|
|
|
|
}
|
|
|
|
Vector3Scale (box->points[i].points[j - 1], trace->extents,
|
|
|
|
box->points[i].points[j - 1]);
|
2011-11-28 01:09:24 +00:00
|
|
|
Vector3Scale (box->edges[i].points[j - 1], trace->extents,
|
|
|
|
box->edges[i].points[j - 1]);
|
|
|
|
VectorScale (box->edges[i].points[j - 1], 2,
|
|
|
|
box->edges[i].points[j - 1]);
|
2011-11-27 09:50:57 +00:00
|
|
|
}
|
|
|
|
Vector3Scale (box->points[i].points[3], trace->extents,
|
|
|
|
box->points[i].points[3]);
|
2011-11-28 01:09:24 +00:00
|
|
|
Vector3Scale (box->edges[i].points[3], trace->extents,
|
|
|
|
box->edges[i].points[3]);
|
|
|
|
VectorScale (box->edges[i].points[3], 2,
|
|
|
|
box->edges[i].points[3]);
|
2011-11-27 09:50:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static vec_t
|
|
|
|
edge_portal_dist (const plane_t *plane, const clipport_t *portal,
|
|
|
|
const vec3_t p1, const vec3_t p2, const vec3_t vel)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
winding_t *winding = portal->winding;
|
|
|
|
winding_t *edges = portal->edges;
|
|
|
|
|
|
|
|
// check for edge point hitting portal face
|
|
|
|
{
|
|
|
|
vec_t t1, t2, vn;
|
|
|
|
|
|
|
|
vn = DotProduct (vel, plane->normal);
|
|
|
|
t1 = PlaneDiff (p1, plane);
|
|
|
|
t2 = PlaneDiff (p2, plane);
|
|
|
|
// ensure p1 is the closest point to the plane
|
2011-11-28 00:24:13 +00:00
|
|
|
if ((0 < t2 && t2 < t1)
|
|
|
|
|| (0 > t2 && t2 > t1)) {
|
2011-11-27 09:50:57 +00:00
|
|
|
// p2 is closer to the plane, so swap the points and times
|
|
|
|
const vec_t *r = p2;
|
|
|
|
vec_t t = t2;
|
|
|
|
t2 = t1; t1 = t;
|
|
|
|
p2 = p1; p1 = r;
|
|
|
|
}
|
|
|
|
if (vn * t1 > 0) {
|
|
|
|
// the edge is travelling away from the portal's plane
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// if t1 * t2 < 0, the points straddle the portal's plane and the
|
|
|
|
// nearest point test can be skipped
|
|
|
|
if (vn && t1 * t2 > 0) { //FIXME epsilon
|
|
|
|
vec3_t x, c;
|
|
|
|
vec3_t imp;
|
|
|
|
|
2011-11-28 00:24:13 +00:00
|
|
|
t1 /= vn;
|
|
|
|
if (t1 <= -1) {
|
2011-11-27 09:50:57 +00:00
|
|
|
// the edge doesn't make it as far as the portal's plane
|
|
|
|
return 1;
|
|
|
|
}
|
2011-11-27 10:38:03 +00:00
|
|
|
VectorMultSub (p1, t1, vel, imp);
|
2011-11-27 09:50:57 +00:00
|
|
|
for (i = 0; i < winding->numpoints; i++) {
|
|
|
|
VectorSubtract (imp, winding->points[i], x);
|
|
|
|
CrossProduct (x, edges->points[i], c);
|
2011-11-27 10:38:03 +00:00
|
|
|
if (DotProduct (c, plane->normal) < 0)
|
2011-11-27 09:50:57 +00:00
|
|
|
break; // miss
|
|
|
|
}
|
|
|
|
if (i == winding->numpoints) {
|
2011-11-28 01:09:24 +00:00
|
|
|
// the closer end of the edge hit the portal, so -t1 is the
|
2011-11-27 09:50:57 +00:00
|
|
|
// fraction
|
2011-11-28 00:24:13 +00:00
|
|
|
return -t1;
|
2011-11-27 09:50:57 +00:00
|
|
|
}
|
|
|
|
// the closer end of the edge missed the portal, check the farther
|
|
|
|
// end, but only with this portal edge.
|
|
|
|
VectorMultSub (p2, t2 / vn, vel, imp);
|
|
|
|
VectorSubtract (imp, winding->points[i], x);
|
|
|
|
CrossProduct (x, edges->points[i], c);
|
2011-11-27 10:38:03 +00:00
|
|
|
if (DotProduct (c, plane->normal) < 0) {
|
2011-11-27 09:50:57 +00:00
|
|
|
// both impacts are on the outside of this portal edge, so the
|
|
|
|
// edge being tested misses the portal
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
// the two impact points are on both sides of a portal edge, so the
|
|
|
|
// edge being tested might hit a portal edge rather than the portal
|
|
|
|
// face
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
vec3_t e;
|
|
|
|
vec_t frac = 1.0;
|
|
|
|
plane_t ep;
|
|
|
|
|
|
|
|
// set up the plane through which the edge travels
|
|
|
|
VectorSubtract (p2, p1, e);
|
|
|
|
CrossProduct (e, vel, ep.normal);
|
|
|
|
ep.dist = DotProduct (p1, ep.normal);
|
2011-11-27 10:38:03 +00:00
|
|
|
ep.type = 3;
|
2011-11-27 09:50:57 +00:00
|
|
|
for (i = 0; i < winding->numpoints; i++) {
|
2011-11-28 00:02:16 +00:00
|
|
|
vec_t t, vn;
|
2011-11-27 09:50:57 +00:00
|
|
|
const vec_t *r = winding->points[i];
|
|
|
|
const vec_t *v = edges->points[i];
|
2011-11-28 00:02:16 +00:00
|
|
|
vec3_t x, y;
|
2011-11-27 09:50:57 +00:00
|
|
|
|
|
|
|
vn = DotProduct (v, ep.normal);
|
|
|
|
if (!vn) // FIXME epsilon
|
|
|
|
continue; // portal edge is parallel to the plane
|
2011-11-27 12:04:08 +00:00
|
|
|
t = PlaneDiff (r, &ep) / vn;
|
2011-11-28 00:24:13 +00:00
|
|
|
if (t < -1 || t > 0)
|
2011-11-27 09:50:57 +00:00
|
|
|
continue; // portal edge does not reach the plane
|
|
|
|
// impact point of portal edge with the plane
|
2011-11-27 12:04:08 +00:00
|
|
|
VectorMultSub (r, t, v, x);
|
2011-11-27 09:50:57 +00:00
|
|
|
// project the impact point back to the edge along the velocity
|
|
|
|
VectorSubtract (x, p1, y);
|
|
|
|
t = DotProduct (y, vel) / DotProduct (vel, vel);
|
|
|
|
VectorMultSub (x, t, vel, y);
|
2011-11-28 00:02:16 +00:00
|
|
|
VectorSubtract (y, p1, y);
|
|
|
|
t = DotProduct (y, y) / DotProduct (e, y);
|
|
|
|
if (t < 0 || t > 1)
|
|
|
|
continue; // the edge misses the portal edge
|
|
|
|
VectorMultAdd (p1, t, e, y);
|
|
|
|
VectorSubtract (x, y, y);
|
|
|
|
t = DotProduct (y, vel) / DotProduct (vel, vel);
|
2011-11-27 09:50:57 +00:00
|
|
|
if (t >= frac)
|
|
|
|
continue; // this is not the nearest edge pair
|
|
|
|
// the edges hit, and they are the closes edge pair so far
|
|
|
|
frac = t;
|
|
|
|
}
|
|
|
|
return frac;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static vec_t
|
|
|
|
box_portal_dist (const hull_t *hull, const clipport_t *portal,
|
|
|
|
const clipbox_t *box, const vec3_t start, const vec3_t vel)
|
|
|
|
{
|
|
|
|
vec3_t nvel;
|
|
|
|
plane_t *plane = hull->planes + portal->planenum;
|
|
|
|
int i, j;
|
|
|
|
vec_t frac, t;
|
|
|
|
vec3_t p1, p2;
|
|
|
|
|
2011-11-27 10:38:03 +00:00
|
|
|
frac = 1.0;
|
2011-11-27 09:50:57 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
// all faces on box have 4 points (and edges), but we need test only
|
|
|
|
// three on each face
|
|
|
|
for (j = 0; j < 3; j++) {
|
2011-11-27 12:04:08 +00:00
|
|
|
VectorAdd (box->points[i].points[j], start, p1);
|
|
|
|
VectorAdd (box->points[i].points[j + 1], start, p2);
|
2011-11-27 09:50:57 +00:00
|
|
|
t = edge_portal_dist (plane, portal, p1, p2, vel);
|
|
|
|
if (t < frac)
|
|
|
|
frac = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorNegate (vel, nvel);
|
|
|
|
for (i = 0; i < portal->winding->numpoints; i++) {
|
|
|
|
j = i + 1;
|
|
|
|
if (j >= portal->winding->numpoints)
|
|
|
|
j -= portal->winding->numpoints;
|
|
|
|
VectorSubtract (portal->winding->points[i], start, p1);
|
|
|
|
VectorSubtract (portal->winding->points[j], start, p2);
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
const clipport_t *p = &box->portals[j];
|
|
|
|
t = edge_portal_dist (box->planes + p->planenum, p, p1, p2, nvel);
|
|
|
|
if (t < frac)
|
|
|
|
frac = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return frac;
|
|
|
|
}
|
|
|
|
|
2004-11-02 08:40:00 +00:00
|
|
|
static inline void
|
2011-11-27 09:50:57 +00:00
|
|
|
calc_impact (hull_t *hull, trace_t *trace,
|
|
|
|
const vec3_t start, const vec3_t end,
|
|
|
|
clipleaf_t *leaf, plane_t *plane)
|
2004-11-02 08:40:00 +00:00
|
|
|
{
|
2011-11-12 08:21:37 +00:00
|
|
|
vec_t t1, t2, frac, offset;
|
2006-12-24 03:01:15 +00:00
|
|
|
vec3_t dist;
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2006-12-24 03:01:15 +00:00
|
|
|
t1 = PlaneDiff (start, plane);
|
|
|
|
t2 = PlaneDiff (end, plane);
|
2011-11-12 08:21:37 +00:00
|
|
|
offset = calc_offset (trace, plane);
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2006-12-24 03:01:15 +00:00
|
|
|
if (t1 < 0) {
|
2011-11-12 08:21:37 +00:00
|
|
|
frac = (t1 + offset + DIST_EPSILON) / (t1 - t2);
|
2004-11-02 08:40:00 +00:00
|
|
|
// invert plane paramterers
|
|
|
|
} else {
|
2011-11-12 08:21:37 +00:00
|
|
|
frac = (t1 - offset - DIST_EPSILON) / (t1 - t2);
|
2004-11-02 08:40:00 +00:00
|
|
|
}
|
|
|
|
frac = bound (0, frac, 1);
|
2011-11-27 09:50:57 +00:00
|
|
|
|
|
|
|
if (leaf && trace->type != tr_point) {
|
|
|
|
int i;
|
|
|
|
int side;
|
|
|
|
int planenum;
|
|
|
|
clipport_t *portal;
|
|
|
|
vec3_t impact;
|
|
|
|
clipbox_t box;
|
|
|
|
|
|
|
|
planenum = plane - hull->planes;
|
|
|
|
|
|
|
|
VectorSubtract (end, start, dist);
|
|
|
|
VectorMultAdd (start, frac, dist, impact);
|
|
|
|
if (DotProduct (dist, plane->normal) > 0)
|
|
|
|
VectorMultAdd (impact, offset, plane->normal, impact);
|
|
|
|
else
|
|
|
|
VectorMultSub (impact, offset, plane->normal, impact);
|
|
|
|
|
|
|
|
init_box (trace, &box, dist);
|
|
|
|
|
|
|
|
for (portal = leaf->portals; portal; portal = portal->next[side]) {
|
|
|
|
side = portal->leafs[1] == leaf;
|
|
|
|
if (portal->planenum != planenum)
|
|
|
|
continue;
|
|
|
|
for (i = 0; i < portal->winding->numpoints; i++) {
|
|
|
|
vec3_t r, s;
|
|
|
|
VectorSubtract (impact, portal->winding->points[i], r);
|
|
|
|
CrossProduct (r, portal->edges->points[i], s);
|
2011-11-27 10:38:03 +00:00
|
|
|
if (DotProduct (s, plane->normal) > 0)
|
2011-11-27 09:50:57 +00:00
|
|
|
continue; // "hit"
|
|
|
|
break; // "miss";
|
|
|
|
}
|
|
|
|
if (i == portal->winding->numpoints)
|
|
|
|
goto finish_impact; // impact with the face of the polygon
|
|
|
|
}
|
2011-11-27 12:04:08 +00:00
|
|
|
frac = 1.0;
|
2011-11-27 09:50:57 +00:00
|
|
|
for (portal = leaf->portals; portal; portal = portal->next[side]) {
|
|
|
|
vec_t t;
|
|
|
|
|
|
|
|
side = portal->leafs[1] == leaf;
|
|
|
|
if (portal->planenum != planenum)
|
|
|
|
continue;
|
|
|
|
t = box_portal_dist (hull, portal, &box, start, dist);
|
|
|
|
if (t < frac)
|
|
|
|
frac = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
finish_impact:
|
2011-11-12 23:48:44 +00:00
|
|
|
if (frac < trace->fraction) {
|
|
|
|
trace->fraction = frac;
|
|
|
|
VectorSubtract (end, start, dist);
|
|
|
|
VectorMultAdd (start, frac, dist, trace->endpos);
|
|
|
|
if (t1 < 0) {
|
|
|
|
// invert plane paramterers
|
|
|
|
VectorNegate (plane->normal, trace->plane.normal);
|
|
|
|
trace->plane.dist = -plane->dist;
|
|
|
|
} else {
|
|
|
|
VectorCopy (plane->normal, trace->plane.normal);
|
|
|
|
trace->plane.dist = plane->dist;
|
|
|
|
}
|
|
|
|
}
|
2004-11-02 08:40:00 +00:00
|
|
|
}
|
2009-12-19 04:45:01 +00:00
|
|
|
|
2007-09-17 11:24:42 +00:00
|
|
|
VISIBLE void
|
2006-12-24 06:34:12 +00:00
|
|
|
MOD_TraceLine (hull_t *hull, int num,
|
|
|
|
const vec3_t start_point, const vec3_t end_point,
|
2004-11-02 08:40:00 +00:00
|
|
|
trace_t *trace)
|
|
|
|
{
|
2011-11-12 11:42:44 +00:00
|
|
|
vec_t start_dist, end_dist, frac[2], offset;
|
2011-11-20 00:33:57 +00:00
|
|
|
vec3_t start, end, dist, vel;
|
2010-12-06 06:30:56 +00:00
|
|
|
int side;
|
2011-09-27 03:33:50 +00:00
|
|
|
qboolean seen_empty, seen_solid;
|
2004-11-02 08:40:00 +00:00
|
|
|
tracestack_t *tstack;
|
|
|
|
tracestack_t tracestack[256];
|
2010-11-29 00:36:21 +00:00
|
|
|
mclipnode_t *node;
|
2011-11-14 02:18:22 +00:00
|
|
|
plane_t *plane, *split_plane;
|
2011-11-20 00:33:57 +00:00
|
|
|
clipleaf_t *leaf;
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2006-12-24 06:34:12 +00:00
|
|
|
VectorCopy (start_point, start);
|
|
|
|
VectorCopy (end_point, end);
|
2011-11-20 00:33:57 +00:00
|
|
|
VectorSubtract (end, start, vel);
|
|
|
|
VectorNormalize (vel);
|
2004-11-02 08:40:00 +00:00
|
|
|
|
|
|
|
tstack = tracestack;
|
2011-09-27 03:33:50 +00:00
|
|
|
seen_empty = 0;
|
|
|
|
seen_solid = 0;
|
2004-11-02 08:40:00 +00:00
|
|
|
split_plane = 0;
|
2011-11-20 00:33:57 +00:00
|
|
|
leaf = 0;
|
|
|
|
plane = 0;
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2011-09-27 08:14:42 +00:00
|
|
|
trace->allsolid = true;
|
2010-12-06 06:30:56 +00:00
|
|
|
trace->startsolid = false;
|
|
|
|
trace->inopen = false;
|
|
|
|
trace->inwater = false;
|
|
|
|
trace->fraction = 1.0;
|
|
|
|
|
2004-11-02 08:40:00 +00:00
|
|
|
while (1) {
|
|
|
|
while (num < 0) {
|
2011-11-20 00:33:57 +00:00
|
|
|
// it's not possible to not be in the leaf when doing a point trace
|
|
|
|
// if leaf is null, assume we're in the leaf
|
|
|
|
// if plane is null, the trace did not cross the last node plane
|
2011-11-20 05:56:07 +00:00
|
|
|
int in_leaf = 1;
|
|
|
|
if (trace->type != tr_point && leaf && split_plane)
|
|
|
|
in_leaf = check_in_leaf (hull, trace, leaf, split_plane,
|
|
|
|
vel, start);
|
2011-11-20 00:33:57 +00:00
|
|
|
if (in_leaf && num == CONTENTS_SOLID) {
|
2011-09-27 03:33:50 +00:00
|
|
|
if (!seen_empty && !seen_solid) {
|
2010-12-06 06:30:56 +00:00
|
|
|
// this is the first leaf visited, thus the start leaf
|
2011-09-27 03:33:50 +00:00
|
|
|
trace->startsolid = seen_solid = true;
|
|
|
|
} else if (!seen_empty && seen_solid) {
|
2011-09-27 08:14:42 +00:00
|
|
|
// If crossing from one solid leaf to another, treat the
|
|
|
|
// whole trace as solid (this is what id does).
|
|
|
|
// However, since allsolid is initialized to true, no need
|
|
|
|
// to do anything.
|
2010-12-06 06:30:56 +00:00
|
|
|
return;
|
2011-09-27 03:33:50 +00:00
|
|
|
} else {
|
2010-12-06 06:30:56 +00:00
|
|
|
// crossing from an empty leaf to a solid leaf: the trace
|
|
|
|
// has collided.
|
2011-11-27 09:50:57 +00:00
|
|
|
calc_impact (hull, trace, start_point, end_point, leaf,
|
|
|
|
split_plane);
|
2011-11-12 23:48:44 +00:00
|
|
|
if (trace->type == tr_point)
|
|
|
|
return;
|
2010-12-06 06:30:56 +00:00
|
|
|
}
|
2011-11-20 00:33:57 +00:00
|
|
|
} else if (in_leaf) {
|
2011-09-27 03:33:50 +00:00
|
|
|
seen_empty = true;
|
2011-09-27 08:14:42 +00:00
|
|
|
trace->allsolid = false;
|
2007-05-14 11:16:41 +00:00
|
|
|
if (num == CONTENTS_EMPTY)
|
|
|
|
trace->inopen = true;
|
|
|
|
else
|
|
|
|
trace->inwater = true;
|
2004-11-02 08:40:00 +00:00
|
|
|
}
|
|
|
|
|
2006-12-24 08:01:39 +00:00
|
|
|
// pop up the stack for a back side
|
2011-11-13 01:13:10 +00:00
|
|
|
do {
|
|
|
|
if (tstack-- == tracestack) {
|
|
|
|
// we've finished.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (tstack->start_frac > trace->fraction);
|
2004-11-02 08:40:00 +00:00
|
|
|
|
|
|
|
// set the hit point for this plane
|
2011-11-12 11:42:44 +00:00
|
|
|
VectorCopy (end, tstack->start);
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2006-12-24 08:01:39 +00:00
|
|
|
// go down the back side
|
2006-12-24 06:34:12 +00:00
|
|
|
VectorCopy (tstack->end, end);
|
2004-11-02 08:40:00 +00:00
|
|
|
side = tstack->side;
|
|
|
|
split_plane = tstack->plane;
|
|
|
|
|
2011-11-20 00:33:57 +00:00
|
|
|
leaf = hull->nodeleafs[tstack->num].leafs[side ^ 1];
|
2004-11-02 08:40:00 +00:00
|
|
|
num = hull->clipnodes[tstack->num].children[side ^ 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
node = hull->clipnodes + num;
|
|
|
|
plane = hull->planes + node->planenum;
|
|
|
|
|
2006-12-24 06:34:12 +00:00
|
|
|
start_dist = PlaneDiff (start, plane);
|
|
|
|
end_dist = PlaneDiff (end, plane);
|
2011-10-02 12:06:56 +00:00
|
|
|
offset = calc_offset (trace, plane);
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2011-10-02 12:06:56 +00:00
|
|
|
if (start_dist >= offset && end_dist >= offset) {
|
2006-12-24 08:01:39 +00:00
|
|
|
// entirely in front of the plane
|
2011-11-20 00:33:57 +00:00
|
|
|
plane = 0;
|
|
|
|
leaf = hull->nodeleafs[num].leafs[0];
|
2004-11-02 08:40:00 +00:00
|
|
|
num = node->children[0];
|
|
|
|
continue;
|
|
|
|
}
|
2011-11-28 08:12:39 +00:00
|
|
|
//non-zero offset lets the object touch the plane but still be
|
|
|
|
//behind the plane. however, point traces are assumed to be on the
|
|
|
|
//front side of the plane if touching the plane
|
|
|
|
if ((offset && start_dist <= -offset && end_dist <= -offset)
|
|
|
|
|| (!offset && start_dist < -offset && end_dist < -offset)) {
|
2006-12-24 08:01:39 +00:00
|
|
|
// entirely behind the plane
|
2011-11-20 00:33:57 +00:00
|
|
|
plane = 0;
|
|
|
|
leaf = hull->nodeleafs[num].leafs[1];
|
2004-11-02 08:40:00 +00:00
|
|
|
num = node->children[1];
|
|
|
|
continue;
|
|
|
|
}
|
2010-12-05 05:52:20 +00:00
|
|
|
|
2010-12-06 06:30:56 +00:00
|
|
|
// cross the plane
|
|
|
|
|
2011-11-12 23:48:44 +00:00
|
|
|
if (start_dist == end_dist) {
|
|
|
|
// avoid division by zero (non-point clip only)
|
2011-11-20 00:33:57 +00:00
|
|
|
// since neither side is forward and we need to check both sides
|
|
|
|
// anyway, it doesn't matter which side we start with, so long as
|
|
|
|
// the fractions are correct.
|
2011-11-12 12:30:45 +00:00
|
|
|
side = 0;
|
|
|
|
frac[0] = 1;
|
|
|
|
frac[1] = 0;
|
|
|
|
} else {
|
2011-11-20 00:33:57 +00:00
|
|
|
// choose the side such that we are always moving forward through
|
|
|
|
// the map
|
|
|
|
side = start_dist < end_dist;
|
2011-11-12 23:48:44 +00:00
|
|
|
// if either start or end have the box straddling the plane, then
|
|
|
|
// frac will be appropriately clipped to 0 and 1, otherwise, frac
|
|
|
|
// will be inside that range
|
2011-11-12 12:30:45 +00:00
|
|
|
frac[0] = (start_dist + offset) / (start_dist - end_dist);
|
|
|
|
frac[1] = (start_dist - offset) / (start_dist - end_dist);
|
|
|
|
frac[0] = bound (0, frac[0], 1);
|
|
|
|
frac[1] = bound (0, frac[1], 1);
|
|
|
|
}
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2011-11-15 04:26:13 +00:00
|
|
|
VectorSubtract (end, start, dist);
|
|
|
|
|
2004-11-02 08:40:00 +00:00
|
|
|
tstack->num = num;
|
|
|
|
tstack->side = side;
|
|
|
|
tstack->plane = plane;
|
2006-12-24 06:34:12 +00:00
|
|
|
VectorCopy (end, tstack->end);
|
2011-11-15 04:26:13 +00:00
|
|
|
VectorMultAdd (start, frac[side ^ 1], dist, tstack->start);
|
|
|
|
tstack->start_frac = frac[side ^ 1];
|
2004-11-02 08:40:00 +00:00
|
|
|
tstack++;
|
|
|
|
|
2011-11-12 11:42:44 +00:00
|
|
|
VectorMultAdd (start, frac[side], dist, end);
|
2004-11-02 08:40:00 +00:00
|
|
|
|
2011-11-20 00:33:57 +00:00
|
|
|
leaf = hull->nodeleafs[num].leafs[side];
|
2004-11-02 08:40:00 +00:00
|
|
|
num = node->children[side];
|
|
|
|
}
|
|
|
|
}
|