]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
BIH building and recursion no longer directly links leaf nodes into the
[xonotic/darkplaces.git] / model_brush.c
index 16d1c7461fe4236a85017512d3439b0406a37ac6..b643aa4a8e8f9c7ba2266bdea035dca9ea119a85 100644 (file)
@@ -1293,36 +1293,38 @@ void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor
        Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2] + 0.125, p[2] - 65536);
 }
 
-static texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, double mid[3])
+static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, double mid[3])
 {
        int i;
        int j;
        int k;
-       int axis = node->plane->type;
        const msurface_t *surface;
        float normal[3];
        float v0[3];
        float v1[3];
        float edgedir[3];
        float edgenormal[3];
-       float p[3];
+       float p[4];
+       float midf;
+       float t1;
+       float t2;
        VectorCopy(mid, p);
+       p[3] = 1;
        surface = model->data_surfaces + node->firstsurface;
        for (i = 0;i < node->numsurfaces;i++, surface++)
        {
-               if (axis < 3)
-               {
-                       if (mid[axis] < surface->mins[axis] || mid[axis] > surface->maxs[axis])
-                               continue;
-               }
-               else
-               {
-                       if (!BoxesOverlap(mid, mid, surface->mins, surface->maxs))
-                               continue;
-               }
+               // skip surfaces whose bounding box does not include the point
+//             if (!BoxesOverlap(mid, mid, surface->mins, surface->maxs))
+//                     continue;
+               // skip faces with contents we don't care about
                if (!(t->trace->hitsupercontentsmask & surface->texture->supercontents))
                        continue;
+               // get the surface normal - since it is flat we know any vertex normal will suffice
                VectorCopy(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex, normal);
+               // skip backfaces
+               if (DotProduct(t->dist, normal) > 0)
+                       continue;
+               // iterate edges and see if the point is outside one of them
                for (j = 0, k = surface->num_vertices - 1;j < surface->num_vertices;k = j, j++)
                {
                        VectorCopy(model->surfmesh.data_vertex3f + 3 * (surface->num_firstvertex + k), v0);
@@ -1332,11 +1334,31 @@ static texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveH
                        if (DotProduct(edgenormal, p) > DotProduct(edgenormal, v0))
                                break;
                }
-               if (j == surface->num_vertices)
-               {
-                       // hit this surface
-                       return surface->texture->currentframe;
-               }
+               // if the point is outside one of the edges, it is not within the surface
+               if (j < surface->num_vertices)
+                       continue;
+
+               // we hit a surface, this is the impact point...
+               VectorCopy(normal, t->trace->plane.normal);
+               t->trace->plane.dist = DotProduct(normal, p);
+
+               // calculate the true fraction
+               t1 = DotProduct(t->start, t->trace->plane.normal) - t->trace->plane.dist;
+               t2 = DotProduct(t->end, t->trace->plane.normal) - t->trace->plane.dist;
+               midf = t1 / (t1 - t2);
+               t->trace->realfraction = midf;
+
+               // calculate the return fraction which is nudged off the surface a bit
+               midf = (t1 - DIST_EPSILON) / (t1 - t2);
+               t->trace->fraction = bound(0, midf, 1);
+
+               if (collision_prefernudgedfraction.integer)
+                       t->trace->realfraction = t->trace->fraction;
+
+               t->trace->hittexture = surface->texture->currentframe;
+               t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags;
+               t->trace->hitsupercontents = t->trace->hittexture->supercontents;
+               return surface->texture->currentframe;
        }
        return NULL;
 }
@@ -1401,36 +1423,13 @@ static int Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(RecursiveHullCheck
                if (Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side], p1, mid) == HULLCHECKSTATE_DONE)
                        return HULLCHECKSTATE_DONE;
 
