]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - collision.c
the record command now disconnects you if starting a new map, this fixes a crash...
[xonotic/darkplaces.git] / collision.c
index 85da8ae34bb261b26c58a85e569931fe1e8fd2c7..50812e5ec78b38ec0ce6144f84955c326c4941d3 100644 (file)
@@ -12,6 +12,7 @@ cvar_t collision_startnudge = {0, "collision_startnudge", "0", "how much to bias
 cvar_t collision_endnudge = {0, "collision_endnudge", "0", "how much to bias collision trace end"};
 cvar_t collision_enternudge = {0, "collision_enternudge", "0", "how much to bias collision entry fraction"};
 cvar_t collision_leavenudge = {0, "collision_leavenudge", "0", "how much to bias collision exit fraction"};
+cvar_t collision_prefernudgedfraction = {0, "collision_prefernudgedfraction", "1", "whether to sort collision events by nudged fraction (1) or real fraction (0)"};
 
 void Collision_Init (void)
 {
@@ -20,6 +21,7 @@ void Collision_Init (void)
        Cvar_RegisterVariable(&collision_endnudge);
        Cvar_RegisterVariable(&collision_enternudge);
        Cvar_RegisterVariable(&collision_leavenudge);
+       Cvar_RegisterVariable(&collision_prefernudgedfraction);
 }
 
 
@@ -109,6 +111,8 @@ void Collision_ValidateBrush(colbrushf_t *brush)
 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)
@@ -123,6 +127,8 @@ float nearestplanedist_float(const float *normal, const colpointf_t *points, int
 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)
@@ -138,7 +144,7 @@ float furthestplanedist_float(const float *normal, const colpointf_t *points, in
 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;
@@ -178,16 +184,23 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                // 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, 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)
@@ -199,14 +212,13 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                                w = !w;
                        }
                }
+
                // if nothing is left, skip it
-               // LordHavoc: do not skip planes, because they may be bevel planes
-               // added by the map compiler to allow sliding along edges
-               //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);
-               //      continue;
-               //}
+               if (pnumpoints < 3)
+               {
+                       //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;
+               }
 
                for (k = 0;k < pnumpoints;k++)
                {
@@ -220,29 +232,33 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                }
                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_SNAP2)
+                               if (VectorDistance2(v, pointsbuf[m].v) < COLLISION_SNAP2)
                                        break;
 
                        // if there is no match, add a new one
@@ -251,7 +267,7 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                                // 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
@@ -271,28 +287,25 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                        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].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) > COLLISION_PLANE_DIST_EPSILON)
-                       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;
+                       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
@@ -321,16 +334,34 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
        }
        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;
@@ -637,29 +668,33 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
        // 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)
+       // see if the trace started outside the brush or not
+       if (enterfrac > -1)
        {
-               if (enterfrac == -1)
+               // started outside, and overlaps, therefore there is a collision here
+               // store out the impact information
+               if (trace->hitsupercontentsmask & thatbrush_start->supercontents)
                {
-                       trace->startsupercontents |= thatbrush_start->supercontents;
-                       trace->startsolid = true;
-                       if (leavefrac < 1)
-                               trace->allsolid = true;
+                       trace->hitsupercontents = thatbrush_start->supercontents;
+                       trace->hitq3surfaceflags = hitq3surfaceflags;
+                       trace->hittexture = hittexture;
+                       trace->realfraction = bound(0, enterfrac, 1);
+                       trace->fraction = bound(0, enterfrac2, 1);
+                       if (collision_prefernudgedfraction.integer)
+                               trace->realfraction = trace->fraction;
+                       VectorCopy(newimpactnormal, trace->plane.normal);
                }
-               // 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);
        }
        else
        {
-               // this brush can not block the trace, but it can update start contents
-               if (enterfrac == -1)
-                       trace->startsupercontents |= thatbrush_start->supercontents;
+               // started inside, update startsolid and friends
+               trace->startsupercontents |= thatbrush_start->supercontents;
+               if (trace->hitsupercontentsmask & thatbrush_start->supercontents)
+               {
+                       trace->startsolid = true;
+                       if (leavefrac < 1)
+                               trace->allsolid = true;
+               }
        }
 }
 
