//[MethodImpl(MethodImplOptions.NoInlining)]
        void FindInsideVertices(ref BlobArray <float3> usedVertices0,
                                ref BlobArray <ushort> vertexIntersectionPlanes,
                                ref BlobArray <int2> vertexIntersectionSegments,
                                ref BlobArray <float4> intersectingPlanes1,
                                float4x4 nodeToTreeSpaceMatrix1,
                                float4x4 vertexToLocal0,
                                //ref HashedVertices                hashedVertices,
                                NativeArray <PlaneVertexIndexPair> foundIndices0,
                                ref int foundIndices0Length)
        {
            var localVertices     = stackalloc float4[usedVertices0.Length];
            var usedVertexIndices = stackalloc ushort[usedVertices0.Length];
            var foundVertexCount  = 0;

            for (int j = 0; j < usedVertices0.Length; j++)
            {
                var brushVertex1 = new float4(usedVertices0[j], 1);
                localVertices[j]     = math.mul(vertexToLocal0, brushVertex1);
                usedVertexIndices[j] = (ushort)j;
            }

            foundVertexCount = usedVertices0.Length;
            for (int j = foundVertexCount - 1; j >= 0; j--)
            {
                if (IsOutsidePlanes(ref intersectingPlanes1, localVertices[j]))
                {
                    if (j < foundVertexCount - 1)
                    {
                        localVertices[j]     = localVertices[foundVertexCount - 1];
                        usedVertexIndices[j] = usedVertexIndices[foundVertexCount - 1];
                    }
                    foundVertexCount--;
                }
            }

            for (int j = 0; j < foundVertexCount; j++)
            {
                var usedVertexIndex = usedVertexIndices[j];
                var segment         = vertexIntersectionSegments[usedVertexIndex];
                if (segment.y == 0)
                {
                    continue;
                }

                var treeSpaceVertex      = math.mul(nodeToTreeSpaceMatrix1, localVertices[j]).xyz;
                var treeSpaceVertexIndex = hashedVertices.AddNoResize(treeSpaceVertex);
                for (int i = segment.x; i < segment.x + segment.y; i++)
                {
                    var planeIndex = vertexIntersectionPlanes[i];
                    foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair {
                        planeIndex = (ushort)planeIndex, vertexIndex = (ushort)treeSpaceVertexIndex
                    };
                    foundIndices0Length++;
                }
            }
        }
        void FindIntersectionVertices(ref NativeArray <float4> intersectingPlanes0,
                                      int intersectingPlanes0Length,
                                      int intersectingPlanesAndEdges0Length,
                                      ref NativeArray <float4> intersectingPlanes1,
                                      int intersectingPlanes1Length,
                                      int intersectingPlanesAndEdges1Length,
                                      ref NativeArray <PlanePair> usedPlanePairs1,
                                      int usedPlanePairs1Length,
                                      ref NativeArray <int> intersectingPlaneIndices0,
                                      int intersectingPlaneIndices0Length,
                                      float4x4 nodeToTreeSpaceMatrix0,
                                      ref HashedVertices hashedTreeSpaceVertices,
                                      ref HashedVertices snapHashedVertices,
                                      NativeArray <PlaneVertexIndexPair> foundIndices0,
                                      ref int foundIndices0Length,
                                      NativeArray <PlaneVertexIndexPair> foundIndices1,
                                      ref int foundIndices1Length)
        {
            int foundVerticesCount = usedPlanePairs1Length * intersectingPlanes0Length;

            NativeCollectionHelpers.EnsureMinimumSize(ref foundVertices, foundVerticesCount);
            NativeCollectionHelpers.EnsureMinimumSize(ref foundEdges, foundVerticesCount);
            NativeCollectionHelpers.EnsureMinimumSize(ref foundIntersections, foundVerticesCount);

            var n = 0;

            for (int i = 0; i < usedPlanePairs1Length; i++)
            {
                for (int j = 0; j < intersectingPlanes0Length; j++)
                {
                    var plane0 = usedPlanePairs1[i].plane0;
                    var plane1 = usedPlanePairs1[i].plane1;
                    var plane2 = intersectingPlanes0[j];

                    foundIntersections[n] = new IntersectionPlanes
                    {
                        //plane0    = plane0,
                        //plane1    = plane1,
                        plane2      = plane2,
                        planeIndex0 = usedPlanePairs1[i].planeIndex0,
                        planeIndex1 = usedPlanePairs1[i].planeIndex1,
                        planeIndex2 = intersectingPlaneIndices0[j]
                    };

                    foundEdges[n] = new IntersectionEdge
                    {
                        edgeVertex0 = usedPlanePairs1[i].edgeVertex0,
                        edgeVertex1 = usedPlanePairs1[i].edgeVertex1
                    };

                    if (math.abs(math.dot(plane2.xyz, plane0.xyz)) >= CSGConstants.kNormalDotAlignEpsilon ||
                        math.abs(math.dot(plane2.xyz, plane1.xyz)) >= CSGConstants.kNormalDotAlignEpsilon ||
                        math.abs(math.dot(plane0.xyz, plane1.xyz)) >= CSGConstants.kNormalDotAlignEpsilon)
                    {
                        continue;
                    }

                    var localVertex = PlaneExtensions.Intersection(plane2, plane0, plane1);
                    if (double.IsNaN(localVertex.x))
                    {
                        continue;
                    }

                    foundVertices[n] = new float4((float3)localVertex, 1);
                    n++;
                }
            }

            for (int k = n - 1; k >= 0; k--)
            {
                var edgeVertex0 = foundEdges[k].edgeVertex0;
                var edgeVertex1 = foundEdges[k].edgeVertex1;
                var plane2      = foundIntersections[k].plane2;

                if (math.abs(math.dot(plane2, edgeVertex0)) <= kFatPlaneWidthEpsilon &&
                    math.abs(math.dot(plane2, edgeVertex1)) <= kFatPlaneWidthEpsilon)
                {
                    if (k < n - 1)
                    {
                        foundIntersections[k] = foundIntersections[n - 1];
                        foundVertices[k]      = foundVertices[n - 1];
                    }
                    n--;
                }
            }

            // TODO: since we're using a pair in the outer loop, we could also determine which
            //       2 planes it intersects at both ends and just check those two planes ..

            // NOTE: for brush2, the intersection will always be only on two planes
            //       UNLESS it's a corner vertex along that edge (we can compare to the two vertices)
            //       in which case we could use a pre-calculated list of planes ..
            //       OR when the intersection is outside of the edge ..

            for (int k = n - 1; k >= 0; k--)
            {
                if (IsOutsidePlanes(intersectingPlanes0, intersectingPlanesAndEdges0Length, foundVertices[k]) ||
                    IsOutsidePlanes(intersectingPlanes1, intersectingPlanesAndEdges1Length, foundVertices[k]))
                {
                    if (k < n - 1)
                    {
                        foundIntersections[k] = foundIntersections[n - 1];
                        foundVertices[k]      = foundVertices[n - 1];
                    }
                    n--;
                }
            }

            for (int k = 0; k < n; k++)
            {
                var planeIndex0 = (ushort)foundIntersections[k].planeIndex0;
                var planeIndex1 = (ushort)foundIntersections[k].planeIndex1;
                var planeIndex2 = (ushort)foundIntersections[k].planeIndex2;

                var localVertex = foundVertices[k];

                // TODO: should be having a Loop for each plane that intersects this vertex, and add that vertex
                //       to ensure they are identical
                var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix0, localVertex).xyz;
                treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex)];
                var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex);

                {
                    // TODO: optimize
                    for (int f = 0; f < foundIndices0Length; f++)
                    {
                        if (foundIndices0[f].vertexIndex == treeSpaceVertexIndex &&
                            foundIndices0[f].planeIndex == planeIndex2)
                        {
                            goto skip0;
                        }
                    }

                    foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair {
                        planeIndex = planeIndex2, vertexIndex = treeSpaceVertexIndex
                    };
                    foundIndices0Length++;
                    skip0 :;
                }

                {
                    // TODO: optimize
                    for (int f = 0; f < foundIndices1Length; f++)
                    {
                        if (foundIndices1[f].vertexIndex == treeSpaceVertexIndex &&
                            foundIndices1[f].planeIndex == planeIndex0)
                        {
                            goto skip1;
                        }
                    }

                    foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                        planeIndex = planeIndex0, vertexIndex = treeSpaceVertexIndex
                    };
                    foundIndices1Length++;
                    skip1 :;
                }

                {
                    // TODO: optimize
                    for (int f = 0; f < foundIndices1Length; f++)
                    {
                        if (foundIndices1[f].vertexIndex == treeSpaceVertexIndex &&
                            foundIndices1[f].planeIndex == planeIndex1)
                        {
                            goto skip2;
                        }
                    }

                    foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                        planeIndex = planeIndex1, vertexIndex = treeSpaceVertexIndex
                    };
                    foundIndices1Length++;
                    skip2 :;
                }
            }
        }
        //[MethodImpl(MethodImplOptions.NoInlining)]
        void FindInsideVertices([NoAlias] NativeArray <float3> usedVertices0,
                                int usedVertices0Length,
                                [NoAlias] NativeArray <ushort> vertexIntersectionPlanes,
                                int vertexIntersectionPlanesLength,
                                [NoAlias] NativeArray <int2> vertexIntersectionSegments,
                                int vertexIntersectionSegmentsLength,
                                [NoAlias] NativeArray <float4> intersectingPlanes1,
                                int intersectingPlanes1Length,
                                int intersectingPlanesAndEdges1Length,
                                float4x4 nodeToTreeSpaceMatrix1,
                                float4x4 vertexToLocal0,
                                [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
                                [NoAlias] ref HashedVertices snapHashedVertices,
                                [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0,
                                ref int foundIndices0Length)
        {
            NativeCollectionHelpers.EnsureMinimumSize(ref localVertices, usedVertices0Length);
            NativeCollectionHelpers.EnsureMinimumSize(ref usedVertexIndices, usedVertices0Length);

            for (int j = 0; j < usedVertices0Length; j++)
            {
                var brushVertex1 = new float4(usedVertices0[j], 1);
                localVertices[j]     = math.mul(vertexToLocal0, brushVertex1);
                usedVertexIndices[j] = (ushort)j;
            }

            var foundVertexCount = usedVertices0Length;

            for (int j = foundVertexCount - 1; j >= 0; j--)
            {
                if (IsOutsidePlanes(intersectingPlanes1, intersectingPlanesAndEdges1Length, localVertices[j]))
                {
                    if (j < foundVertexCount - 1)
                    {
                        localVertices[j]     = localVertices[foundVertexCount - 1];
                        usedVertexIndices[j] = usedVertexIndices[foundVertexCount - 1];
                    }
                    foundVertexCount--;
                }
            }

            for (int j = 0; j < foundVertexCount; j++)
            {
                var usedVertexIndex = usedVertexIndices[j];
                var segment         = vertexIntersectionSegments[usedVertexIndex];
                if (segment.y == 0)
                {
                    continue;
                }

                var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix1, localVertices[j]).xyz;
                treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex)];
                var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex);
                for (int i = segment.x; i < segment.x + segment.y; i++)
                {
                    var planeIndex = vertexIntersectionPlanes[i];

                    // TODO: optimize
                    for (int k = 0; k < foundIndices0Length; k++)
                    {
                        if (foundIndices0[k].planeIndex == planeIndex &&
                            foundIndices0[k].vertexIndex == treeSpaceVertexIndex)
                        {
                            goto skipMe;
                        }
                    }

                    foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair {
                        planeIndex = (ushort)planeIndex, vertexIndex = (ushort)treeSpaceVertexIndex
                    };
                    foundIndices0Length++;
skipMe:
                    ;
                }
            }
        }
        //[MethodImpl(MethodImplOptions.NoInlining)]
        void FindIntersectionVertices(ref BlobArray <float4> intersectingPlanes0,
                                      ref BlobArray <float4> intersectingPlanes1,
                                      ref BlobArray <PlanePair> usedPlanePairs1,
                                      ref BlobArray <int> intersectingPlaneIndices0,
                                      float4x4 nodeToTreeSpaceMatrix0,
                                      //ref HashedVertices              hashedVertices,
                                      NativeArray <PlaneVertexIndexPair> foundIndices0,
                                      ref int foundIndices0Length,
                                      NativeArray <PlaneVertexIndexPair> foundIndices1,
                                      ref int foundIndices1Length)
        {
            var foundVertices      = new NativeArray <float4>(usedPlanePairs1.Length * intersectingPlanes0.Length, Allocator.Temp);
            var foundEdges         = new NativeArray <IntersectionEdge>(usedPlanePairs1.Length * intersectingPlanes0.Length, Allocator.Temp);
            var foundIntersections = new NativeArray <IntersectionPlanes>(usedPlanePairs1.Length * intersectingPlanes0.Length, Allocator.Temp);
            var n = 0;

            for (int i = 0; i < usedPlanePairs1.Length; i++)
            {
                for (int j = 0; j < intersectingPlanes0.Length; j++)
                {
                    foundIntersections[n] = new IntersectionPlanes
                    {
                        plane0      = usedPlanePairs1[i].plane0,
                        plane1      = usedPlanePairs1[i].plane1,
                        plane2      = intersectingPlanes0[j],
                        planeIndex0 = usedPlanePairs1[i].planeIndex0,
                        planeIndex1 = usedPlanePairs1[i].planeIndex1,
                        planeIndex2 = intersectingPlaneIndices0[j]
                    };

                    foundEdges[n] = new IntersectionEdge
                    {
                        edgeVertex0 = usedPlanePairs1[i].edgeVertex0,
                        edgeVertex1 = usedPlanePairs1[i].edgeVertex1
                    };

                    var plane0 = usedPlanePairs1[i].plane0;
                    var plane1 = usedPlanePairs1[i].plane1;
                    var plane2 = intersectingPlanes0[j];

                    foundVertices[n] = new float4(PlaneExtensions.Intersection(plane2, plane0, plane1), 1);
                    n++;
                }
            }

            for (int k = n - 1; k >= 0; k--)
            {
                var edgeVertex0 = foundEdges[k].edgeVertex0;
                var edgeVertex1 = foundEdges[k].edgeVertex1;
                var plane2      = foundIntersections[k].plane2;

                if (math.abs(math.dot(plane2, edgeVertex0)) <= kDistanceEpsilon &&
                    math.abs(math.dot(plane2, edgeVertex1)) <= kDistanceEpsilon)
                {
                    if (k < n - 1)
                    {
                        foundIntersections[k] = foundIntersections[n - 1];
                        foundVertices[k]      = foundVertices[n - 1];
                    }
                    n--;
                }
            }

            // TODO: since we're using a pair in the outer loop, we could also determine which
            //       2 planes it intersects at both ends and just check those two planes ..

            // NOTE: for brush2, the intersection will always be only on two planes
            //       UNLESS it's a corner vertex along that edge (we can compare to the two vertices)
            //       in which case we could use a pre-calculated list of planes ..
            //       OR when the intersection is outside of the edge ..

            for (int k = n - 1; k >= 0; k--)
            {
                if (IsOutsidePlanes(ref intersectingPlanes0, foundVertices[k]) ||
                    IsOutsidePlanes(ref intersectingPlanes1, foundVertices[k]))
                {
                    if (k < n - 1)
                    {
                        foundIntersections[k] = foundIntersections[n - 1];
                        foundVertices[k]      = foundVertices[n - 1];
                    }
                    n--;
                }
            }

            for (int k = 0; k < n; k++)
            {
                var planeIndex0 = (ushort)foundIntersections[k].planeIndex0;
                var planeIndex1 = (ushort)foundIntersections[k].planeIndex1;
                var planeIndex2 = (ushort)foundIntersections[k].planeIndex2;

                var localVertex = foundVertices[k];

                // TODO: should be having a Loop for each plane that intersects this vertex, and add that vertex
                //       to ensure they are identical
                var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix0, localVertex).xyz;
                var vertexIndex     = hashedVertices.AddNoResize(treeSpaceVertex);

                foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair {
                    planeIndex = planeIndex2, vertexIndex = vertexIndex
                };
                foundIndices0Length++;

                foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                    planeIndex = planeIndex0, vertexIndex = vertexIndex
                };
                foundIndices1Length++;

                foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                    planeIndex = planeIndex1, vertexIndex = vertexIndex
                };
                foundIndices1Length++;
            }
        }