#include "quakedef.h"
#include "polygon.h"
-#define COLLISION_SNAPSCALE (8.0f)
+#define COLLISION_SNAPSCALE (32.0f)
#define COLLISION_SNAP (1.0f / COLLISION_SNAPSCALE)
+#define COLLISION_SNAP2 (2.0f / COLLISION_SNAPSCALE)
+#define COLLISION_PLANE_DIST_EPSILON (2.0f / COLLISION_SNAPSCALE)
cvar_t collision_impactnudge = {0, "collision_impactnudge", "0.03125", "how much to back off from the impact"};
cvar_t collision_startnudge = {0, "collision_startnudge", "0", "how much to bias collision trace start"};
for (k = 0;k < brush->numplanes;k++)
{
d = DotProduct(brush->points[j].v, brush->planes[k].normal) - brush->planes[k].dist;
- if (d > (1.0f / 8.0f))
+ if (d > COLLISION_PLANE_DIST_EPSILON)
{
Con_Printf("Collision_ValidateBrush: point #%i (%f %f %f) infront of plane #%i (%f %f %f %f)\n", j, brush->points[j].v[0], brush->points[j].v[1], brush->points[j].v[2], k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist);
printbrush = true;
}
- if (fabs(d) > 0.125f)
+ if (fabs(d) > COLLISION_PLANE_DIST_EPSILON)
pointsoffplanes++;
else
pointonplanes++;
float nearestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
{
float dist, bestdist;
+ if (!numpoints)
+ return 0;
bestdist = DotProduct(points->v, normal);
points++;
while(--numpoints)
float furthestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
{
float dist, bestdist;
+ if (!numpoints)
+ return 0;
bestdist = DotProduct(points->v, normal);
points++;
while(--numpoints)
}
-colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const colplanef_t *originalplanes)
+colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const colplanef_t *originalplanes, int supercontents)
{
// TODO: planesbuf could be replaced by a remapping table
- int j, k, m, w;
+ int j, k, m, w, xyzflags;
int numpointsbuf = 0, maxpointsbuf = 256, numplanesbuf = 0, maxplanesbuf = 256, numelementsbuf = 0, maxelementsbuf = 256;
+ double maxdist;
colbrushf_t *brush;
colpointf_t pointsbuf[256];
colplanef_t planesbuf[256];
memset(polypointbuf, 0, sizeof(polypointbuf));
memset(p, 0, sizeof(p));
#endif
+ // figure out how large a bounding box we need to properly compute this brush
+ maxdist = 0;
+ for (j = 0;j < numoriginalplanes;j++)
+ maxdist = max(maxdist, fabs(originalplanes[j].dist));
+ // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
+ maxdist = floor(maxdist * (4.0 / 1024.0) + 2) * 1024.0;
// construct a collision brush (points, planes, and renderable mesh) from
// a set of planes, this also optimizes out any unnecessary planes (ones
// whose polygon is clipped away by the other planes)
// check if there are too many and skip the brush
if (numplanesbuf >= maxplanesbuf)
{
- Con_Print("Collision_NewBrushFromPlanes: failed to build collision brush: too many planes for buffer\n");
+ Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many planes for buffer\n");
return NULL;
}
+ // add the new plane
+ VectorCopy(originalplanes[j].normal, planesbuf[numplanesbuf].normal);
+ planesbuf[numplanesbuf].dist = originalplanes[j].dist;
+ planesbuf[numplanesbuf].q3surfaceflags = originalplanes[j].q3surfaceflags;
+ planesbuf[numplanesbuf].texture = originalplanes[j].texture;
+ numplanesbuf++;
+
// create a large polygon from the plane
w = 0;
- PolygonD_QuadForPlane(p[w], originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist, 1024.0*1024.0*1024.0);
+ PolygonD_QuadForPlane(p[w], originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist, maxdist);
pnumpoints = 4;
// clip it by all other planes
- for (k = 0;k < numoriginalplanes && pnumpoints && pnumpoints <= pmaxpoints;k++)
+ for (k = 0;k < numoriginalplanes && pnumpoints >= 3 && pnumpoints <= pmaxpoints;k++)
{
+ // skip the plane this polygon
+ // (nothing happens if it is processed, this is just an optimization)
if (k != j)
{
// we want to keep the inside of the brush plane so we flip
// the cutting plane
- PolygonD_Divide(pnumpoints, p[w], -originalplanes[k].normal[0], -originalplanes[k].normal[1], -originalplanes[k].normal[2], -originalplanes[k].dist, 1.0/32.0, pmaxpoints, p[!w], &pnumpoints, 0, NULL, NULL, NULL);
+ PolygonD_Divide(pnumpoints, p[w], -originalplanes[k].normal[0], -originalplanes[k].normal[1], -originalplanes[k].normal[2], -originalplanes[k].dist, COLLISION_PLANE_DIST_EPSILON, pmaxpoints, p[!w], &pnumpoints, 0, NULL, NULL, NULL);
w = !w;
}
}
+
// if nothing is left, skip it
if (pnumpoints < 3)
{
- //Con_Printf("Collision_NewBrushFromPlanes: warning: polygon for plane %f %f %f %f clipped away\n", originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist);
+ //Con_DPrintf("Collision_NewBrushFromPlanes: warning: polygon for plane %f %f %f %f clipped away\n", originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist);
continue;
}
int l, m;
m = 0;
for (l = 0;l < numoriginalplanes;l++)
- if (fabs(DotProduct(&p[w][k*3], originalplanes[l].normal) - originalplanes[l].dist) < 1.0/8.0)
+ if (fabs(DotProduct(&p[w][k*3], originalplanes[l].normal) - originalplanes[l].dist) < COLLISION_PLANE_DIST_EPSILON)
m++;
if (m < 3)
break;
}
if (k < pnumpoints)
{
- Con_Printf("Collision_NewBrushFromPlanes: warning: polygon point does not lie on at least 3 planes\n");
+ Con_DPrintf("Collision_NewBrushFromPlanes: warning: polygon point does not lie on at least 3 planes\n");
//return NULL;
}
// check if there are too many polygon vertices for buffer
if (pnumpoints > pmaxpoints)
{
- Con_Print("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n");
+ Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n");
return NULL;
}
// check if there are too many triangle elements for buffer
if (numelementsbuf + (pnumpoints - 2) * 3 > maxelementsbuf)
{
- Con_Print("Collision_NewBrushFromPlanes: failed to build collision brush: too many triangle elements for buffer\n");
+ Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many triangle elements for buffer\n");
return NULL;
}
for (k = 0;k < pnumpoints;k++)
{
+ float v[3];
+ // downgrade to float precision before comparing
+ VectorCopy(&p[w][k*3], v);
+
// check if there is already a matching point (no duplicates)
for (m = 0;m < numpointsbuf;m++)
- if (VectorDistance2(&p[w][k*3], pointsbuf[m].v) < COLLISION_SNAP)
+ if (VectorDistance2(v, pointsbuf[m].v) < COLLISION_SNAP2)
break;
// if there is no match, add a new one
// check if there are too many and skip the brush
if (numpointsbuf >= maxpointsbuf)
{
- Con_Print("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n");
+ Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n");
return NULL;
}
// add the new one
elementsbuf[numelementsbuf++] = polypointbuf[k + 1];
elementsbuf[numelementsbuf++] = polypointbuf[k + 2];
}
+ }
- // add the new plane
- VectorCopy(originalplanes[j].normal, planesbuf[numplanesbuf].normal);
- planesbuf[numplanesbuf].dist = originalplanes[j].dist;
- planesbuf[numplanesbuf].supercontents = originalplanes[j].supercontents;
- planesbuf[numplanesbuf].q3surfaceflags = originalplanes[j].q3surfaceflags;
- planesbuf[numplanesbuf].texture = originalplanes[j].texture;
- numplanesbuf++;
+ // if nothing is left, there's nothing to allocate
+ if (numplanesbuf < 4)
+ {
+ Con_DPrintf("Collision_NewBrushFromPlanes: failed to build collision brush: %i triangles, %i planes (input was %i planes), %i vertices\n", numelementsbuf / 3, numplanesbuf, numoriginalplanes, numpointsbuf);
+ return NULL;
}
+ // if no triangles or points could be constructed, then this routine failed but the brush is not discarded
+ if (numelementsbuf < 12 || numpointsbuf < 4)
+ Con_DPrintf("Collision_NewBrushFromPlanes: unable to rebuild triangles/points for collision brush: %i triangles, %i planes (input was %i planes), %i vertices\n", numelementsbuf / 3, numplanesbuf, numoriginalplanes, numpointsbuf);
+
// validate plane distances
for (j = 0;j < numplanesbuf;j++)
{
float d = furthestplanedist_float(planesbuf[j].normal, pointsbuf, numpointsbuf);
- if (fabs(planesbuf[j].dist - d) > (1.0f/32.0f))
- Con_Printf("plane %f %f %f %f mismatches dist %f\n", planesbuf[j].normal[0], planesbuf[j].normal[1], planesbuf[j].normal[2], planesbuf[j].dist, d);
- }
-
- // if nothing is left, there's nothing to allocate
- if (numelementsbuf < 12 || numplanesbuf < 4 || numpointsbuf < 4)
- {
- Con_Printf("Collision_NewBrushFromPlanes: failed to build collision brush: %i triangles, %i planes (input was %i planes), %i vertices\n", numelementsbuf / 3, numplanesbuf, numoriginalplanes, numpointsbuf);
- return NULL;
+ if (fabs(planesbuf[j].dist - d) > COLLISION_PLANE_DIST_EPSILON)
+ Con_DPrintf("plane %f %f %f %f mismatches dist %f\n", planesbuf[j].normal[0], planesbuf[j].normal[1], planesbuf[j].normal[2], planesbuf[j].dist, d);
}
// allocate the brush and copy to it
brush = (colbrushf_t *)Mem_Alloc(mempool, sizeof(colbrushf_t) + sizeof(colpointf_t) * numpointsbuf + sizeof(colplanef_t) * numplanesbuf + sizeof(int) * numelementsbuf);
+ brush->supercontents = supercontents;
brush->numplanes = numplanesbuf;
brush->numpoints = numpointsbuf;
brush->numtriangles = numelementsbuf / 3;
brush->planes[j].normal[1] = planesbuf[j].normal[1];
brush->planes[j].normal[2] = planesbuf[j].normal[2];
brush->planes[j].dist = planesbuf[j].dist;
- brush->planes[j].supercontents = planesbuf[j].supercontents;
brush->planes[j].q3surfaceflags = planesbuf[j].q3surfaceflags;
brush->planes[j].texture = planesbuf[j].texture;
- brush->supercontents |= brush->planes[j].supercontents;
}
for (j = 0;j < brush->numtriangles * 3;j++)
brush->elements[j] = elementsbuf[j];
- VectorCopy(brush->points[0].v, brush->mins);
- VectorCopy(brush->points[0].v, brush->maxs);
- for (j = 1;j < brush->numpoints;j++)
+
+ xyzflags = 0;
+ VectorClear(brush->mins);
+ VectorClear(brush->maxs);
+ for (j = 0;j < min(6, numoriginalplanes);j++)
{
- brush->mins[0] = min(brush->mins[0], brush->points[j].v[0]);
- brush->mins[1] = min(brush->mins[1], brush->points[j].v[1]);
- brush->mins[2] = min(brush->mins[2], brush->points[j].v[2]);
- brush->maxs[0] = max(brush->maxs[0], brush->points[j].v[0]);
- brush->maxs[1] = max(brush->maxs[1], brush->points[j].v[1]);
- brush->maxs[2] = max(brush->maxs[2], brush->points[j].v[2]);
+ if (originalplanes[j].normal[0] == 1) {xyzflags |= 1;brush->maxs[0] = originalplanes[j].dist;}
+ else if (originalplanes[j].normal[0] == -1) {xyzflags |= 2;brush->mins[0] = -originalplanes[j].dist;}
+ else if (originalplanes[j].normal[1] == 1) {xyzflags |= 4;brush->maxs[1] = originalplanes[j].dist;}
+ else if (originalplanes[j].normal[1] == -1) {xyzflags |= 8;brush->mins[1] = -originalplanes[j].dist;}
+ else if (originalplanes[j].normal[2] == 1) {xyzflags |= 16;brush->maxs[2] = originalplanes[j].dist;}
+ else if (originalplanes[j].normal[2] == -1) {xyzflags |= 32;brush->mins[2] = -originalplanes[j].dist;}
+ }
+ // if not all xyzflags were set, then this is not a brush from q3map/q3map2, and needs reconstruction of the bounding box
+ // (this case works for any brush with valid points, but sometimes brushes are not reconstructed properly and hence the points are not valid, so this is reserved as a fallback case)
+ if (xyzflags != 63)
+ {
+ VectorCopy(brush->points[0].v, brush->mins);
+ VectorCopy(brush->points[0].v, brush->maxs);
+ for (j = 1;j < brush->numpoints;j++)
+ {
+ brush->mins[0] = min(brush->mins[0], brush->points[j].v[0]);
+ brush->mins[1] = min(brush->mins[1], brush->points[j].v[1]);
+ brush->mins[2] = min(brush->mins[2], brush->points[j].v[2]);
+ brush->maxs[0] = max(brush->maxs[0], brush->points[j].v[0]);
+ brush->maxs[1] = max(brush->maxs[1], brush->points[j].v[1]);
+ brush->maxs[2] = max(brush->maxs[2], brush->points[j].v[2]);
+ }
}
brush->mins[0] -= 1;
brush->mins[1] -= 1;
{
int j;
for (j = 0, p = brush->points;j < brush->numpoints;j++, p++)
- if (DotProduct(p->v, brush->planes[i].normal) > brush->planes[i].dist + (1.0 / 32.0))
+ if (DotProduct(p->v, brush->planes[i].normal) > brush->planes[i].dist + COLLISION_PLANE_DIST_EPSILON)
Con_Printf("Error in brush plane generation, plane %i\n", i);
}
}
// NOTE: start and end of each brush pair must have same numplanes/numpoints
void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end)
{
- int nplane, nplane2, fstartsolid = true, fendsolid = true, brushsolid, hitsupercontents = 0, hitq3surfaceflags = 0;
+ int nplane, nplane2, hitq3surfaceflags = 0;
float enterfrac = -1, leavefrac = 1, d1, d2, f, imove, newimpactnormal[3], enterfrac2 = -1;
const colplanef_t *startplane, *endplane;
texture_t *hittexture = NULL;
return;
}
f = furthestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints);
- if (fabs(f - startplane->dist) > 0.125f)
+ if (fabs(f - startplane->dist) > COLLISION_PLANE_DIST_EPSILON)
Con_Printf("startplane->dist %f != calculated %f (thisbrush_start)\n", startplane->dist, f);
}
d1 = nearestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints) - furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints) - collision_startnudge.value;
return;
}
f = furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints);
- if (fabs(f - startplane->dist) > 0.125f)
+ if (fabs(f - startplane->dist) > COLLISION_PLANE_DIST_EPSILON)
Con_Printf("startplane->dist %f != calculated %f (thatbrush_start)\n", startplane->dist, f);
}
d1 = nearestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints) - startplane->dist - collision_startnudge.value;
}
//Con_Printf("%c%i: d1 = %f, d2 = %f, d1 / (d1 - d2) = %f\n", nplane2 != nplane ? 'b' : 'a', nplane2, d1, d2, d1 / (d1 - d2));
- if(d1 > d2)
+ if (d1 > d2)
{
// moving into brush
- if(d2 > 0)
+ if (d2 > 0)
return;
- if(d1 > 0)
+ if (d1 > 0)
{
// enter
- fstartsolid = false;
imove = 1 / (d1 - d2);
f = (d1 - collision_enternudge.value) * imove;
+ // check if this will reduce the collision time range
if (enterfrac < f)
{
+ // reduced collision time range
enterfrac = f;
+ // if the collision time range is now empty, no collision
+ if (enterfrac > leavefrac)
+ return;
+ // if the collision would be further away than the trace's
+ // existing collision data, we don't care about this
+ // collision
+ if (enterfrac > trace->realfraction)
+ return;
+ // calculate the nudged fraction and impact normal we'll
+ // need if we accept this collision later
enterfrac2 = f - collision_impactnudge.value * imove;
VectorLerp(startplane->normal, enterfrac, endplane->normal, newimpactnormal);
- hitsupercontents = startplane->supercontents;
hitq3surfaceflags = startplane->q3surfaceflags;
hittexture = startplane->texture;
}
else
{
// moving out of brush
- if(d1 > 0)
+ if (d1 > 0)
return;
- if(d2 > 0)
+ if (d2 > 0)
{
// leave
- fendsolid = false;
f = (d1 + collision_leavenudge.value) / (d1 - d2);
+ // check if this will reduce the collision time range
if (leavefrac > f)
+ {
+ // reduced collision time range
leavefrac = f;
+ // if the collision time range is now empty, no collision
+ if (enterfrac > leavefrac)
+ return;
+ }
}
}
}
- brushsolid = trace->hitsupercontentsmask & thatbrush_start->supercontents;
- if (fstartsolid)
+ // at this point we know the trace overlaps the brush because it was not
+ // rejected at any point in the loop above
+
+ // see if this brush can block the trace or not according to contents
+ if (trace->hitsupercontentsmask & thatbrush_start->supercontents)
{
- trace->startsupercontents |= thatbrush_start->supercontents;
- if (brushsolid)
+ if (enterfrac == -1)
{
+ trace->startsupercontents |= thatbrush_start->supercontents;
trace->startsolid = true;
- if (fendsolid)
+ if (leavefrac < 1)
trace->allsolid = true;
}
+ // store out the impact information
+ trace->hitsupercontents = thatbrush_start->supercontents;
+ trace->hitq3surfaceflags = hitq3surfaceflags;
+ trace->hittexture = hittexture;
+ trace->realfraction = bound(0, enterfrac, 1);
+ trace->fraction = bound(0, enterfrac2, 1);
+ VectorCopy(newimpactnormal, trace->plane.normal);
}
-
- // LordHavoc: we need an epsilon nudge here because for a point trace the
- // penetrating line segment is normally zero length if this brush was
- // generated from a polygon (infinitely thin), and could even be slightly
- // positive or negative due to rounding errors in that case.
- if (brushsolid && enterfrac > -1 && enterfrac < trace->realfraction && enterfrac - (1.0f / 1024.0f) <= leavefrac)
+ else
{
-#if 0
- // broken
- if (thatbrush_start->ispolygon)
- {
- d1 = nearestplanedist_float(thatbrush_start->planes[0].normal, thisbrush_start->points, thisbrush_start->numpoints) - thatbrush_start->planes[0].dist - collision_startnudge.value;
- d2 = nearestplanedist_float(thatbrush_end->planes[0].normal, thisbrush_end->points, thisbrush_end->numpoints) - thatbrush_end->planes[0].dist - collision_endnudge.value;
- move = d1 - d2;
- if (move <= 0 || d2 > collision_enternudge.value || d1 < 0)
- return;
- // enter
- imove = 1 / move;
- enterfrac = (d1 - collision_enternudge.value) * imove;
- if (enterfrac < trace->realfraction)
- {
- enterfrac2 = enterfrac - collision_impactnudge.value * imove;
- trace->hitsupercontents = thatbrush_start->planes[0].supercontents;
- trace->hitq3surfaceflags = thatbrush_start->planes[0].q3surfaceflags;
- trace->hittexture = thatbrush_start->planes[0].texture;
- trace->realfraction = bound(0, enterfrac, 1);
- trace->fraction = bound(0, enterfrac2, 1);
- VectorLerp(thatbrush_start->planes[0].normal, enterfrac, thatbrush_end->planes[0].normal, trace->plane.normal);
- }
- }
- else
-#endif
- {
- trace->hitsupercontents = hitsupercontents;
- trace->hitq3surfaceflags = hitq3surfaceflags;
- trace->hittexture = hittexture;
- trace->realfraction = bound(0, enterfrac, 1);
- trace->fraction = bound(0, enterfrac2, 1);
- VectorCopy(newimpactnormal, trace->plane.normal);
- }
+ // this brush can not block the trace, but it can update start contents
+ if (enterfrac == -1)
+ trace->startsupercontents |= thatbrush_start->supercontents;
}
}
// NOTE: start and end brush pair must have same numplanes/numpoints
void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end)
{
- int nplane, fstartsolid = true, fendsolid = true, brushsolid, hitsupercontents = 0, hitq3surfaceflags = 0;
+ int nplane, hitq3surfaceflags = 0;
float enterfrac = -1, leavefrac = 1, d1, d2, f, imove, newimpactnormal[3], enterfrac2 = -1;
const colplanef_t *startplane, *endplane;
texture_t *hittexture = NULL;
if (thatbrush_start->numpoints)
{
f = furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints);
- if (fabs(f - startplane->dist) > 0.125f)
+ if (fabs(f - startplane->dist) > COLLISION_PLANE_DIST_EPSILON)
Con_Printf("startplane->dist %f != calculated %f\n", startplane->dist, f);
}
}
if (d1 > 0)
{
// enter
- fstartsolid = false;
imove = 1 / (d1 - d2);
f = (d1 - collision_enternudge.value) * imove;
+ // check if this will reduce the collision time range
if (enterfrac < f)
{
+ // reduced collision time range
enterfrac = f;
+ // if the collision time range is now empty, no collision
+ if (enterfrac > leavefrac)
+ return;
+ // if the collision would be further away than the trace's
+ // existing collision data, we don't care about this
+ // collision
+ if (enterfrac > trace->realfraction)
+ return;
+ // calculate the nudged fraction and impact normal we'll
+ // need if we accept this collision later
enterfrac2 = f - collision_impactnudge.value * imove;
VectorLerp(startplane->normal, enterfrac, endplane->normal, newimpactnormal);
- hitsupercontents = startplane->supercontents;
hitq3surfaceflags = startplane->q3surfaceflags;
hittexture = startplane->texture;
}
if (d2 > 0)
{
// leave
- fendsolid = false;
f = (d1 + collision_leavenudge.value) / (d1 - d2);
+ // check if this will reduce the collision time range
if (leavefrac > f)
+ {
+ // reduced collision time range
leavefrac = f;
+ // if the collision time range is now empty, no collision
+ if (enterfrac > leavefrac)
+ return;
+ }
}
}
}
- brushsolid = trace->hitsupercontentsmask & thatbrush_start->supercontents;
- if (fstartsolid)
+ // at this point we know the trace overlaps the brush because it was not
+ // rejected at any point in the loop above
+
+ // see if this brush can block the trace or not according to contents
+ if (trace->hitsupercontentsmask & thatbrush_start->supercontents)
{
- trace->startsupercontents |= thatbrush_start->supercontents;
- if (brushsolid)
+ if (enterfrac == -1)
{
+ trace->startsupercontents |= thatbrush_start->supercontents;
trace->startsolid = true;
- if (fendsolid)
+ if (leavefrac < 1)
trace->allsolid = true;
}
+ // store out the impact information
+ trace->hitsupercontents = thatbrush_start->supercontents;
+ trace->hitq3surfaceflags = hitq3surfaceflags;
+ trace->hittexture = hittexture;
+ trace->realfraction = bound(0, enterfrac, 1);
+ trace->fraction = bound(0, enterfrac2, 1);
+ VectorCopy(newimpactnormal, trace->plane.normal);
}
-
- // LordHavoc: we need an epsilon nudge here because for a point trace the
- // penetrating line segment is normally zero length if this brush was
- // generated from a polygon (infinitely thin), and could even be slightly
- // positive or negative due to rounding errors in that case.
- if (brushsolid && enterfrac > -1 && enterfrac < trace->realfraction && enterfrac <= leavefrac)
+ else
{
-#if 0
- // broken
- if (thatbrush_start->ispolygon)
- {
- d1 = DotProduct(thatbrush_start->planes[0].normal, linestart) - thatbrush_start->planes[0].dist - collision_startnudge.value;
- d2 = DotProduct(thatbrush_end->planes[0].normal, lineend) - thatbrush_end->planes[0].dist - collision_endnudge.value;
- move = d1 - d2;
- if (move <= 0 || d2 > collision_enternudge.value || d1 < 0)
- return;
- // enter
- imove = 1 / move;
- enterfrac = (d1 - collision_enternudge.value) * imove;
- if (enterfrac < trace->realfraction)
- {
- enterfrac2 = enterfrac - collision_impactnudge.value * imove;
- trace->hitsupercontents = hitsupercontents;
- trace->hitq3surfaceflags = hitq3surfaceflags;
- trace->hittexture = hittexture;
- trace->realfraction = bound(0, enterfrac, 1);
- trace->fraction = bound(0, enterfrac2, 1);
- VectorLerp(thatbrush_start->planes[0].normal, enterfrac, thatbrush_end->planes[0].normal, trace->plane.normal);
- }
- }
- else
-#endif
- {
- trace->hitsupercontents = hitsupercontents;
- trace->hitq3surfaceflags = hitq3surfaceflags;
- trace->hittexture = hittexture;
- trace->realfraction = bound(0, enterfrac, 1);
- trace->fraction = bound(0, enterfrac2, 1);
- VectorCopy(newimpactnormal, trace->plane.normal);
- }
+ // this brush can not block the trace, but it can update start contents
+ if (enterfrac == -1)
+ trace->startsupercontents |= thatbrush_start->supercontents;
}
}
polyf_brush.supercontents = supercontents;
for (i = 0;i < polyf_brush.numplanes;i++)
{
- polyf_brush.planes[i].supercontents = supercontents;
polyf_brush.planes[i].q3surfaceflags = q3surfaceflags;
polyf_brush.planes[i].texture = texture;
}
Matrix4x4_Transform(polygonmatrixend, points + i * 3, polyf_brushend.points[i].v);
for (i = 0;i < polyf_brushstart.numplanes;i++)
{
- polyf_brushstart.planes[i].supercontents = supercontents;
polyf_brushstart.planes[i].q3surfaceflags = q3surfaceflags;
polyf_brushstart.planes[i].texture = texture;
}
brush->supercontents = supercontents;
for (j = 0;j < brush->numplanes;j++)
{
- brush->planes[j].supercontents = supercontents;
brush->planes[j].q3surfaceflags = q3surfaceflags;
brush->planes[j].texture = texture;
brush->planes[j].dist = furthestplanedist_float(brush->planes[j].normal, brush->points, brush->numpoints);