-               t->trace->hittexture = Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(t, model, node, mid);
-               if (!t->trace->hittexture)
-                       return Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side ^ 1], mid, p2);
-
-               // we hit a surface, this is the impact point...
-               if (side)
-               {
-                       t->trace->plane.dist = -plane->dist;
-                       VectorNegate (plane->normal, t->trace->plane.normal);
-               }
-               else
-               {
-                       t->trace->plane.dist = plane->dist;
-                       VectorCopy (plane->normal, t->trace->plane.normal);
-               }
-       
-               // calculate the true fraction
-               t->trace->realfraction = midf;
-       
-               // calculate the return fraction which is nudged off the surface a bit
-               midf = (t1 - DIST_EPSILON) / (t1 - t2);
-               t->trace->fraction = bound(0, midf, 1);
-       
-               if (collision_prefernudgedfraction.integer)
-                       t->trace->realfraction = t->trace->fraction;
-
-               t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags;
-               t->trace->hitsupercontents = t->trace->hittexture->supercontents;
+               // test each surface on the node
+               Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(t, model, node, mid);
+               if (t->trace->hittexture)
+                       return HULLCHECKSTATE_DONE;
 
-               return HULLCHECKSTATE_DONE;
+               // recurse back side
+               return Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side ^ 1], mid, p2);
        }
        leaf = (const mleaf_t *)node;
        side = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, leaf->contents);
@@ -5976,9 +5975,34 @@ static void Mod_CollisionBIH_TracePoint_RecursiveBIHNode(trace_t *trace, dp_mode
        const bih_node_t *node;
        const colbrushf_t *brush;
        int axis;
-       while (nodenum >= 0)
+       for(;;)
        {
                node = model->collision_bih.nodes + nodenum;
+               if (node->type == BIH_UNORDERED)
+               {
+                       for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
+                       {
+                               leaf = model->collision_bih.leafs + node->children[axis];
+#if 1
+                               if (!BoxesOverlap(point, point, leaf->mins, leaf->maxs))
+                                       continue;
+#endif
+                               switch(leaf->type)
+                               {
+                               case BIH_BRUSH:
+                                       brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
+                                       Collision_TracePointBrushFloat(trace, point, brush);
+                                       break;
+                               case BIH_COLLISIONTRIANGLE:
+                                       // collision triangle - skipped because they have no volume
+                                       break;
+                               case BIH_RENDERTRIANGLE:
+                                       // render triangle - skipped because they have no volume
+                                       break;
+                               }
+                       }
+                       return;
+               }
                axis = node->type - BIH_SPLITX;
                if (point[axis] <= node->backmax)
                {
@@ -5991,22 +6015,6 @@ static void Mod_CollisionBIH_TracePoint_RecursiveBIHNode(trace_t *trace, dp_mode
                else // no overlap with either child?  just return
                        return;
        }
-       if (!model->collision_bih.leafs)
-               return;
-       leaf = model->collision_bih.leafs + (-1-nodenum);
-       switch(leaf->type)
-       {
-       case BIH_BRUSH:
-               brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
-               Collision_TracePointBrushFloat(trace, point, brush);
-               break;
-       case BIH_COLLISIONTRIANGLE:
-               // collision triangle - skipped because they have no volume
-               break;
-       case BIH_RENDERTRIANGLE:
-               // render triangle - skipped because they have no volume
-               break;
-       }
 }
 
 static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model_t *model, bih_t *bih, int nodenum, const vec3_t start, const vec3_t end, const vec3_t linestart, const vec3_t lineend)
@@ -6036,13 +6044,44 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model
        segmentmaxs[0] = max(start[0], end[0]);
        segmentmaxs[1] = max(start[1], end[1]);
        segmentmaxs[2] = max(start[2], end[2]);
-       while (nodenum >= 0)
+       for (;;)
        {
                node = bih->nodes + nodenum;
 #if 0
                if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs))
                        return;
 #endif
+               if (node->type == BIH_UNORDERED)
+               {
+                       for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
+                       {
+                               leaf = model->collision_bih.leafs + node->children[axis];
+#if 1
+                               if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs))
+                                       continue;
+#endif
+                               switch(leaf->type)
+                               {
+                               case BIH_BRUSH:
+                                       brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
+                                       Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush);
+                                       break;
+                               case BIH_COLLISIONTRIANGLE:
+                                       if (!mod_q3bsp_curves_collisions.integer)
+                                               continue;
+                                       e = model->brush.data_collisionelement3i + 3*leaf->itemindex;
+                                       texture = model->data_textures + leaf->textureindex;
+                                       Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
+                                       break;
+                               case BIH_RENDERTRIANGLE:
+                                       e = model->surfmesh.data_element3i + 3*leaf->itemindex;
+                                       texture = model->data_textures + leaf->textureindex;
+                                       Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
+                                       break;
+                               }
+                       }
+                       return;
+               }
                axis = node->type - BIH_SPLITX;
 #if 0
                if (segmentmins[axis] <= node->backmax)
