+static void Mod_BIH_TracePoint_RecursiveBIHNode(trace_t *trace, dp_model_t *model, int nodenum, const vec3_t point)
+{
+ const bih_leaf_t *leaf;
+ const bih_node_t *node;
+ const colbrushf_t *brush;
+ int axis;
+ while (nodenum >= 0)
+ {
+ node = model->collision_bih.nodes + nodenum;
+ axis = node->type - BIH_SPLITX;
+ if (point[axis] <= node->backmax)
+ {
+ if (point[axis] >= node->frontmin)
+ Mod_BIH_TracePoint_RecursiveBIHNode(trace, model, node->front, point);
+ nodenum = node->back;
+ }
+ else if (point[axis] >= node->frontmin)
+ nodenum = node->front;
+ 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_LEAF:
+ // brush
+ brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
+ Collision_TracePointBrushFloat(trace, point, brush);
+ break;
+ case BIH_LEAF + 1:
+ // triangle - skipped because they have no volume
+ break;
+ default:
+ break;
+ }
+}
+
+static void Mod_BIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model_t *model, int nodenum, const vec3_t start, const vec3_t end, const vec3_t linestart, const vec3_t lineend)
+{
+ const bih_leaf_t *leaf;
+ const bih_node_t *node;
+ const colbrushf_t *brush;
+ const int *e;
+ const texture_t *texture;
+ int axis;
+#if 0
+ int sideflags;
+ vec_t frontdist1;
+ vec_t frontdist2;
+ vec_t frontfrac;
+ vec_t backdist1;
+ vec_t backdist2;
+ vec_t backfrac;
+ vec3_t clipped[2];
+#endif
+ vec3_t segmentmins;
+ vec3_t segmentmaxs;
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ while (nodenum >= 0)
+ {
+ node = model->collision_bih.nodes + nodenum;
+#if 0
+ if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs))
+ return;
+#endif
+ axis = node->type - BIH_SPLITX;
+#if 1
+ if (segmentmins[axis] <= node->backmax)
+ {
+ if (segmentmaxs[axis] >= node->frontmin)
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend);
+ nodenum = node->back;
+ }
+ else if (segmentmaxs[axis] >= node->frontmin)
+ nodenum = node->front;
+ else
+ return; // trace falls between children
+#else
+ frontdist1 = start[axis] - node->backmax;
+ frontdist2 = end[axis] - node->backmax;
+ backdist1 = start[axis] - node->frontmin;
+ backdist2 = end[axis] - node->frontmin;
+ sideflags = 0;
+ if (frontdist1 < 0)
+ sideflags |= 1;
+ if (frontdist2 < 0)
+ sideflags |= 2;
+ if (backdist1 < 0)
+ sideflags |= 4;
+ if (backdist2 < 0)
+ sideflags |= 8;
+ switch(sideflags)
+ {
+ case 0:
+ // start end START END
+ nodenum = node->front;
+ continue;
+ case 1:
+ // START end START END
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[0]);
+ start = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->front;
+ break;
+ case 2:
+ // start END START END
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[0]);
+ end = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->front;
+ break;
+ case 3:
+ // START END START END
+ return; // line falls in gap between children
+ case 4:
+ // start end start END
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend);
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ end = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 5:
+ // START end start END
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[1]);
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, clipped[1], end, linestart, lineend);
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ end = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 6:
+ // start END start END
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[1]);
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, clipped[1], linestart, lineend);
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ end = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 7:
+ // START END start END
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ end = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 8:
+ // start end START end
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend);
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ start = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 9:
+ // START end START end
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[1]);
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, clipped[1], end, linestart, lineend);
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ start = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 10:
+ // start END START end
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[1]);
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, clipped[1], linestart, lineend);
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ start = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 11:
+ // START END START end
+ backfrac = backdist1 / (backdist1 - backdist2);
+ VectorLerp(start, backfrac, end, clipped[0]);
+ start = clipped[0];
+ segmentmins[0] = min(start[0], end[0]);
+ segmentmins[1] = min(start[1], end[1]);
+ segmentmins[2] = min(start[2], end[2]);
+ segmentmaxs[0] = max(start[0], end[0]);
+ segmentmaxs[1] = max(start[1], end[1]);
+ segmentmaxs[2] = max(start[2], end[2]);
+ nodenum = node->back;
+ break;
+ case 12:
+ // start end start end
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend);
+ nodenum = node->back;
+ break;
+ case 13:
+ // START end start end
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[1]);
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, clipped[1], end, linestart, lineend);
+ nodenum = node->back;
+ break;
+ case 14:
+ // start END start end
+ frontfrac = frontdist1 / (frontdist1 - frontdist2);
+ VectorLerp(start, frontfrac, end, clipped[1]);
+ Mod_BIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, clipped[1], linestart, lineend);
+ nodenum = node->back;
+ break;
+ case 15:
+ // START END start end
+ nodenum = node->back;
+ continue;
+ }
+#endif
+ }
+ 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_LEAF:
+ // brush
+ brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
+ Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush);
+ break;
+ case BIH_LEAF + 1:
+ // triangle
+ 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;
+ default:
+ break;
+ }
+}
+
+static void Mod_BIH_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)
+{
+ const bih_leaf_t *leaf;
+ const bih_node_t *node;
+ const colbrushf_t *brush;
+ const int *e;
+ const texture_t *texture;
+ int axis;
+ while (nodenum >= 0)
+ {
+ node = model->collision_bih.nodes + nodenum;
+ axis = node->type - BIH_SPLITX;
+#if 0
+#if 0
+ if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs))
+ return;
+#endif
+ Mod_BIH_TraceBrush_RecursiveBIHNode(trace, model, node->front, thisbrush_start, thisbrush_end, segmentmins, segmentmaxs);
+ nodenum = node->back;
+ continue;
+#endif
+ if (segmentmins[axis] <= node->backmax)
+ {
+ if (segmentmaxs[axis] >= node->frontmin)
+ Mod_BIH_TraceBrush_RecursiveBIHNode(trace, model, node->front, thisbrush_start, thisbrush_end, segmentmins, segmentmaxs);
+ nodenum = node->back;
+ }
+ else if (segmentmaxs[axis] >= node->frontmin)
+ nodenum = node->front;
+ 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_LEAF:
+ // brush
+ brush = model->brush.data_brushes[leaf->itemindex].colbrushf;
+ Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush);
+ break;
+ case BIH_LEAF + 1:
+ // triangle
+ 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;
+ default:
+ break;
+ }
+}
+