From: havoc Date: Mon, 21 Mar 2011 06:57:28 +0000 (+0000) Subject: BIH building and recursion no longer directly links leaf nodes into the X-Git-Tag: xonotic-v0.6.0~163^2~591 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=07724ad4d6ab79f66c46e2ea2180d4efd05b3ee4;p=xonotic%2Fdarkplaces.git BIH building and recursion no longer directly links leaf nodes into the hierarchy, they are only used by unordered children group nodes changed BIH_MAXUNORDEREDCHILDREN to 8 and removed mod_collision_bih_childrengrouping cvar because this seems to be the optimal value (values up to 16 sometimes yield minor gains but not consistent) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10955 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/bih.c b/bih.c index 48a56e42..7a25c668 100644 --- a/bih.c +++ b/bih.c @@ -53,15 +53,12 @@ static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *tota totalmaxs[0] = maxs[0]; totalmaxs[1] = maxs[1]; totalmaxs[2] = maxs[2]; - // if there is only one child this is a leaf - if (numchildren < 2) - return -1-leaflist[0]; // if we run out of nodes it's the caller's fault, but don't crash if (bih->numnodes == bih->maxnodes) { if (!bih->error) bih->error = BIHERROR_OUT_OF_NODES; - return -1-leaflist[0]; + return 0; } nodenum = bih->numnodes++; node = bih->nodes + nodenum; @@ -77,8 +74,8 @@ static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *tota 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) + // check if there are few enough children to store an unordered node + if (numchildren <= BIH_MAXUNORDEREDCHILDREN) { node->type = BIH_UNORDERED; for (j = 0;j < numchildren;j++) @@ -133,7 +130,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 maxchildrenunordered) +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 i; @@ -145,9 +142,6 @@ 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); @@ -163,7 +157,7 @@ static void BIH_GetTriangleListForBox_Node(const bih_t *bih, int nodenum, int ma int axis; bih_node_t *node; bih_leaf_t *leaf; - while (nodenum >= 0) + for(;;) { node = bih->nodes + nodenum; // check if this is an unordered node (which holds an array of leaf numbers) @@ -212,32 +206,11 @@ static void BIH_GetTriangleListForBox_Node(const bih_t *bih, int nodenum, int ma // 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); + BIH_GetTriangleListForBox_Node(bih, bih->rootnode, maxtriangles, trianglelist_idx, trianglelist_surf, &numtriangles, mins, maxs); return numtriangles; } diff --git a/bih.h b/bih.h index f1af0ef2..43b659e9 100644 --- a/bih.h +++ b/bih.h @@ -6,7 +6,7 @@ #ifndef BIH_H #define BIH_H -#define BIH_MAXUNORDEREDCHILDREN 16 +#define BIH_MAXUNORDEREDCHILDREN 8 typedef enum biherror_e { @@ -39,13 +39,13 @@ typedef struct bih_node_s // TODO: move bounds data to parent node and remove it from leafs? float mins[3]; float maxs[3]; - // < 0 is a leaf index (-1-leafindex), >= 0 is another node index (always >= this node's index) + // node indexes of children (always > this node's index) int front; int back; // interval of children float frontmin; // children[0] float backmax; // children[1] - // BIH_UNORDERED uses this for a list of leafindex (positive), -1 = end of list + // BIH_UNORDERED uses this for a list of leafindex (all >= 0), -1 = end of list int children[BIH_MAXUNORDEREDCHILDREN]; } bih_node_t; @@ -78,14 +78,13 @@ typedef struct bih_s // fields used only during BIH_Build: int maxnodes; - int maxchildrenunordered; int error; // set to a value if an error occurs in building (such as numnodes == maxnodes) int *leafsort; int *leafsortscratch; } bih_t; -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 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_GetTriangleListForBox(const bih_t *bih, int maxtriangles, int *trianglelist_idx, int *trianglelist_surf, const float *mins, const float *maxs); diff --git a/gl_rsurf.c b/gl_rsurf.c index 4ee874d6..d8d0492e 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -957,7 +957,6 @@ static void R_Q1BSP_RecursiveGetLightInfo_BIH(r_q1bsp_getlightinfo_t *info, cons int surfaceindex; int t; int nodeleafindex; - int nodenumleafs; const int *nodeleaflist; int currentmaterialflags; qboolean castshadow; @@ -970,125 +969,111 @@ static void R_Q1BSP_RecursiveGetLightInfo_BIH(r_q1bsp_getlightinfo_t *info, cons // note: because the BSP leafs are not in the BIH tree, the _BSP function // must be called to mark leafs visible for entity culling... // we start at the root node - nodestack[nodestackpos++] = 0; + nodestack[nodestackpos++] = bih->rootnode; // we'll be done when the stack is empty while (nodestackpos) { // pop one off the stack to process nodenum = nodestack[--nodestackpos]; - if (nodenum >= 0) + // node + node = bih->nodes + nodenum; + if (node->type == BIH_UNORDERED) { - // node - node = bih->nodes + nodenum; - if (node->type == BIH_UNORDERED) + nodeleaflist = node->children; + for (nodeleafindex = 0;nodeleafindex < BIH_MAXUNORDEREDCHILDREN && node->children[nodeleafindex] >= 0;nodeleafindex++) { - nodeleaflist = node->children; - for (nodenumleafs = 0;nodenumleafs < BIH_MAXUNORDEREDCHILDREN;nodenumleafs++) - if (node->children[nodenumleafs] < 0) - break; - } - else - { - axis = node->type - BIH_SPLITX; -#if 0 - if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs)) + leaf = bih->leafs + node->children[nodeleafindex]; + if (leaf->type != BIH_RENDERTRIANGLE) + continue; +#if 1 + if (!BoxesOverlap(info->lightmins, info->lightmaxs, leaf->mins, leaf->maxs)) continue; #endif -#if 0 - if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(node->mins, node->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes)) +#if 1 + if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(leaf->mins, leaf->maxs, info->numfrustumplanes, info->frustumplanes)) continue; #endif - if (info->lightmins[axis] <= node->backmax) + surfaceindex = leaf->surfaceindex; + surface = info->model->data_surfaces + surfaceindex; + currentmaterialflags = R_GetCurrentTexture(surface->texture)->currentmaterialflags; + castshadow = !(currentmaterialflags & MATERIALFLAG_NOSHADOW); + t = leaf->itemindex + surface->num_firstshadowmeshtriangle - surface->num_firsttriangle; + e = info->model->brush.shadowmesh->element3i + t * 3; + v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; + VectorCopy(v[0], v2[0]); + VectorCopy(v[1], v2[1]); + VectorCopy(v[2], v2[2]); + if (info->svbsp_insertoccluder) { - if (info->lightmaxs[axis] >= node->frontmin && nodestackpos < GETLIGHTINFO_MAXNODESTACK) - nodestack[nodestackpos++] = node->front; - nodestack[nodestackpos++] = node->back; + if (castshadow) + SVBSP_AddPolygon(&r_svbsp, 3, v2[0], true, NULL, NULL, 0); continue; } - else if (info->lightmaxs[axis] >= node->frontmin) - { - nodestack[nodestackpos++] = node->front; + if (info->svbsp_active && !(SVBSP_AddPolygon(&r_svbsp, 3, v2[0], false, NULL, NULL, 0) & 2)) continue; + // we don't occlude triangles from lighting even + // if they are backfacing, because when using + // shadowmapping they are often not fully occluded + // on the horizon of an edge + SETPVSBIT(info->outlighttrispvs, t); + if (castshadow) + { + if (currentmaterialflags & MATERIALFLAG_NOCULLFACE) + { + // if the material is double sided we + // can't cull by direction + SETPVSBIT(info->outshadowtrispvs, t); + } + else if (r_shadow_frontsidecasting.integer) + { + // front side casting occludes backfaces, + // so they are completely useless as both + // casters and lit polygons + if (PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) + SETPVSBIT(info->outshadowtrispvs, t); + } + else + { + // back side casting does not occlude + // anything so we can't cull lit polygons + if (!PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) + SETPVSBIT(info->outshadowtrispvs, t); + } + } + if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) + { + SETPVSBIT(info->outsurfacepvs, surfaceindex); + info->outsurfacelist[info->outnumsurfaces++] = surfaceindex; } - else - continue; // light falls between children, nothing here } } else { - // leaf - nodenum = -1-nodenum; - nodenumleafs = 1; - nodeleaflist = &nodenum; - } - - for (nodeleafindex = 0;nodeleafindex < nodenumleafs;nodeleafindex++) - { - leaf = bih->leafs + nodeleaflist[nodeleafindex]; - if (leaf->type != BIH_RENDERTRIANGLE) - continue; -#if 1 - if (!BoxesOverlap(info->lightmins, info->lightmaxs, leaf->mins, leaf->maxs)) + axis = node->type - BIH_SPLITX; +#if 0 + if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs)) continue; #endif -#if 1 - if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(leaf->mins, leaf->maxs, info->numfrustumplanes, info->frustumplanes)) +#if 0 + if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(node->mins, node->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes)) continue; #endif - surfaceindex = leaf->surfaceindex; - surface = info->model->data_surfaces + surfaceindex; - currentmaterialflags = R_GetCurrentTexture(surface->texture)->currentmaterialflags; - castshadow = !(currentmaterialflags & MATERIALFLAG_NOSHADOW); - t = leaf->itemindex + surface->num_firstshadowmeshtriangle - surface->num_firsttriangle; - e = info->model->brush.shadowmesh->element3i + t * 3; - v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; - v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; - v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; - VectorCopy(v[0], v2[0]); - VectorCopy(v[1], v2[1]); - VectorCopy(v[2], v2[2]); - if (info->svbsp_insertoccluder) + if (info->lightmins[axis] <= node->backmax) { - if (castshadow) - SVBSP_AddPolygon(&r_svbsp, 3, v2[0], true, NULL, NULL, 0); - continue; - } - if (info->svbsp_active && !(SVBSP_AddPolygon(&r_svbsp, 3, v2[0], false, NULL, NULL, 0) & 2)) + if (info->lightmaxs[axis] >= node->frontmin && nodestackpos < GETLIGHTINFO_MAXNODESTACK) + nodestack[nodestackpos++] = node->front; + nodestack[nodestackpos++] = node->back; continue; - // we don't occlude triangles from lighting even - // if they are backfacing, because when using - // shadowmapping they are often not fully occluded - // on the horizon of an edge - SETPVSBIT(info->outlighttrispvs, t); - if (castshadow) - { - if (currentmaterialflags & MATERIALFLAG_NOCULLFACE) - { - // if the material is double sided we - // can't cull by direction - SETPVSBIT(info->outshadowtrispvs, t); - } - else if (r_shadow_frontsidecasting.integer) - { - // front side casting occludes backfaces, - // so they are completely useless as both - // casters and lit polygons - if (PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) - SETPVSBIT(info->outshadowtrispvs, t); - } - else - { - // back side casting does not occlude - // anything so we can't cull lit polygons - if (!PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) - SETPVSBIT(info->outshadowtrispvs, t); - } } - if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) + else if (info->lightmaxs[axis] >= node->frontmin) { - SETPVSBIT(info->outsurfacepvs, surfaceindex); - info->outsurfacelist[info->outnumsurfaces++] = surfaceindex; + nodestack[nodestackpos++] = node->front; + continue; } + else + continue; // light falls between children, nothing here } } } diff --git a/model_brush.c b/model_brush.c index 71c55bcc..b643aa4a 100644 --- a/model_brush.c +++ b/model_brush.c @@ -52,7 +52,6 @@ cvar_t mod_q3shader_default_polygonoffset = {0, "mod_q3shader_default_polygonoff cvar_t mod_q1bsp_polygoncollisions = {0, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"}; cvar_t mod_collision_bih = {0, "mod_collision_bih", "1", "enables use of generated Bounding Interval Hierarchy tree instead of compiled bsp tree in collision code"}; -cvar_t mod_collision_bih_childrengrouping = {0, "mod_collision_bih_childrengrouping", "16", "this setting prevents excessive recursion depth in the BIH tree by building a shallow tree"}; cvar_t mod_recalculatenodeboxes = {0, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"}; static texture_t mod_q1bsp_texture_solid; @@ -88,7 +87,6 @@ void Mod_BrushInit(void) Cvar_RegisterVariable(&mod_q3shader_default_polygonoffset); Cvar_RegisterVariable(&mod_q1bsp_polygoncollisions); Cvar_RegisterVariable(&mod_collision_bih); - Cvar_RegisterVariable(&mod_collision_bih_childrengrouping); Cvar_RegisterVariable(&mod_recalculatenodeboxes); memset(&mod_q1bsp_texture_solid, 0, sizeof(mod_q1bsp_texture_solid)); @@ -5977,7 +5975,7 @@ 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) @@ -6017,26 +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); -#if 1 - if (!BoxesOverlap(point, point, leaf->mins, leaf->maxs)) - return; -#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; - } } 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) @@ -6066,7 +6044,7 @@ 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 @@ -6348,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) @@ -6384,7 +6336,7 @@ 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) @@ -6439,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) @@ -7143,7 +7069,7 @@ bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t temp_leafsortscratch = temp_leafsort + bihnumleafs; // now build it - BIH_Build(out, bihnumleafs, bihleafs, bihmaxnodes, bihnodes, temp_leafsort, temp_leafsortscratch, mod_collision_bih_childrengrouping.integer); + BIH_Build(out, bihnumleafs, bihleafs, bihmaxnodes, bihnodes, temp_leafsort, temp_leafsortscratch); // we're done with the temporary data Mem_Free(temp_leafsort);