@@ -752,29 +787,33 @@ void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const
        // 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)
+       // see if the trace started outside the brush or not
+       if (enterfrac > -1)
        {
-               if (enterfrac == -1)
+               // started outside, and overlaps, therefore there is a collision here
+               // store out the impact information
+               if (trace->hitsupercontentsmask & thatbrush_start->supercontents)
                {
-                       trace->startsupercontents |= thatbrush_start->supercontents;
-                       trace->startsolid = true;
-                       if (leavefrac < 1)
-                               trace->allsolid = true;
+                       trace->hitsupercontents = thatbrush_start->supercontents;
+                       trace->hitq3surfaceflags = hitq3surfaceflags;
+                       trace->hittexture = hittexture;
+                       trace->realfraction = bound(0, enterfrac, 1);
+                       trace->fraction = bound(0, enterfrac2, 1);
+                       if (collision_prefernudgedfraction.integer)
+                               trace->realfraction = trace->fraction;
+                       VectorCopy(newimpactnormal, trace->plane.normal);
                }
-               // 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);
        }
        else
        {
-               // this brush can not block the trace, but it can update start contents
-               if (enterfrac == -1)
-                       trace->startsupercontents |= thatbrush_start->supercontents;
+               // started inside, update startsolid and friends
+               trace->startsupercontents |= thatbrush_start->supercontents;
+               if (trace->hitsupercontentsmask & thatbrush_start->supercontents)
+               {
+                       trace->startsolid = true;
+                       if (leavefrac < 1)
+                               trace->allsolid = true;
+               }
        }
 }
 
@@ -801,11 +840,12 @@ static colbrushf_t polyf_brush;
 
 void Collision_SnapCopyPoints(int numpoints, const colpointf_t *in, colpointf_t *out, float fractionprecision, float invfractionprecision)
 {
-       while (numpoints--)
+       int i;
+       for (i = 0;i < numpoints;i++)
        {
-               out->v[0] = floor(in->v[0] * fractionprecision + 0.5f) * invfractionprecision;
-               out->v[1] = floor(in->v[1] * fractionprecision + 0.5f) * invfractionprecision;
-               out->v[2] = floor(in->v[2] * fractionprecision + 0.5f) * invfractionprecision;
+               out[i].v[0] = floor(in[i].v[0] * fractionprecision + 0.5f) * invfractionprecision;
+               out[i].v[1] = floor(in[i].v[1] * fractionprecision + 0.5f) * invfractionprecision;
+               out[i].v[2] = floor(in[i].v[2] * fractionprecision + 0.5f) * invfractionprecision;
        }
 }
 
@@ -822,7 +862,7 @@ void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbru
        polyf_brush.planes = polyf_planes;
        polyf_brush.supercontents = supercontents;
        polyf_brush.points = polyf_points;
