+ brush = leaf->firstleafbrush[i]->colbrushf;
+ if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs))
+ {
+ brush->markframe = markframe;
+ Collision_TraceLineBrushFloat(trace, linestart, lineend, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ if (startfrac > trace->realfraction)
+ return;
+ }
+ }
+ // can't do point traces on curves (they have no thickness)
+ if (mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end))
+ {
+ // line trace the curves
+ for (i = 0;i < leaf->numleaffaces;i++)
+ {
+ face = leaf->firstleafface[i];
+ if (face->num_collisiontriangles && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
+ {
+ face->collisionmarkframe = markframe;
+ Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ if (startfrac > trace->realfraction)
+ return;
+ }
+ }
+ }
+}
+
+static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs)
+{
+ int i;
+ //int sides;
+ float nodesegmentmins[3], nodesegmentmaxs[3];
+ q3mleaf_t *leaf;
+ colbrushf_t *brush;
+ q3msurface_t *face;
+ /*
+ // find which nodes the line is in and recurse for them
+ while (node->plane)
+ {
+ // recurse down node sides
+ int startside, endside;
+ float dist1near, dist1far, dist2near, dist2far;
+ BoxPlaneCornerDistances(thisbrush_start->mins, thisbrush_start->maxs, node->plane, &dist1near, &dist1far);
+ BoxPlaneCornerDistances(thisbrush_end->mins, thisbrush_end->maxs, node->plane, &dist2near, &dist2far);
+ startside = dist1near < 0;
+ startside = dist1near < 0 ? (dist1far < 0 ? 1 : 2) : (dist1far < 0 ? 2 : 0);
+ endside = dist2near < 0 ? (dist2far < 0 ? 1 : 2) : (dist2far < 0 ? 2 : 0);
+ if (startside == 2 || endside == 2)
+ {
+ // brushes cross plane
+ // do not clip anything, just take both sides
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ continue;
+ }
+ if (startside == 0)
+ {
+ if (endside == 0)
+ {
+ node = node->children[0];
+ continue;
+ }
+ else
+ {
+ //midf0 = dist1near / (dist1near - dist2near);
+ //midf1 = dist1far / (dist1far - dist2far);
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ continue;
+ }
+ }
+ else
+ {
+ if (endside == 0)
+ {
+ //midf0 = dist1near / (dist1near - dist2near);
+ //midf1 = dist1far / (dist1far - dist2far);
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ continue;
+ }
+ else
+ {
+ node = node->children[1];
+ continue;
+ }
+ }
+
+ if (dist1near < 0 && dist2near < 0 && dist1far < 0 && dist2far < 0){node = node->children[1];continue;}
+ if (dist1near < 0 && dist2near < 0 && dist1far < 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near < 0 && dist2near < 0 && dist1far >= 0 && dist2far < 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near < 0 && dist2near < 0 && dist1far >= 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near < 0 && dist2near >= 0 && dist1far < 0 && dist2far < 0){node = node->children[1];continue;}
+ if (dist1near < 0 && dist2near >= 0 && dist1far < 0 && dist2far >= 0){}
+ if (dist1near < 0 && dist2near >= 0 && dist1far >= 0 && dist2far < 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near < 0 && dist2near >= 0 && dist1far >= 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near >= 0 && dist2near < 0 && dist1far < 0 && dist2far < 0){node = node->children[1];continue;}
+ if (dist1near >= 0 && dist2near < 0 && dist1far < 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near >= 0 && dist2near < 0 && dist1far >= 0 && dist2far < 0){}
+ if (dist1near >= 0 && dist2near < 0 && dist1far >= 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near >= 0 && dist2near >= 0 && dist1far < 0 && dist2far < 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;}
+ if (dist1near >= 0 && dist2near >= 0 && dist1far < 0 && dist2far >= 0){node = node->children[0];continue;}
+ if (dist1near >= 0 && dist2near >= 0 && dist1far >= 0 && dist2far < 0){node = node->children[0];continue;}
+ if (dist1near >= 0 && dist2near >= 0 && dist1far >= 0 && dist2far >= 0){node = node->children[0];continue;}
+ {
+ if (dist2near < 0) // d1n<0 && d2n<0
+ {
+ if (dist2near < 0) // d1n<0 && d2n<0
+ {
+ if (dist2near < 0) // d1n<0 && d2n<0
+ {
+ }
+ else // d1n<0 && d2n>0
+ {
+ }
+ }
+ else // d1n<0 && d2n>0
+ {
+ if (dist2near < 0) // d1n<0 && d2n<0
+ {
+ }
+ else // d1n<0 && d2n>0
+ {
+ }
+ }
+ }
+ else // d1n<0 && d2n>0
+ {
+ }
+ }
+ else // d1n>0
+ {
+ if (dist2near < 0) // d1n>0 && d2n<0
+ {
+ }
+ else // d1n>0 && d2n>0
+ {
+ }
+ }
+ if (dist1near < 0 == dist1far < 0 == dist2near < 0 == dist2far < 0)
+ {
+ node = node->children[startside];
+ continue;
+ }
+ if (dist1near < dist2near)
+ {
+ // out
+ if (dist1near >= 0)
+ {
+ node = node->children[0];
+ continue;
+ }
+ if (dist2far < 0)
+ {
+ node = node->children[1];
+ continue;
+ }
+ // dist1near < 0 && dist2far >= 0
+ }
+ else
+ {
+ // in
+ }
+ startside = dist1near < 0 ? (dist1far < 0 ? 1 : 2) : (dist1far < 0 ? 2 : 0);
+ endside = dist2near < 0 ? (dist2far < 0 ? 1 : 2) : (dist2far < 0 ? 2 : 0);
+ if (startside == 2 || endside == 2)
+ {
+ // brushes cross plane
+ // do not clip anything, just take both sides
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ }
+ else if (startside == endside)
+ node = node->children[startside];
+ else if (startside == 0) // endside = 1 (start infront, end behind)
+ {
+ }
+ else // startside == 1 endside = 0 (start behind, end infront)
+ {
+ }
+ == endside)
+ {
+ if (startside < 2)
+ node = node->children[startside];
+ else
+ {
+ // start and end brush cross plane
+ }
+ }
+ else
+ {
+ }
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ node = node->children[1];
+ else if (dist1near < 0 && dist1far < 0 && dist2near >= 0 && dist2far >= 0)
+ else if (dist1near >= 0 && dist1far >= 0 && dist2near < 0 && dist2far < 0)
+ else if (dist1near >= 0 && dist1far >= 0 && dist2near >= 0 && dist2far >= 0)
+ node = node->children[0];
+ else
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ {
+ }
+ else if (dist1near >= 0 && dist1far >= 0)
+ {
+ }
+ else // mixed (lying on plane)
+ {
+ }
+ {
+ if (dist2near < 0 && dist2far < 0)
+ {
+ }
+ else
+ node = node->children[1];
+ }
+ if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0)
+ node = node->children[0];
+ else if (dist1near >= 0 && dist1far >= 0 && dist2near >= 0 && dist2far >= 0)
+ node = node->children[1];
+ else
+ {
+ // both sides
+ Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ }
+ sides = dist1near || dist1near < 0 | dist1far < 0 | dist2near < 0 | dist
+ startside = dist1 < 0;
+ endside = dist2 < 0;
+ if (startside == endside)
+ {
+ // most of the time the line fragment is on one side of the plane
+ node = node->children[startside];
+ }
+ else
+ {
+ // line crosses node plane, split the line
+ midfrac = dist1 / (dist1 - dist2);
+ VectorLerp(start, midfrac, end, mid);
+ // take the near side first
+ Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs);
+ if (midfrac <= trace->fraction)
+ Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs);
+ return;
+ }
+ }
+ */
+#if 1
+ for (;;)
+ {
+ nodesegmentmins[0] = max(segmentmins[0], node->mins[0]);
+ nodesegmentmins[1] = max(segmentmins[1], node->mins[1]);
+ nodesegmentmins[2] = max(segmentmins[2], node->mins[2]);
+ nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]);
+ nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]);
+ nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]);
+ if (nodesegmentmins[0] > nodesegmentmaxs[0] || nodesegmentmins[1] > nodesegmentmaxs[1] || nodesegmentmins[2] > nodesegmentmaxs[2])
+ return;
+ if (!node->plane)
+ break;
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ }
+#elif 0
+ // FIXME: could be made faster by copying TraceLine code and making it use
+ // box plane distances... (variant on the BoxOnPlaneSide code)
+ for (;;)
+ {
+ nodesegmentmins[0] = max(segmentmins[0], node->mins[0]);
+ nodesegmentmins[1] = max(segmentmins[1], node->mins[1]);
+ nodesegmentmins[2] = max(segmentmins[2], node->mins[2]);
+ nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]);
+ nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]);
+ nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]);
+ if (nodesegmentmins[0] > nodesegmentmaxs[0] || nodesegmentmins[1] > nodesegmentmaxs[1] || nodesegmentmins[2] > nodesegmentmaxs[2])
+ return;
+ if (!node->plane)
+ break;
+ if (mod_q3bsp_debugtracebrush.integer == 2)
+ {
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ continue;
+ }
+ else if (mod_q3bsp_debugtracebrush.integer == 1)
+ {
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
+ {
+ // segment box crosses plane
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ continue;
+ }
+ // take whichever side the segment box is on
+ node = node->children[sides - 1];
+ continue;
+ }
+ else
+ {
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
+ {
+ // segment box crosses plane
+ // now check start and end brush boxes to handle a lot of 'diagonal' cases more efficiently...
+ sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, node->plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, node->plane);
+ if (sides == 3)
+ {
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ continue;
+ }
+ }
+ // take whichever side the segment box is on
+ node = node->children[sides - 1];
+ continue;
+ }
+ return;
+ }
+#else
+ // FIXME: could be made faster by copying TraceLine code and making it use
+ // box plane distances... (variant on the BoxOnPlaneSide code)
+ for (;;)
+ {
+ nodesegmentmins[0] = max(segmentmins[0], node->mins[0]);
+ nodesegmentmins[1] = max(segmentmins[1], node->mins[1]);
+ nodesegmentmins[2] = max(segmentmins[2], node->mins[2]);
+ nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]);
+ nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]);
+ nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]);
+ if (nodesegmentmins[0] > nodesegmentmaxs[0] || nodesegmentmins[1] > nodesegmentmaxs[1] || nodesegmentmins[2] > nodesegmentmaxs[2])
+ return;
+ if (!node->plane)
+ break;
+ if (mod_q3bsp_debugtracebrush.integer == 2)
+ {
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ }
+ else if (mod_q3bsp_debugtracebrush.integer == 1)
+ {
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
+ {
+ // segment box crosses plane
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ node = node->children[1];
+ }
+ else
+ {
+ // take whichever side the segment box is on
+ node = node->children[sides - 1];
+ }
+ }
+ else
+ {
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
+ {
+ // segment box crosses plane
+ // now check start and end brush boxes to handle a lot of 'diagonal' cases more efficiently...
+ sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, node->plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, node->plane);
+ if (sides == 3)
+ {
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ sides = 2;
+ }
+ }
+ // take whichever side the segment box is on
+ node = node->children[sides - 1];
+ }
+ }
+#endif
+ // hit a leaf
+ leaf = (q3mleaf_t *)node;
+ for (i = 0;i < leaf->numleafbrushes;i++)
+ {
+ brush = leaf->firstleafbrush[i]->colbrushf;
+ if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs))
+ {
+ brush->markframe = markframe;