private static BSPNodeInfo ReadBSPNode(BinaryReader reader)
        {
            BSPNodeInfo node = new BSPNodeInfo();

            bool isLeaf = reader.ReadByte() != 0;

            if (isLeaf)
            {
                UInt32 numTriangles = reader.ReadUInt32();
                node.Triangles = new int[numTriangles];
                for (UInt32 i = 0; i < numTriangles; i++)
                {
                    node.Triangles[i] = reader.ReadInt32();
                }
            }
            else
            {
                node.P.N   = ReadVector3(reader);
                node.P.D   = reader.ReadSingle();
                node.Back  = ReadBSPNode(reader);
                node.Front = ReadBSPNode(reader);
            }

            return(node);
        }
        private static int NodeTriangleTest(Vector3 p0, Vector3 p1, CollisionInfo collision, BSPNodeInfo node, ref Vector3 hitPoint)
        {
            if (node.Triangles.Length == 0)
            {
                return(-1);
            }

            Vector3 d = (p1 - p0);

            float distanceToTarget = d.Length;

            // If the end point is basically the same as the start point, then there is no occlusion
            if (d.Length < Epsilon)
            {
                return(-1);
            }

            d = d.Normalize();

            for (int i = 0; i < node.Triangles.Length; i++)
            {
                int t = node.Triangles[i];

                var triangle = collision.Triangles[t];
                var fixture  = collision.Fixtures[triangle.fixture];

                if (fixture.Hidden)
                {
                    return(-1);
                }

                Vector3 v0 = collision.Vertices[triangle.i0];
                Vector3 v1 = collision.Vertices[triangle.i1];
                Vector3 v2 = collision.Vertices[triangle.i2];

                float distance;
                if (RayTestTriangle(out distance, p0, d, v0, v1, v2, ref hitPoint))
                {
                    if (distance < distanceToTarget)
                    {
                        return(i);
                    }
                }
            }

            return(-1);
        }
        private static bool SegmentTest(Vector3 p0, Vector3 p1, CollisionInfo collision, BSPNodeInfo node, int depth, ref SegmentTestInfo info)
        {
            if (node == null)
            {
                return(false);
            }

            info.NumNodesTested++;
            info.MaxDepthReached = Math.Max(info.MaxDepthReached, depth);

            if (node.IsLeaf)
            {
                TriangleInfo hitTriangle = new TriangleInfo();
                int          tri         = NodeTriangleTest(p0, p1, collision, node, ref info.HitPoint);
                info.NumTrianglesTested += (tri != -1) ? (tri + 1) : node.Triangles.Length;
                info.HitTriangle         = hitTriangle;
                return(tri != -1);
            }
            else
            {
                float d0 = Vector3.Dot(node.P.N, p0) - node.P.D;
                float d1 = Vector3.Dot(node.P.N, p1) - node.P.D;

                if (d0 < -Epsilon && d1 < -Epsilon)
                {
                    // Both points behind plane
                    return(SegmentTest(p0, p1, collision, node.Back, depth + 1, ref info));
                }
                else if (d0 > Epsilon && d1 > Epsilon)
                {
                    // Both points in front of plane
                    return(SegmentTest(p0, p1, collision, node.Front, depth + 1, ref info));
                }
                else
                {
                    // Points span plane
                    return(SegmentTest(p0, p1, collision, node.Front, depth + 1, ref info) || SegmentTest(p0, p1, collision, node.Back, depth + 1, ref info));
                }
            }
        }