@@ -6287,32 +6326,6 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model
 #endif
 #endif
        }
-       if (!bih->leafs)
-               return;
-       leaf = bih->leafs + (-1-nodenum);
-#if 1
-       if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs))
-               return;
-#endif
-       switch(leaf->type)
-       {
-       case BIH_BRUSH:
-               brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
-               Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush);
-               break;
-       case BIH_COLLISIONTRIANGLE:
-               if (!mod_q3bsp_curves_collisions.integer)
-                       return;
-               e = model->brush.data_collisionelement3i + 3*leaf->itemindex;
-               texture = model->data_textures + leaf->textureindex;
-               Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
-               break;
-       case BIH_RENDERTRIANGLE:
-               e = model->surfmesh.data_element3i + 3*leaf->itemindex;
-               texture = model->data_textures + leaf->textureindex;
-               Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
-               break;
-       }
 }
 
 static void Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace_t *trace, dp_model_t *model, int nodenum, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const vec3_t segmentmins, const vec3_t segmentmaxs)
@@ -6323,9 +6336,40 @@ static void Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace_t *trace, dp_mode
        const int *e;
        const texture_t *texture;
        int axis;
-       while (nodenum >= 0)
+       for(;;)
        {
                node = model->collision_bih.nodes + nodenum;
+               if (node->type == BIH_UNORDERED)
+               {
+                       for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
+                       {
+                               leaf = model->collision_bih.leafs + node->children[axis];
+#if 1
+                               if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs))
+                                       continue;
+#endif
+                               switch(leaf->type)
+                               {
+                               case BIH_BRUSH:
+                                       brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
+                                       Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush);
+                                       break;
+                               case BIH_COLLISIONTRIANGLE:
+                                       if (!mod_q3bsp_curves_collisions.integer)
+                                               continue;
+                                       e = model->brush.data_collisionelement3i + 3*leaf->itemindex;
+                                       texture = model->data_textures + leaf->textureindex;
+                                       Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
+                                       break;
+                               case BIH_RENDERTRIANGLE:
+                                       e = model->surfmesh.data_element3i + 3*leaf->itemindex;
+                                       texture = model->data_textures + leaf->textureindex;
+                                       Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
+                                       break;
+                               }
+                       }
+                       return;
+               }
                axis = node->type - BIH_SPLITX;
 #if 1
                if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs))
@@ -6347,32 +6391,6 @@ static void Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace_t *trace, dp_mode
                else
                        return; // trace falls between children
        }
-       if (!model->collision_bih.leafs)
-               return;
-       leaf = model->collision_bih.leafs + (-1-nodenum);
-#if 1
-       if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs))
-               return;
-#endif
-       switch(leaf->type)
-       {
-       case BIH_BRUSH:
-               brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
-               Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush);
-               break;
-       case BIH_COLLISIONTRIANGLE:
-               if (!mod_q3bsp_curves_collisions.integer)
-                       return;
-               e = model->brush.data_collisionelement3i + 3*leaf->itemindex;
-               texture = model->data_textures + leaf->textureindex;
-               Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
-               break;
-       case BIH_RENDERTRIANGLE:
-               e = model->surfmesh.data_element3i + 3*leaf->itemindex;
-               texture = model->data_textures + leaf->textureindex;
-               Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture);
-               break;
-       }
 }
 
 void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask)
@@ -7165,7 +7183,7 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->TraceLine = Mod_Q3BSP_TraceLine;
        mod->TracePoint = Mod_Q3BSP_TracePoint;
        mod->PointSuperContents = Mod_Q3BSP_PointSuperContents;
-       mod->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLineAgainstSurfaces;
+       mod->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLine;
        mod->brush.TraceLineOfSight = Mod_Q3BSP_TraceLineOfSight;
        mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents;
        mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents;
@@ -7464,7 +7482,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
        loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
        loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
-       loadmodel->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLineAgainstSurfaces;
+       loadmodel->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLine;
        loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        loadmodel->brush.TraceLineOfSight = NULL;
        loadmodel->brush.SuperContentsFromNativeContents = NULL;