]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - collision.c
improved plane distance epsilon checking and improved precision when converting brush...
[xonotic/darkplaces.git] / collision.c
index fb7da1bbe8cd7463204696f86ec2d26cf5f62937..ca95a54b1487eb45f916811bc0c095c3f13b4cf8 100644 (file)
@@ -2,8 +2,9 @@
 #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_PLANE_DIST_EPSILON (1.0f / 32.0f)
 
 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"};
@@ -76,12 +77,12 @@ void Collision_ValidateBrush(colbrushf_t *brush)
                        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++;
@@ -133,11 +134,12 @@ float furthestplanedist_float(const float *normal, const colpointf_t *points, in
 }
 
 
-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 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];
@@ -154,6 +156,12 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
        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, 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) + 1) * 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)
@@ -175,7 +183,7 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
 
                // 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++)
@@ -184,7 +192,7 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                        {
                                // 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;
                        }
                }
@@ -200,7 +208,7 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                        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;
@@ -262,7 +270,6 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                // 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++;
@@ -272,7 +279,7 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
        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))
+               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);
        }
 
@@ -285,6 +292,7 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
 
        // 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;
@@ -303,10 +311,8 @@ colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalpla
                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];
@@ -496,7 +502,7 @@ void Collision_CalcPlanesForPolygonBrushFloat(colbrushf_t *brush)
                {
                        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);
                }
        }
@@ -518,7 +524,7 @@ colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, 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, fstartsolid = true, fendsolid = true, brushsolid, hitq3surfaceflags = 0;
        float enterfrac = -1, leavefrac = 1, d1, d2, f, imove, newimpactnormal[3], enterfrac2 = -1;
        const colplanef_t *startplane, *endplane;
        texture_t *hittexture = NULL;
@@ -542,7 +548,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
                                        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;
@@ -561,7 +567,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
                                        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;
@@ -585,7 +591,6 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
                                        enterfrac = f;
                                        enterfrac2 = f - collision_impactnudge.value * imove;
                                        VectorLerp(startplane->normal, enterfrac, endplane->normal, newimpactnormal);
-                                       hitsupercontents = startplane->supercontents;
                                        hitq3surfaceflags = startplane->q3surfaceflags;
                                        hittexture = startplane->texture;
                                }
@@ -640,7 +645,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
                        if (enterfrac < trace->realfraction)
                        {
                                enterfrac2 = enterfrac - collision_impactnudge.value * imove;
-                               trace->hitsupercontents = thatbrush_start->planes[0].supercontents;
+                               trace->hitsupercontents = thatbrush_start->supercontents;
                                trace->hitq3surfaceflags = thatbrush_start->planes[0].q3surfaceflags;
                                trace->hittexture = thatbrush_start->planes[0].texture;
                                trace->realfraction = bound(0, enterfrac, 1);
@@ -651,7 +656,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
                else
 #endif
                {
-                       trace->hitsupercontents = hitsupercontents;
+                       trace->hitsupercontents = thatbrush_start->supercontents;
                        trace->hitq3surfaceflags = hitq3surfaceflags;
                        trace->hittexture = hittexture;
                        trace->realfraction = bound(0, enterfrac, 1);
@@ -664,7 +669,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush
 // 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, fstartsolid = true, fendsolid = true, brushsolid, hitq3surfaceflags = 0;
        float enterfrac = -1, leavefrac = 1, d1, d2, f, imove, newimpactnormal[3], enterfrac2 = -1;
        const colplanef_t *startplane, *endplane;
        texture_t *hittexture = NULL;
@@ -688,7 +693,7 @@ void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const
                        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);
                        }
                }
@@ -709,7 +714,6 @@ void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const
                                        enterfrac = f;
                                        enterfrac2 = f - collision_impactnudge.value * imove;
                                        VectorLerp(startplane->normal, enterfrac, endplane->normal, newimpactnormal);
-                                       hitsupercontents = startplane->supercontents;
                                        hitq3surfaceflags = startplane->q3surfaceflags;
                                        hittexture = startplane->texture;
                                }
@@ -764,7 +768,7 @@ void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const
                        if (enterfrac < trace->realfraction)
                        {
                                enterfrac2 = enterfrac - collision_impactnudge.value * imove;
-                               trace->hitsupercontents = hitsupercontents;
+                               trace->hitsupercontents = thatbrush_start->supercontents;
                                trace->hitq3surfaceflags = hitq3surfaceflags;
                                trace->hittexture = hittexture;
                                trace->realfraction = bound(0, enterfrac, 1);
@@ -775,7 +779,7 @@ void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const
                else
 #endif
                {
-                       trace->hitsupercontents = hitsupercontents;
+                       trace->hitsupercontents = thatbrush_start->supercontents;
                        trace->hitq3surfaceflags = hitq3surfaceflags;
                        trace->hittexture = hittexture;
                        trace->realfraction = bound(0, enterfrac, 1);
@@ -846,7 +850,6 @@ void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *th
        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;
        }
@@ -961,7 +964,6 @@ void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t
                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;
        }
@@ -1038,7 +1040,6 @@ colbrushf_t *Collision_BrushForBox(const matrix4x4_t *matrix, const vec3_t mins,
        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);