]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - bih.c
added mod_collision_bih_childrengrouping cvar (default 16), this
[xonotic/darkplaces.git] / bih.c
diff --git a/bih.c b/bih.c
index 8797d20dcfcde1bcb587f949cba18a79457ebf2d..48a56e4208246f107e79f79ec795d686aa31f803 100644 (file)
--- a/bih.c
+++ b/bih.c
@@ -2,7 +2,7 @@
 // This code written in 2010 by Forest Hale (lordhavoc ghdigital com), and placed into public domain.
 
 #include <stdlib.h>
-#include <memory.h>
+#include <string.h>
 #include "bih.h"
 
 static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *totalmins, float *totalmaxs)
@@ -10,10 +10,10 @@ static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *tota
        int i;
        int j;
        int longestaxis;
-       int axis;
+       int axis = 0;
        int nodenum;
-       int front;
-       int back;
+       int front = 0;
+       int back = 0;
        bih_node_t *node;
        bih_leaf_t *child;
        float splitdist;
@@ -72,6 +72,19 @@ static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *tota
        node->maxs[0] = maxs[0];
        node->maxs[1] = maxs[1];
        node->maxs[2] = maxs[2];
+       node->front = 0;
+       node->back = 0;
+       node->frontmin = 0;
+       node->backmax = 0;
+       memset(node->children, -1, sizeof(node->children));
+       // check if this should be an unordered node to reduce recursion depth
+       if (numchildren <= bih->maxchildrenunordered)
+       {
+               node->type = BIH_UNORDERED;
+               for (j = 0;j < numchildren;j++)
+                       node->children[j] = leaflist[j];
+               return nodenum;
+       }
        // pick longest axis
        longestaxis = 0;
        if (size[0] < size[1]) longestaxis = 1;
@@ -112,7 +125,7 @@ static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *tota
        }
 
        // we now have front and back children divided in leaflist...
-       node->type = BIH_SPLITX + axis;
+       node->type = (bih_nodetype_t)((int)BIH_SPLITX + axis);
        node->front = BIH_BuildNode(bih, front, leaflist, frontmins, frontmaxs);
        node->frontmin = frontmins[axis];
        node->back = BIH_BuildNode(bih, back, leaflist + front, backmins, backmaxs);
@@ -120,7 +133,7 @@ static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *tota
        return nodenum;
 }
 
-int BIH_Build(bih_t *bih, int numleafs, bih_leaf_t *leafs, int maxnodes, bih_node_t *nodes, int *temp_leafsort, int *temp_leafsortscratch)
+int BIH_Build(bih_t *bih, int numleafs, bih_leaf_t *leafs, int maxnodes, bih_node_t *nodes, int *temp_leafsort, int *temp_leafsortscratch, int maxchildrenunordered)
 {
        int i;
 
@@ -132,6 +145,9 @@ int BIH_Build(bih_t *bih, int numleafs, bih_leaf_t *leafs, int maxnodes, bih_nod
        bih->numnodes = 0;
        bih->maxnodes = maxnodes;
        bih->nodes = nodes;
+       bih->maxchildrenunordered = maxchildrenunordered;
+       if (bih->maxchildrenunordered > BIH_MAXUNORDEREDCHILDREN)
+               bih->maxchildrenunordered = BIH_MAXUNORDEREDCHILDREN;
 
        // clear things we intend to rebuild
        memset(bih->nodes, 0, sizeof(bih->nodes[0]) * bih->maxnodes);
@@ -141,3 +157,87 @@ int BIH_Build(bih_t *bih, int numleafs, bih_leaf_t *leafs, int maxnodes, bih_nod
        bih->rootnode = BIH_BuildNode(bih, bih->numleafs, bih->leafsort, bih->mins, bih->maxs);
        return bih->error;
 }
+
+static void BIH_GetTriangleListForBox_Node(const bih_t *bih, int nodenum, int maxtriangles, int *trianglelist_idx, int *trianglelist_surf, int *numtrianglespointer, const float *mins, const float *maxs)
+{
+       int axis;
+       bih_node_t *node;
+       bih_leaf_t *leaf;
+       while (nodenum >= 0)
+       {
+               node = bih->nodes + nodenum;
+               // check if this is an unordered node (which holds an array of leaf numbers)
+               if (node->type == BIH_UNORDERED)
+               {
+                       for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
+                       {
+                               leaf = bih->leafs + node->children[axis];
+                               if (mins[0] > leaf->maxs[0] || maxs[0] < leaf->mins[0]
+                                || mins[1] > leaf->maxs[1] || maxs[1] < leaf->mins[1]
+                                || mins[2] > leaf->maxs[2] || maxs[2] < leaf->mins[2])
+                                       continue;
+                               switch(leaf->type)
+                               {
+                               case BIH_RENDERTRIANGLE:
+                                       if (*numtrianglespointer >= maxtriangles)
+                                       {
+                                               ++*numtrianglespointer; // so the caller can detect overflow
+                                               break;
+                                       }
+                                       if(trianglelist_surf)
+                                               trianglelist_surf[*numtrianglespointer] = leaf->surfaceindex;
+                                       trianglelist_idx[*numtrianglespointer] = leaf->itemindex;
+                                       ++*numtrianglespointer;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       return;
+               }
+               // splitting node
+               axis = node->type - BIH_SPLITX;
+               if (mins[axis] < node->backmax)
+               {
+                       if (maxs[axis] > node->frontmin)
+                               BIH_GetTriangleListForBox_Node(bih, node->front, maxtriangles, trianglelist_idx, trianglelist_surf, numtrianglespointer, mins, maxs);
+                       nodenum = node->back;
+                       continue;
+               }
+               if (maxs[axis] > node->frontmin)
+               {
+                       nodenum = node->front;
+                       continue;
+               }
+               // fell between the child groups, nothing here
+               return;
+       }
+       leaf = bih->leafs + (-1-nodenum);
+       if (mins[0] > leaf->maxs[0] || maxs[0] < leaf->mins[0]
+        || mins[1] > leaf->maxs[1] || maxs[1] < leaf->mins[1]
+        || mins[2] > leaf->maxs[2] || maxs[2] < leaf->mins[2])
+               return;
+       switch(leaf->type)
+       {
+       case BIH_RENDERTRIANGLE:
+               if (*numtrianglespointer >= maxtriangles)
+               {
+                       ++*numtrianglespointer; // so the caller can detect overflow
+                       break;
+               }
+               if(trianglelist_surf)
+                       trianglelist_surf[*numtrianglespointer] = leaf->surfaceindex;
+               trianglelist_idx[*numtrianglespointer] = leaf->itemindex;
+               ++*numtrianglespointer;
+               break;
+       default:
+               break;
+       }
+}
+
+int BIH_GetTriangleListForBox(const bih_t *bih, int maxtriangles, int *trianglelist_idx, int *trianglelist_surf, const float *mins, const float *maxs)
+{
+       int numtriangles = 0;
+       BIH_GetTriangleListForBox_Node(bih, 0, maxtriangles, trianglelist_idx, trianglelist_surf, &numtriangles, mins, maxs);
+       return numtriangles;
+}