-       Collision_SnapCopyPoints(numpoints, (colpointf_t *)points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
+       Collision_SnapCopyPoints(polyf_brush.numpoints, (colpointf_t *)points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
        Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
        //Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
        Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &polyf_brush, &polyf_brush);
@@ -831,7 +871,6 @@ void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbru
 void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numtriangles, const int *element3i, const float *vertex3f, int supercontents, int q3surfaceflags, texture_t *texture, const vec3_t segmentmins, const vec3_t segmentmaxs)
 {
        int i;
-       float facemins[3], facemaxs[3];
        polyf_brush.numpoints = 3;
        polyf_brush.numplanes = 5;
        polyf_brush.points = polyf_points;
@@ -844,18 +883,17 @@ void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *th
        }
        for (i = 0;i < numtriangles;i++, element3i += 3)
        {
-               VectorCopy(vertex3f + element3i[0] * 3, polyf_points[0].v);
-               VectorCopy(vertex3f + element3i[1] * 3, polyf_points[1].v);
-               VectorCopy(vertex3f + element3i[2] * 3, polyf_points[2].v);
-               Collision_SnapCopyPoints(3, polyf_points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
-               facemins[0] = min(polyf_points[0].v[0], min(polyf_points[1].v[0], polyf_points[2].v[0]));
-               facemins[1] = min(polyf_points[0].v[1], min(polyf_points[1].v[1], polyf_points[2].v[1]));
-               facemins[2] = min(polyf_points[0].v[2], min(polyf_points[1].v[2], polyf_points[2].v[2]));
-               facemaxs[0] = max(polyf_points[0].v[0], max(polyf_points[1].v[0], polyf_points[2].v[0]));
-               facemaxs[1] = max(polyf_points[0].v[1], max(polyf_points[1].v[1], polyf_points[2].v[1]));
-               facemaxs[2] = max(polyf_points[0].v[2], max(polyf_points[1].v[2], polyf_points[2].v[2]));
-               if (BoxesOverlap(segmentmins, segmentmaxs, facemins, facemaxs))
+               if (segmentmaxs[0] >= min(vertex3f[element3i[0]*3+0], min(vertex3f[element3i[1]*3+0], vertex3f[element3i[2]*3+0]))
+                && segmentmins[0] <= max(vertex3f[element3i[0]*3+0], max(vertex3f[element3i[1]*3+0], vertex3f[element3i[2]*3+0]))
+                && segmentmaxs[1] >= min(vertex3f[element3i[0]*3+1], min(vertex3f[element3i[1]*3+1], vertex3f[element3i[2]*3+1]))
+                && segmentmins[1] <= max(vertex3f[element3i[0]*3+1], max(vertex3f[element3i[1]*3+1], vertex3f[element3i[2]*3+1]))
+                && segmentmaxs[2] >= min(vertex3f[element3i[0]*3+2], min(vertex3f[element3i[1]*3+2], vertex3f[element3i[2]*3+2]))
+                && segmentmins[2] <= max(vertex3f[element3i[0]*3+2], max(vertex3f[element3i[1]*3+2], vertex3f[element3i[2]*3+2])))
                {
+                       VectorCopy(vertex3f + element3i[0] * 3, polyf_points[0].v);
+                       VectorCopy(vertex3f + element3i[1] * 3, polyf_points[1].v);
+                       VectorCopy(vertex3f + element3i[2] * 3, polyf_points[2].v);
+                       Collision_SnapCopyPoints(polyf_brush.numpoints, polyf_points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
                        Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
                        //Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
                        Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &polyf_brush, &polyf_brush);
@@ -874,7 +912,7 @@ void Collision_TraceLinePolygonFloat(trace_t *trace, const vec3_t linestart, con
        polyf_brush.numplanes = numpoints + 2;
        //polyf_brush.points = (colpointf_t *)points;
        polyf_brush.points = polyf_points;
-       Collision_SnapCopyPoints(numpoints, (colpointf_t *)points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
+       Collision_SnapCopyPoints(polyf_brush.numpoints, (colpointf_t *)points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
        polyf_brush.planes = polyf_planes;
        polyf_brush.supercontents = supercontents;
        Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
@@ -903,19 +941,17 @@ void Collision_TraceLineTriangleMeshFloat(trace_t *trace, const vec3_t linestart
        }
        for (i = 0;i < numtriangles;i++, element3i += 3)
        {
-               float facemins[3], facemaxs[3];
-               VectorCopy(vertex3f + element3i[0] * 3, polyf_points[0].v);
-               VectorCopy(vertex3f + element3i[1] * 3, polyf_points[1].v);
-               VectorCopy(vertex3f + element3i[2] * 3, polyf_points[2].v);
-               Collision_SnapCopyPoints(numpoints, polyf_points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
-               facemins[0] = min(polyf_points[0].v[0], min(polyf_points[1].v[0], polyf_points[2].v[0]));
-               facemins[1] = min(polyf_points[0].v[1], min(polyf_points[1].v[1], polyf_points[2].v[1]));
-               facemins[2] = min(polyf_points[0].v[2], min(polyf_points[1].v[2], polyf_points[2].v[2]));
-               facemaxs[0] = max(polyf_points[0].v[0], max(polyf_points[1].v[0], polyf_points[2].v[0]));
-               facemaxs[1] = max(polyf_points[0].v[1], max(polyf_points[1].v[1], polyf_points[2].v[1]));
-               facemaxs[2] = max(polyf_points[0].v[2], max(polyf_points[1].v[2], polyf_points[2].v[2]));
-               if (BoxesOverlap(segmentmins, segmentmaxs, facemins, facemaxs))
+               if (segmentmaxs[0] >= min(vertex3f[element3i[0]*3+0], min(vertex3f[element3i[1]*3+0], vertex3f[element3i[2]*3+0]))
+                && segmentmins[0] <= max(vertex3f[element3i[0]*3+0], max(vertex3f[element3i[1]*3+0], vertex3f[element3i[2]*3+0]))
+                && segmentmaxs[1] >= min(vertex3f[element3i[0]*3+1], min(vertex3f[element3i[1]*3+1], vertex3f[element3i[2]*3+1]))
+                && segmentmins[1] <= max(vertex3f[element3i[0]*3+1], max(vertex3f[element3i[1]*3+1], vertex3f[element3i[2]*3+1]))
+                && segmentmaxs[2] >= min(vertex3f[element3i[0]*3+2], min(vertex3f[element3i[1]*3+2], vertex3f[element3i[2]*3+2]))
+                && segmentmins[2] <= max(vertex3f[element3i[0]*3+2], max(vertex3f[element3i[1]*3+2], vertex3f[element3i[2]*3+2])))
                {
+                       VectorCopy(vertex3f + element3i[0] * 3, polyf_points[0].v);
+                       VectorCopy(vertex3f + element3i[1] * 3, polyf_points[1].v);
+                       VectorCopy(vertex3f + element3i[2] * 3, polyf_points[2].v);
+                       Collision_SnapCopyPoints(polyf_brush.numpoints, polyf_points, polyf_points, COLLISION_SNAPSCALE, COLLISION_SNAP);
                        Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
                        //Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
                        Collision_TraceLineBrushFloat(trace, linestart, lineend, &polyf_brush, &polyf_brush);
@@ -956,8 +992,8 @@ void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t
                polyf_brushstart.planes[i].q3surfaceflags = q3surfaceflags;
                polyf_brushstart.planes[i].texture = texture;
        }
-       Collision_SnapCopyPoints(numpoints, polyf_pointsstart, polyf_pointsstart, COLLISION_SNAPSCALE, COLLISION_SNAP);
-       Collision_SnapCopyPoints(numpoints, polyf_pointsend, polyf_pointsend, COLLISION_SNAPSCALE, COLLISION_SNAP);
+       Collision_SnapCopyPoints(polyf_brushstart.numpoints, polyf_pointsstart, polyf_pointsstart, COLLISION_SNAPSCALE, COLLISION_SNAP);
+       Collision_SnapCopyPoints(polyf_brushend.numpoints, polyf_pointsend, polyf_pointsend, COLLISION_SNAPSCALE, COLLISION_SNAP);
        Collision_CalcPlanesForPolygonBrushFloat(&polyf_brushstart);
        Collision_CalcPlanesForPolygonBrushFloat(&polyf_brushend);
 
@@ -1234,6 +1270,9 @@ void Collision_TraceLineTriangleFloat(trace_t *trace, const vec3_t linestart, co
        // (the main fraction remains perfect)
        trace->fraction = f - collision_impactnudge.value * d;
 
+       if (collision_prefernudgedfraction.integer)
+               trace->realfraction = trace->fraction;
+
        // store the new trace plane (because collisions only happen from
        // the front this is always simply the triangle normal, never flipped)
        d = 1.0 / sqrt(faceplanenormallength2);