Example #1
0
        public unsafe void GetSelfOverlapsViaQueries <TResultList>(ref TResultList results) where TResultList : IList <Overlap>
        {
            var leafQueryResults = new QuickList <int>(BufferPools <int> .Thread);

            for (int i = 0; i < leafCount; ++i)
            {
                var             leaf = leaves[i];
                BoundingBoxWide leafBoundingBox;
                BoundingBoxWide.GetBoundingBox(ref Levels[leaf.LevelIndex].Nodes[leaf.NodeIndex].BoundingBoxes, leaf.ChildIndex, out leafBoundingBox);
                TestRecursive(0, 0, ref leafBoundingBox, ref leafQueryResults);
                for (int j = 0; j < leafQueryResults.Count; ++j)
                {
                    //Only include results which which are forward in the list to avoid self tests.
                    if (i < leafQueryResults.Elements[j])
                    {
                        results.Add(new Overlap {
                            A = i, B = leafQueryResults.Elements[j]
                        });
                    }
                }
                leafQueryResults.Count = 0;
            }
            leafQueryResults.Dispose();
            //Console.WriteLine("Query-based results:");
            //for (int i = 0; i < results.Count; ++i)
            //{
            //    Console.WriteLine($"{results[i].A}, {results[i].B}");
            //}
        }
