private void VisitNodes(short nodeId, ref Ray ray, ref float tMax, Action<BSPNode> callback)
{
if (nodeId >= nodes.Length || nodeId < 0) return;
var node = nodes[nodeId];
if (node == null) return;
if ((node.flags == BSPNodeFlags.Flag_Leaf) || (node.flags == BSPNodeFlags.Flag_NoChild))
{
// Do stuff here
callback(node);
// We've reached the end of this branch, continue on with the next one.
return;
}
//Figure out which child to recurse into first
float startVal;
float dirVal;
var planeDist = node.planeDist;
short first;
short last;
switch (node.flags)
{
case BSPNodeFlags.Flag_XAxis:
planeDist = -node.planeDist;
startVal = ray.Position.X;
dirVal = ray.Direction.X;
if (startVal <= planeDist)
{
first = node.posChild;
last = node.negChild;
}
else
{
first = node.negChild;
last = node.posChild;
}
break;
case BSPNodeFlags.Flag_YAxis:
startVal = ray.Position.Y;
dirVal = ray.Direction.Y;
if (startVal >= planeDist)
{
first = node.posChild;
last = node.negChild;
}
else
{
first = node.negChild;
last = node.posChild;
}
break;
case BSPNodeFlags.Flag_ZAxis:
startVal = ray.Position.Z;
dirVal = ray.Direction.Z;
if (startVal >= planeDist)
{
first = node.posChild;
last = node.negChild;
}
else
{
first = node.negChild;
last = node.posChild;
}
break;
default:
throw new Exception("This BSPNode has no divider planes. Wierd.");
}
if (dirVal.NearlyZero())
{
// Segment is parallel to the splitting plane, visit the near side only.
VisitNodes(first, ref ray, ref tMax, callback);
return;
}
// The t-value for the intersection with the boundary plane
var tIntersection = (planeDist - startVal) / dirVal;
VisitNodes(first, ref ray, ref tMax, callback);
// Test if line segment straddles the boundary plane
if (0.0f > tIntersection || tIntersection > tMax) return;
// It does, visit the far side
VisitNodes(last, ref ray, ref tMax, callback);
}