Example #2
0
        unsafe void GetOverlapsBetweenDifferentNodes <TResultList>(int levelIndex, int aIndex, int bIndex, ref TResultList results) where TResultList : IList <Overlap>
        {
            //There are no shared children, so test them all.
            var a         = Levels[levelIndex].Nodes[aIndex];
            var b         = Levels[levelIndex].Nodes[bIndex];
            int nextLevel = levelIndex + 1;

            for (int i = 0; i < Vector <float> .Count; ++i)
            {
                if (a.Children[i] == -1)
                {
                    continue;
                }
                //REALLY want a shuffle here. If we could just push forward, retest, push forward, retest...
                //Unclear how much of a performance benefit this would actually be, since this is just a series of broadcasts.
                //... not sure it's actually compiled to a series of broadcasts, though.
                Vector <int>    intersectionMask;
                BoundingBoxWide aWide;
                BoundingBoxWide.GetBoundingBox(ref a.BoundingBoxes, i, out aWide);
                //var aChild = new Vector<int>(a.Children[i]);
                //var less = Vector.LessThan(aChild, b.Children);
                //var bChildIsVector.LessThan(b.Children, new Vector<int>(-1));
                BoundingBoxWide.Intersects(ref aWide, ref b.BoundingBoxes, out intersectionMask);
                for (int j = 0; j < Vector <float> .Count; ++j)
                {
                    //TODO: would it be faster to compute a single combined value via simd and then use a single switch?
                    if (b.Children[j] != -1 && intersectionMask[j] < 0)
                    {
                        //TODO: try removing branches via bool ops
                        if (a.Children[i] >= 0 && b.Children[j] >= 0)
                        {
                            GetOverlapsBetweenDifferentNodes(nextLevel, a.Children[i], b.Children[j], ref results);
                        }
                        else if (a.Children[i] < -1 && b.Children[j] >= 0)
                        {
                            //leaf A versus node B.
                            TestLeafAgainstNode(Encode(a.Children[i]), ref aWide, nextLevel, b.Children[j], ref results);
                        }
                        else if (a.Children[i] >= 0 && b.Children[j] < -1)
                        {
                            //leaf B versus node A.
                            BoundingBoxWide bWide;
                            BoundingBoxWide.GetBoundingBox(ref b.BoundingBoxes, j, out bWide);
                            TestLeafAgainstNode(Encode(b.Children[j]), ref bWide, nextLevel, a.Children[i], ref results);
                        }
                        else if (a.Children[i] < -1 && b.Children[j] < -1)
                        {
                            //Two leaves.
                            var leafA = Encode(a.Children[i]);
                            var leafB = Encode(b.Children[j]);
                            results.Add(new Overlap {
                                A = leafA, B = leafB
                            });
                        }
                    }
                }
            }
        }
            public void Add(ref StreamingLeafGroup parent, int sourceIndex, int destinationIndex, Vector <int>[] masks)
            {
                //This is basically: a[i] = b[j]
                var             leavesBroadcast = new Vector <int>(parent.Leaves[sourceIndex]);
                BoundingBoxWide boundsBroadcast;

                BoundingBoxWide.GetBoundingBox(ref parent.BoundingBoxes, sourceIndex, out boundsBroadcast);
                Leaves = Vector.ConditionalSelect(masks[destinationIndex], leavesBroadcast, Leaves);
                BoundingBoxWide.ConditionalSelect(ref masks[destinationIndex], ref boundsBroadcast, ref BoundingBoxes, out BoundingBoxes);
            }
        public unsafe void GetSelfOverlapsViaStreamingQueries <TResultList>(ref TResultList results) where TResultList : IList <Overlap>
        {
            //var startTime = Stopwatch.GetTimestamp();
            var rootTarget = new StreamingTarget {
                LeafGroups = new QuickList <StreamingLeafGroup>(BufferPools <StreamingLeafGroup> .Locking, BufferPool <StreamingLeafGroup> .GetPoolIndex(LeafCount))
            };

            rootTarget.LeafGroups.Add(new StreamingLeafGroup());
            for (int i = 0; i < LeafCount; ++i)
            {
                BoundingBoxWide leafWide;
                BoundingBoxWide.GetBoundingBox(ref Levels[leaves[i].LevelIndex].Nodes[leaves[i].NodeIndex].BoundingBoxes, leaves[i].ChildIndex, out leafWide);
                var leafIndexWide = new Vector <int>(i);
                rootTarget.Add(ref leafIndexWide, ref leafWide, singleMasks);
            }
            //var endTime = Stopwatch.GetTimestamp();
            //Console.WriteLine($"Initial target construction time: {(endTime - startTime) / (double)Stopwatch.Frequency}");

            QuickQueue <StreamingTarget> targets = new QuickQueue <StreamingTarget>(BufferPools <StreamingTarget> .Locking, BufferPool <StreamingLeafGroup> .GetPoolIndex(LeafCount));

            targets.Enqueue(ref rootTarget);

            QuickList <int> fallbackResults = new QuickList <int>(BufferPools <int> .Locking);

            StreamingTarget target;

            while (targets.TryDequeueLast(out target))
            {
                const int GroupFallbackThreshold = 2; //unfortunately, this should be as high as possible right now because the regular query is faster, period.
                if (target.LeafGroups.Count <= GroupFallbackThreshold)
                {
                    var max = target.LastLeavesCount == Vector <int> .Count ? target.LeafGroups.Count : target.LeafGroups.Count - 1;
                    for (int leafGroupIndex = 0; leafGroupIndex < max; ++leafGroupIndex)
                    {
                        for (int leafInGroupIndex = 0; leafInGroupIndex < Vector <int> .Count; ++leafInGroupIndex)
                        {
                            BoundingBoxWide leafWide;
                            BoundingBoxWide.GetBoundingBox(ref target.LeafGroups.Elements[leafGroupIndex].BoundingBoxes, leafInGroupIndex, out leafWide);
                            TestRecursive(target.LevelIndex, target.NodeIndex, ref leafWide, ref fallbackResults);
                            for (int resultIndex = 0; resultIndex < fallbackResults.Count; ++resultIndex)
                            {
                                var queryLeafIndex = target.LeafGroups.Elements[leafGroupIndex].Leaves[leafInGroupIndex];
                                if (queryLeafIndex < fallbackResults.Elements[resultIndex])
                                {
                                    results.Add(new Overlap {
                                        A = queryLeafIndex, B = fallbackResults.Elements[resultIndex]
                                    });
                                }
                            }
                            fallbackResults.Count = 0;
                        }
                    }
                    if (target.LastLeavesCount < Vector <int> .Count)
                    {
                        var leafGroupIndex = target.LeafGroups.Count - 1;
                        for (int leafInGroupIndex = 0; leafInGroupIndex < target.LastLeavesCount; ++leafInGroupIndex)
                        {
                            BoundingBoxWide leafWide;
                            BoundingBoxWide.GetBoundingBox(ref target.LeafGroups.Elements[leafGroupIndex].BoundingBoxes, leafInGroupIndex, out leafWide);
                            TestRecursive(target.LevelIndex, target.NodeIndex, ref leafWide, ref fallbackResults);
                            for (int resultIndex = 0; resultIndex < fallbackResults.Count; ++resultIndex)
                            {
                                var queryLeafIndex = target.LeafGroups.Elements[leafGroupIndex].Leaves[leafInGroupIndex];
                                if (queryLeafIndex < fallbackResults.Elements[resultIndex])
                                {
                                    results.Add(new Overlap {
                                        A = queryLeafIndex, B = fallbackResults.Elements[resultIndex]
                                    });
                                }
                            }
                            fallbackResults.Count = 0;
                        }
                    }
                }
                else
                {
                    var node = Levels[target.LevelIndex].Nodes[target.NodeIndex];



                    //Test each node child against all of the leaves for this node.
                    for (int nodeChildIndex = 0; nodeChildIndex < Vector <int> .Count; ++nodeChildIndex)
                    {
                        if (node.Children[nodeChildIndex] == -1)
                        {
                            continue;
                        }

                        BoundingBoxWide nodeChildWide;
                        BoundingBoxWide.GetBoundingBox(ref node.BoundingBoxes, nodeChildIndex, out nodeChildWide);

                        if (node.Children[nodeChildIndex] >= 0)
                        {
                            //Internal node. Can spawn more targets.
                            StreamingTarget newTarget = new StreamingTarget
                            {
                                LevelIndex = target.LevelIndex + 1,
                                NodeIndex  = node.Children[nodeChildIndex],
                                LeafGroups = new QuickList <StreamingLeafGroup>(BufferPools <StreamingLeafGroup> .Locking, BufferPool <StreamingLeafGroup> .GetPoolIndex(target.LeafGroups.Count))
                            };
                            newTarget.LeafGroups.Add(new StreamingLeafGroup());


                            for (int leafGroupIndex = 0; leafGroupIndex < target.LeafGroups.Count; ++leafGroupIndex)
                            {
                                Vector <int> intersectionMask;
                                BoundingBoxWide.Intersects(ref nodeChildWide, ref target.LeafGroups.Elements[leafGroupIndex].BoundingBoxes, out intersectionMask);

                                int leafCountInGroup = leafGroupIndex == target.LeafGroups.Count - 1 ? target.LastLeavesCount : Vector <int> .Count;

                                for (int leafIndexInGroup = 0; leafIndexInGroup < leafCountInGroup; ++leafIndexInGroup)
                                {
                                    if (intersectionMask[leafIndexInGroup] < 0)
                                    {
                                        newTarget.Add(ref target, leafGroupIndex, leafIndexInGroup, singleMasks);
                                    }
                                }
                            }
                            targets.Enqueue(ref newTarget);
                        }
                        else
                        {
                            //Leaf node.

                            var nodeLeafIndex = Encode(node.Children[nodeChildIndex]);

                            for (int leafGroupIndex = 0; leafGroupIndex < target.LeafGroups.Count; ++leafGroupIndex)
                            {
                                Vector <int> intersectionMask;
                                BoundingBoxWide.Intersects(ref nodeChildWide, ref target.LeafGroups.Elements[leafGroupIndex].BoundingBoxes, out intersectionMask);

                                int leafCountInGroup = leafGroupIndex == target.LeafGroups.Count - 1 ? target.LastLeavesCount : Vector <int> .Count;

                                for (int leafIndexInGroup = 0; leafIndexInGroup < leafCountInGroup; ++leafIndexInGroup)
                                {
                                    if (intersectionMask[leafIndexInGroup] < 0)
                                    {
                                        var leafIndex = target.LeafGroups[leafGroupIndex].Leaves[leafIndexInGroup];
                                        if (leafIndex < nodeLeafIndex) //The other leaf will also find a collision!
                                        {
                                            results.Add(new Overlap {
                                                A = leafIndex, B = nodeLeafIndex
                                            });
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                target.LeafGroups.Count = 0; //Don't bother forcing a clear on these. TODO: buffer safety check disable
                target.LeafGroups.Dispose();
            }
            targets.Dispose();
            fallbackResults.Dispose();

            //Console.WriteLine("Streaming Query based results:");
            //for (int i = 0; i < results.Count; ++i)
            //{
            //    Console.WriteLine($"{results[i].A}, {results[i].B}");
            //}
        }