UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
GenericOctree.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 GenericOctree.h: Generic octree definition.
5=============================================================================*/
6
7#pragma once
8
9#include "Containers/Array.h"
12#include "CoreGlobals.h"
13#include "CoreMinimal.h"
14#include "CoreTypes.h"
15#include "GenericOctreePublic.h"
16#include "HAL/PlatformMisc.h"
17#include "Logging/LogCategory.h"
18#include "Logging/LogMacros.h"
19#include "Math/Box.h"
21#include "Math/MathFwd.h"
22#include "Math/UnrealMathSSE.h"
24#include "Math/Vector.h"
25#include "Math/Vector4.h"
26#include "Math/VectorRegister.h"
28#include "Templates/EnableIf.h"
29#include "Templates/Models.h"
33
35#define FOREACH_OCTREE_CHILD_NODE(ChildRef) \
36 for(FOctreeChildNodeRef ChildRef(0);!ChildRef.IsNULL();ChildRef.Advance())
37
39
42{
43public:
45
46 FVector4 Center; // LWC_TODO: Case for FVector4d
48
51
57
60 {
61 FVector C, E;
62 Box.GetCenterAndExtents(C,E); // LWC_TODO: Perf pessimization
63 Center = FVector4(C, 0);
64 Extent = FVector4(E, 0);
65 }
66
68 template<typename TExtent>
75
82
84 [[nodiscard]] FBox GetBox() const
85 {
86 return FBox(Center - Extent,Center + Extent);
87 }
88
94 [[nodiscard]] friend inline bool Intersect(const FBoxCenterAndExtent& A,const FBoxCenterAndExtent& B)
95 {
96 // CenterDifference is the vector between the centers of the bounding boxes.
98
99 // CompositeExtent is the extent of the bounding box which is the convolution of A with B.
101
102 // For each axis, the boxes intersect on that axis if the projected distance between their centers is less than the sum of their
103 // extents. If the boxes don't intersect on any of the axes, they don't intersect.
105 }
111 template<typename TExtent>
113 {
114 // CenterDifference is the vector between the centers of the bounding boxes.
116
117 // CompositeExtent is the extent of the bounding box which is the convolution of A with B.
119
120 // For each axis, the boxes intersect on that axis if the projected distance between their centers is less than the sum of their
121 // extents. If the boxes don't intersect on any of the axes, they don't intersect.
123 }
130 [[nodiscard]] friend inline bool Intersect(const float A[4],const FBoxCenterAndExtent& B)
131 {
132 // CenterDifference is the vector between the centers of the bounding boxes.
134
135 // CompositeExtent is the extent of the bounding box which is the convolution of A with B.
137
138 // For each axis, the boxes intersect on that axis if the projected distance between their centers is less than the sum of their
139 // extents. If the boxes don't intersect on any of the axes, they don't intersect.
141 }
142};
143
146{
147public:
149
152 {
153 checkSlow(InX >= 0 && InX <= 1);
154 checkSlow(InY >= 0 && InY <= 1);
155 checkSlow(InZ >= 0 && InZ <= 1);
156 Index = int8(InX << 0) | int8(InY << 1) | int8(InZ << 2);
157 }
158
161 : Index(InIndex)
162 {
163 checkSlow(Index < 8);
164 }
165
168 {
169 ++Index;
170 }
171
174 {
175 return Index >= 8;
176 }
177
179 {
180 Index = 8;
181 }
182
184 {
185 return (Index >> 0) & 1;
186 }
187
189 {
190 return (Index >> 1) & 1;
191 }
192
194 {
195 return (Index >> 2) & 1;
196 }
197};
198
201{
202public:
203
204 union
205 {
206 struct
207 {
214 };
215
216 struct
217 {
220
223 };
224
227
230 };
231
236
239 : AllBits(0)
240 {
241 // The positive child bits correspond to the child index, and the negative to the NOT of the child index.
244 }
245
248};
249
252{
253public:
254
256
258 enum { LoosenessDenominator = 16 };
259
262
265
268
271
274
278
285
289 {
290 // A child node's tight extents are half its parent's extents, and its loose extents are expanded by 1/LoosenessDenominator.
291 const FReal TightChildExtent = Bounds.Extent.X * 0.5f;
293
296 }
297
303 {
304 // A child node's tight extents are half its parent's extents, and its loose extents are expanded by 1/LoosenessDenominator.
305 const FReal TightChildExtent = Bounds.Extent.X * 0.5f;
307
310 }
311
313 {
314 // LWC_TODO: not sure this is correct for VectorRegister = VectorRegister4Double
316 } Mask;
317
318 Mask.v = MakeVectorRegister(1u, 2u, 4u, 8u);
323 }
324
334
347
363
371};
372
374
376template<typename ElementType,typename OctreeSemantics>
378{
380public:
383
384private:
385 struct FNode
386 {
387 FNodeIndex ChildNodes = INDEX_NONE;
388 uint32 InclusiveNumElements = 0;
389
390 bool IsLeaf() const
391 {
392 return ChildNodes == INDEX_NONE;
393 }
394 };
395
396 FOctreeNodeContext RootNodeContext;
397 TArray<FNode> TreeNodes;
398 TArray<FNodeIndex> ParentLinks;
399 TArray<ElementArrayType, TAlignedHeapAllocator<alignof(ElementArrayType)>> TreeElements;
400
401 class FFreeList
402 {
403 struct FSpan
404 {
405 FNodeIndex Start;
406 FNodeIndex End;
407 };
408
409 TArray<FSpan> FreeList;
410
411 public:
412 FFreeList()
413 {
414 Reset();
415 }
416
417 void Push(FNodeIndex NodeIndex)
418 {
419 //find the index that points to our right side node
420 int Index = 1; //exclude the dummy
421 int Size = FreeList.Num() - 1;
422
423 //start with binary search for larger lists
424 while (Size > 32)
425 {
426 const int LeftoverSize = Size % 2;
427 Size = Size / 2;
428
429 const int CheckIndex = Index + Size;
430 const int IndexIfLess = CheckIndex + LeftoverSize;
431
432 Index = FreeList[CheckIndex].Start > NodeIndex ? IndexIfLess : Index;
433 }
434
435 //small size array optimization
436 int ArrayEnd = FMath::Min(Index + Size + 1, FreeList.Num());
437 while (Index < ArrayEnd)
438 {
439 if (FreeList[Index].Start < NodeIndex)
440 {
441 break;
442 }
443 Index++;
444 }
445
446 //can we merge with the right node
447 if (Index < FreeList.Num() && FreeList[Index].End + 1 == NodeIndex)
448 {
449 FreeList[Index].End = NodeIndex;
450
451 //are we filling the gap between the left and right node
452 if (FreeList[Index - 1].Start - 1 == NodeIndex)
453 {
454 FreeList[Index - 1].Start = FreeList[Index].Start;
455 FreeList.RemoveAt(Index);
456 }
457 return;
458 }
459
460 //can we merge with the left node
461 if (FreeList[Index - 1].Start - 1 == NodeIndex)
462 {
463 FreeList[Index - 1].Start = NodeIndex;
464 return;
465 }
466
467 //we are node that could not be merged
468 FreeList.Insert(FSpan{ NodeIndex , NodeIndex }, Index);
469 }
470
471 FNodeIndex Pop()
472 {
473 FSpan& Span = FreeList.Last();
474 FNodeIndex Index = Span.Start;
476 if (Span.Start == Span.End)
477 {
478 FreeList.Pop();
479 return Index;
480 }
481 else
482 {
483 Span.Start++;
484 return Index;
485 }
486 }
487
488 void Reset()
489 {
490 FreeList.Reset(1);
491 //push a dummy
492 FreeList.Push(FSpan{ INDEX_NONE, INDEX_NONE });
493 }
494
495 [[nodiscard]] int Num() const
496 {
497 //includes one dummy
498 return FreeList.Num() - 1;
499 }
500 };
501
502 TArray<FNodeIndex> FreeList;
504 FVector::FReal MinLeafExtent;
505
506 FNodeIndex AllocateEightNodes()
507 {
509 if (FreeList.Num())
510 {
511 Index = (FreeList.Pop() * 8) + 1;
512 }
513 else
514 {
515 Index = TreeNodes.AddDefaulted(8);
516 ParentLinks.AddDefaulted();
517 FNodeIndex ElementIndex = TreeElements.AddDefaulted(8);
518 checkSlow(Index == ElementIndex);
519 }
520 return Index;
521 }
522
523 void FreeEightNodes(FNodeIndex Index)
524 {
525 checkSlow(Index != INDEX_NONE && Index != 0);
526 for (int8 i = 0; i < 8; i++)
527 {
528 TreeNodes[Index + i] = FNode();
529 checkSlow(TreeElements[Index + i].Num() == 0);
530 }
531 ParentLinks[(Index - 1) / 8] = INDEX_NONE;
532 //TODO shrink the TreeNodes as well as the TreeElements and ParentLinks to reduce high watermark memory footprint.
533 FreeList.Push((Index - 1) / 8);
534 }
535
536 void AddElementInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& ElementBounds, typename TCallTraits<ElementType>::ConstReference Element, ElementArrayType& TempElementStorage)
537 {
538 checkSlow(CurrentNodeIndex != INDEX_NONE);
539 TreeNodes[CurrentNodeIndex].InclusiveNumElements++;
540 if (TreeNodes[CurrentNodeIndex].IsLeaf())
541 {
542 if (TreeElements[CurrentNodeIndex].Num() + 1 > OctreeSemantics::MaxElementsPerLeaf && NodeContext.Bounds.Extent.X > MinLeafExtent)
543 {
544 TempElementStorage = MoveTemp(TreeElements[CurrentNodeIndex]);
545
546 FNodeIndex ChildStartIndex = AllocateEightNodes();
547 ParentLinks[(ChildStartIndex - 1) / 8] = CurrentNodeIndex;
548 TreeNodes[CurrentNodeIndex].ChildNodes = ChildStartIndex;
549 TreeNodes[CurrentNodeIndex].InclusiveNumElements = 0;
550
552 {
553 const FBoxCenterAndExtent ChildElementBounds(OctreeSemantics::GetBoundingBox(ChildElement));
554 AddElementInternal(CurrentNodeIndex, NodeContext, ChildElementBounds, ChildElement, TempElementStorage);
555 }
556
557 TempElementStorage.Reset();
558 AddElementInternal(CurrentNodeIndex, NodeContext, ElementBounds, Element, TempElementStorage);
559 return;
560 }
561 else
562 {
563 int ElementIndex = TreeElements[CurrentNodeIndex].Emplace(Element);
564
565 SetElementId(Element, FOctreeElementId2(CurrentNodeIndex, ElementIndex));
566 return;
567 }
568 }
569 else
570 {
571 const FOctreeChildNodeRef ChildRef = NodeContext.GetContainingChild(ElementBounds);
572 if (ChildRef.IsNULL())
573 {
574 int ElementIndex = TreeElements[CurrentNodeIndex].Emplace(Element);
575 SetElementId(Element, FOctreeElementId2(CurrentNodeIndex, ElementIndex));
576 return;
577 }
578 else
579 {
580 FNodeIndex ChildNodeIndex = TreeNodes[CurrentNodeIndex].ChildNodes + ChildRef.Index;
582 AddElementInternal(ChildNodeIndex, ChildNodeContext, ElementBounds, Element, TempElementStorage);
583 return;
584 }
585 }
586 }
587
588 void CollapseNodesInternal(FNodeIndex CurrentNodeIndex, ElementArrayType& CollapsedNodeElements)
589 {
590 CollapsedNodeElements.Append(MoveTemp(TreeElements[CurrentNodeIndex]));
591 TreeElements[CurrentNodeIndex].Reset();
592
593 if (!TreeNodes[CurrentNodeIndex].IsLeaf())
594 {
595 FNodeIndex ChildStartIndex = TreeNodes[CurrentNodeIndex].ChildNodes;
596 for (int8 i = 0; i < 8; i++)
597 {
598 CollapseNodesInternal(ChildStartIndex + i, CollapsedNodeElements);
599 }
600
601 // Mark the node as a leaf.
602 TreeNodes[CurrentNodeIndex].ChildNodes = INDEX_NONE;
603
604 FreeEightNodes(ChildStartIndex);
605 }
606 }
607
608 template<typename PredicateFunc, typename IterateFunc>
609 void FindNodesWithPredicateInternal(FNodeIndex ParentNodeIndex, FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const PredicateFunc& Predicate, const IterateFunc& Func) const
610 {
611 if (TreeNodes[CurrentNodeIndex].InclusiveNumElements > 0)
612 {
613 if (Predicate(ParentNodeIndex, CurrentNodeIndex, NodeContext.Bounds))
614 {
615 Func(ParentNodeIndex, CurrentNodeIndex, NodeContext.Bounds);
616
617 if (!TreeNodes[CurrentNodeIndex].IsLeaf())
618 {
619 FNodeIndex ChildStartIndex = TreeNodes[CurrentNodeIndex].ChildNodes;
620 for (int8 i = 0; i < 8; i++)
621 {
622 FindNodesWithPredicateInternal(CurrentNodeIndex, ChildStartIndex + i, NodeContext.GetChildContext(FOctreeChildNodeRef(i)), Predicate, Func);
623 }
624 }
625 }
626 }
627 }
628
629 template<typename IterateFunc>
630 void FindElementsWithBoundsTestInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& BoxBounds, const IterateFunc& Func) const
631 {
632 if (TreeNodes[CurrentNodeIndex].InclusiveNumElements > 0)
633 {
634 for (typename TCallTraits<ElementType>::ConstReference Element : TreeElements[CurrentNodeIndex])
635 {
636 if (Intersect(OctreeSemantics::GetBoundingBox(Element), BoxBounds))
637 {
638 Func(Element);
639 }
640 }
641
642 if (!TreeNodes[CurrentNodeIndex].IsLeaf())
643 {
644 const FOctreeChildNodeSubset IntersectingChildSubset = NodeContext.GetIntersectingChildren(BoxBounds);
645 FNodeIndex ChildStartIndex = TreeNodes[CurrentNodeIndex].ChildNodes;
646 for (int8 i = 0; i < 8; i++)
647 {
649 {
650 FindElementsWithBoundsTestInternal(ChildStartIndex + i, NodeContext.GetChildContext(FOctreeChildNodeRef(i)), BoxBounds, Func);
651 }
652 }
653 }
654 }
655 }
656
657 template<typename IterateFunc>
658 FOctreeElementId2 FindFirstElementWithBoundsTestInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& BoxBounds, const IterateFunc& Func) const
659 {
660 if (TreeNodes[CurrentNodeIndex].InclusiveNumElements > 0)
661 {
662 for (int Index = 0; Index < TreeElements[CurrentNodeIndex].Num(); Index++)
663 {
664 typename TCallTraits<ElementType>::ConstReference Element = TreeElements[CurrentNodeIndex][Index];
665 if (Intersect(OctreeSemantics::GetBoundingBox(Element), BoxBounds))
666 {
667 if (!Func(Element))
668 {
669 return FOctreeElementId2(CurrentNodeIndex, Index);
670 }
671 }
672 }
673
674 if (!TreeNodes[CurrentNodeIndex].IsLeaf())
675 {
676 const FOctreeChildNodeSubset IntersectingChildSubset = NodeContext.GetIntersectingChildren(BoxBounds);
677 FNodeIndex ChildStartIndex = TreeNodes[CurrentNodeIndex].ChildNodes;
678 for (int8 i = 0; i < 8; i++)
679 {
681 {
682 FOctreeElementId2 FoundIndex = FindFirstElementWithBoundsTestInternal(ChildStartIndex + i, NodeContext.GetChildContext(FOctreeChildNodeRef(i)), BoxBounds, Func);
683 if (FoundIndex.IsValidId())
684 {
685 return FoundIndex;
686 }
687 }
688 }
689 }
690 }
691
692 // No matching element was found
693 return FOctreeElementId2();
694 }
695
696 template<typename IterateFunc>
697 void FindNearbyElementsInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& BoxBounds, const IterateFunc& Func) const
698 {
699 if (TreeNodes[CurrentNodeIndex].InclusiveNumElements > 0)
700 {
701 for (int Index = 0; Index < TreeElements[CurrentNodeIndex].Num(); Index++)
702 {
703 Func(TreeElements[CurrentNodeIndex][Index]);
704 }
705
706 if (!TreeNodes[CurrentNodeIndex].IsLeaf())
707 {
708 // Find the child of the current node, if any, that contains the current new point
709 FOctreeChildNodeRef ChildRef = NodeContext.GetContainingChild(BoxBounds);
710 if (!ChildRef.IsNULL())
711 {
712 FNodeIndex ChildStartIndex = TreeNodes[CurrentNodeIndex].ChildNodes;
713 // If the specified child node exists and contains any match, push it than process it
714 if (TreeNodes[ChildStartIndex + ChildRef.Index].InclusiveNumElements > 0)
715 {
716 FindNearbyElementsInternal(ChildStartIndex + ChildRef.Index, NodeContext.GetChildContext(ChildRef), BoxBounds, Func);
717 }
718 // If the child node doesn't is a match, it's not worth pursuing any further. In an attempt to find
719 // anything to match vs. the new point, process all of the children of the current octree node
720 else
721 {
722 for (int8 i = 0; i < 8; i++)
723 {
724 FindNearbyElementsInternal(ChildStartIndex + i, NodeContext.GetChildContext(FOctreeChildNodeRef(i)), BoxBounds, Func);
725 }
726 }
727 }
728 }
729 }
730 }
731public:
732
734 {
735 return TreeNodes.Num();
736 }
737
742 template<typename IterateAllElementsFunc>
743 inline void FindAllElements(const IterateAllElementsFunc& Func) const
744 {
745 for (const ElementArrayType& Elements : TreeElements)
746 {
747 for (typename TCallTraits<ElementType>::ConstReference Element : Elements)
748 {
749 Func(Element);
750 }
751 }
752 }
753
759 template<typename PredicateFunc, typename IterateFunc>
760 inline void FindNodesWithPredicate(const PredicateFunc& Predicate, const IterateFunc& Func) const
761 {
762 FindNodesWithPredicateInternal(INDEX_NONE, 0, RootNodeContext, Predicate, Func);
763 }
764
770 template<typename PredicateFunc, typename IterateFunc>
771 inline void FindElementsWithPredicate(const PredicateFunc& Predicate, const IterateFunc& Func) const
772 {
773 FindNodesWithPredicateInternal(INDEX_NONE, 0, RootNodeContext, Predicate, [&Func, this](FNodeIndex /*ParentNodeIndex*/, FNodeIndex NodeIndex, const FBoxCenterAndExtent& /*NodeBounds*/ )
774 {
775 for (typename TCallTraits<ElementType>::ConstReference Element : TreeElements[NodeIndex])
776 {
777 Func(NodeIndex, Element);
778 }
779 });
780 }
781
787 template<typename IterateBoundsFunc>
788 inline void FindElementsWithBoundsTest(const FBoxCenterAndExtent& BoxBounds, const IterateBoundsFunc& Func) const
789 {
790 FindElementsWithBoundsTestInternal(0, RootNodeContext, BoxBounds, Func);
791 }
792
799 template<typename IterateBoundsFunc>
801 {
802 return FindFirstElementWithBoundsTestInternal(0, RootNodeContext, BoxBounds, Func);
803 }
804
810 template<typename IterateBoundsFunc>
811 inline void FindNearbyElements(const FVector& Position, const IterateBoundsFunc& Func) const
812 {
813 FindNearbyElementsInternal(0, RootNodeContext, FBoxCenterAndExtent(Position, FVector::ZeroVector), Func);
814 }
815
816
822 {
824 const FBoxCenterAndExtent ElementBounds(OctreeSemantics::GetBoundingBox(Element));
825 AddElementInternal(0, RootNodeContext, ElementBounds, Element, TempElementStorage);
826 }
827
832 inline void RemoveElement(FOctreeElementId2 ElementId)
833 {
834 checkSlow(ElementId.IsValidId());
835
836 // Remove the element from the node's element list.
837 TreeElements[ElementId.NodeIndex].RemoveAtSwap(ElementId.ElementIndex, EAllowShrinking::No);
838
839 if (ElementId.ElementIndex < TreeElements[ElementId.NodeIndex].Num())
840 {
841 // Update the external element id for the element that was swapped into the vacated element index.
842 SetElementId(TreeElements[ElementId.NodeIndex][ElementId.ElementIndex], ElementId);
843 }
844
846 {
847 // Update the inclusive element counts for the nodes between the element and the root node,
848 // and find the largest node that is small enough to collapse.
849 FNodeIndex NodeIndex = ElementId.NodeIndex;
850 while (true)
851 {
852 TreeNodes[NodeIndex].InclusiveNumElements--;
853 if (TreeNodes[NodeIndex].InclusiveNumElements < OctreeSemantics::MinInclusiveElementsPerNode)
854 {
855 CollapseNodeIndex = NodeIndex;
856 }
857
858 if (NodeIndex == 0)
859 {
860 break;
861 }
862
863 NodeIndex = ParentLinks[(NodeIndex - 1) / 8];
864 }
865 }
866
867 // Collapse the largest node that was pushed below the threshold for collapse by the removal.
869 {
870 if (TreeElements[CollapseNodeIndex].Num() < (int32)TreeNodes[CollapseNodeIndex].InclusiveNumElements)
871 {
873 TempElementStorage.Reserve(TreeNodes[CollapseNodeIndex].InclusiveNumElements);
874 // Gather the elements contained in this node and its children.
875 CollapseNodesInternal(CollapseNodeIndex, TempElementStorage);
877
878 for (int ElementIndex = 0; ElementIndex < TreeElements[CollapseNodeIndex].Num(); ElementIndex++)
879 {
880 // Update the external element id for the element that's being collapsed.
881 SetElementId(TreeElements[CollapseNodeIndex][ElementIndex], FOctreeElementId2(CollapseNodeIndex, ElementIndex));
882 }
883 }
884 }
885 }
886
890 void Destroy()
891 {
892 TreeNodes.Reset(1);
893 TreeElements.Reset(1);
894 FreeList.Reset();
895 ParentLinks.Reset();
896 TreeNodes.AddDefaulted();
897 TreeElements.AddDefaulted();
898 }
899
901 [[nodiscard]] ElementType& GetElementById(FOctreeElementId2 ElementId)
902 {
903 return TreeElements[ElementId.NodeIndex][ElementId.ElementIndex];
904 }
905
907 [[nodiscard]] const ElementType& GetElementById(FOctreeElementId2 ElementId) const
908 {
909 return TreeElements[ElementId.NodeIndex][ElementId.ElementIndex];
910 }
911
917 {
918 return ElementId.IsValidId() && ElementId.ElementIndex < TreeElements[ElementId.NodeIndex].Num();
919 };
920
926 {
927 return TreeElements[NodeIndex];
928 }
929
931 void DumpStats() const
932 {
933 int32 NumNodes = 0;
934 int32 NumLeaves = 0;
935 int32 NumElements = 0;
938
939 FindNodesWithPredicateInternal(INDEX_NONE, 0, RootNodeContext, [](FNodeIndex /*ParentNodeIndex*/, FNodeIndex /*NodeIndex*/, const FBoxCenterAndExtent&) { return true; }, [&, this](FNodeIndex /*ParentNodeIndex*/, FNodeIndex NodeIndex, const FBoxCenterAndExtent&)
940 {
941 const int32 CurrentNodeElementCount = GetElementsForNode(NodeIndex).Num();
942
943 NumNodes++;
944 if (TreeNodes[NodeIndex].IsLeaf())
945 {
946 NumLeaves++;
947 }
948
949 NumElements += CurrentNodeElementCount;
951
953 {
955 }
957 });
958
959 UE_LOG(LogGenericOctree, Log, TEXT("Octree overview:"));
960 UE_LOG(LogGenericOctree, Log, TEXT("\t%i nodes"), NumNodes);
961 UE_LOG(LogGenericOctree, Log, TEXT("\t%i leaves"), NumLeaves);
962 UE_LOG(LogGenericOctree, Log, TEXT("\t%i elements"), NumElements);
963 UE_LOG(LogGenericOctree, Log, TEXT("\t%i >= elements per node"), MaxElementsPerNode);
964 UE_LOG(LogGenericOctree, Log, TEXT("Octree node element distribution:"));
965 for (int32 i = 0; i < NodeElementDistribution.Num(); i++)
966 {
967 if (NodeElementDistribution[i] > 0)
968 {
969 UE_LOG(LogGenericOctree, Log, TEXT("\tElements: %3i, Nodes: %3i"), i, NodeElementDistribution[i]);
970 }
971 }
972 }
973
975 {
976 SIZE_T TotalSizeBytes = TreeNodes.GetAllocatedSize();
977 TotalSizeBytes += TreeElements.GetAllocatedSize();
978 TotalSizeBytes += TreeNodes[0].InclusiveNumElements * sizeof(ElementType);
979 return TotalSizeBytes;
980 }
981
983 {
984 const int32 ClampedLevel = FMath::Clamp<uint32>(Level, 0, OctreeSemantics::MaxNodeDepth);
985 return RootNodeContext.Bounds.Extent.X * FMath::Pow((1.0f + 1.0f / (FReal)FOctreeNodeContext::LoosenessDenominator) / 2.0f, FReal(ClampedLevel));
986 }
987
989 {
990 return RootNodeContext.Bounds;
991 }
992
994 {
995 for (ElementArrayType& Elements : TreeElements)
996 {
997 Elements.Shrink();
998 }
999 }
1000
1007 void ApplyOffset(const FVector& InOffset, bool bGlobalOctree = false)
1008 {
1010 TempElementStorage.Reserve(TreeNodes[0].InclusiveNumElements);
1011
1012 //collect all elements
1013 CollapseNodesInternal(0, TempElementStorage);
1014 checkSlow(TreeNodes[0].IsLeaf());
1015 Destroy();
1016
1017 if (!bGlobalOctree)
1018 {
1019 RootNodeContext.Bounds.Center += FVector4(InOffset, 0.0f);
1020 }
1021
1022 // Offset & Add all elements from a saved nodes to a new empty octree
1023 for (ElementType& Element : TempElementStorage)
1024 {
1025 OctreeSemantics::ApplyOffset(Element, InOffset);
1026 AddElement(Element);
1027 }
1028 }
1029
1032 : RootNodeContext(FBoxCenterAndExtent(InOrigin, FVector(InExtent, InExtent, InExtent)), 0, 0)
1033 , MinLeafExtent(InExtent* FMath::Pow((1.0f + 1.0f / (FReal)FOctreeNodeContext::LoosenessDenominator) / 2.0f, FReal(OctreeSemantics::MaxNodeDepth)))
1034 {
1035 TreeNodes.AddDefaulted();
1036 TreeElements.AddDefaulted();
1037 }
1038
1041 {
1042 TreeNodes.AddDefaulted();
1043 TreeElements.AddDefaulted();
1044 }
1045
1046private:
1047
1048
1049 // Concept definition for the new octree semantics, which adds a new TOctree parameter
1050 struct COctreeSemanticsV2
1051 {
1052 template<typename Semantics>
1053 auto Requires(typename Semantics::FOctree& OctreeInstance, const ElementType& Element, FOctreeElementId2 Id)
1054 -> decltype(Semantics::SetElementId(OctreeInstance, Element, Id));
1055 };
1056
1057 // Function overload set which calls the V2 version if it's supported or the old version if it's not
1058 template <typename Semantics>
1059 void SetOctreeSemanticsElementId(const ElementType& Element, FOctreeElementId2 Id)
1060 {
1062 {
1063 Semantics::SetElementId(static_cast<typename Semantics::FOctree&>(*this), Element, Id);
1064 }
1065 else
1066 {
1067 Semantics::SetElementId(Element, Id);
1068 }
1069 }
1070
1071protected:
1072 // redirects SetElementId call to the proper implementation
1073 void SetElementId(const ElementType& Element, FOctreeElementId2 Id)
1074 {
1076 }
1077};
1078
1080template<typename ElementType, typename OctreeSemantics>
1082{
1083public:
1084
1088
1090 class FNode
1091 {
1092 public:
1093
1095
1097 explicit FNode(const FNode* InParent)
1098 : Parent(InParent)
1099 , InclusiveNumElements(0)
1100 , bIsLeaf(true)
1101 {
1103 {
1104 Children[ChildRef.Index] = NULL;
1105 }
1106 }
1107
1110 {
1112 {
1113 delete Children[ChildRef.Index];
1114 }
1115 }
1116
1117 // Accessors.
1119 {
1120 return ElementConstIt(Elements);
1121 }
1123 {
1124 return bIsLeaf;
1125 }
1127 {
1128 return Children[ChildRef.Index] != NULL && Children[ChildRef.Index]->InclusiveNumElements > 0;
1129 }
1131 {
1132 return Children[ChildRef.Index];
1133 }
1135 {
1136 return Elements.Num();
1137 }
1139 {
1140 return InclusiveNumElements;
1141 }
1143 {
1144 return Elements;
1145 }
1147 {
1148 Elements.Shrink();
1150 {
1151 if (Children[ChildRef.Index])
1152 {
1153 Children[ChildRef.Index]->ShrinkElements();
1154 }
1155 }
1156 }
1157
1158 void ApplyOffset(const FVector& InOffset)
1159 {
1160 for (auto& Element : Elements)
1161 {
1162 OctreeSemantics::ApplyOffset(Element, InOffset);
1163 }
1164
1166 {
1167 if (Children[ChildRef.Index])
1168 {
1169 Children[ChildRef.Index]->ApplyOffset(InOffset);
1170 }
1171 }
1172 }
1173
1174 private:
1175
1177 mutable ElementArrayType Elements;
1178
1180 const FNode* Parent;
1181
1183 mutable FNode* Children[8];
1184
1186 mutable uint32 InclusiveNumElements : 31;
1187
1189 mutable uint32 bIsLeaf : 1;
1190 };
1191
1192
1193
1196 {
1197 public:
1198
1199 const FNode* Node;
1201
1204 Node(NULL),
1205 Context()
1206 {}
1207
1213 };
1214
1216 typedef TInlineAllocator<7 * (14 - 1) + 8> DefaultStackAllocator;
1217
1219 template<typename StackAllocator = DefaultStackAllocator>
1221 {
1222 public:
1223
1226 {
1227 FNodeReference* NewNode = new (NodeStack) FNodeReference;
1228 NewNode->Node = CurrentNode.Node->GetChild(ChildRef);
1229 CurrentNode.Context.GetChildContext(ChildRef, &NewNode->Context);
1230 }
1233 {
1234 FNodeReference* NewNode = new (NodeStack) FNodeReference;
1235 NewNode->Node = CurrentNode.Node->GetChild(ChildRef);
1236 CurrentNode.Context.GetChildContext(ChildRef, &NewNode->Context);
1239 }
1242 {
1243 new (NodeStack) FNodeReference(CurrentNode.Node->GetChild(ChildRef), Context);
1244 }
1245
1246
1248 void Advance()
1249 {
1250 if (NodeStack.Num())
1251 {
1252 CurrentNode = NodeStack[NodeStack.Num() - 1];
1253 NodeStack.RemoveAt(NodeStack.Num() - 1);
1254 }
1255 else
1256 {
1257 CurrentNode = FNodeReference();
1258 }
1259 }
1260
1263 {
1264 return CurrentNode.Node != NULL;
1265 }
1266
1269 : CurrentNode(FNodeReference(&Tree.RootNode, Tree.RootNodeContext))
1270 {}
1271
1274 CurrentNode(FNodeReference(&Node, Context))
1275 {}
1276
1277 // Accessors.
1278 [[nodiscard]] const FNode& GetCurrentNode() const
1279 {
1280 return *CurrentNode.Node;
1281 }
1283 {
1284 return CurrentNode.Context;
1285 }
1286
1287 private:
1288
1290 FNodeReference CurrentNode;
1291
1294 };
1295
1297 template<typename StackAllocator = DefaultStackAllocator>
1299 {
1300 public:
1301
1303 void Advance()
1304 {
1305 ++ElementIt;
1306 AdvanceToNextIntersectingElement();
1307 }
1308
1311 {
1312 return NodeIt.HasPendingNodes();
1313 }
1314
1317 : IteratorBounds(InBoundingBox)
1318 , NodeIt(Tree)
1319 , ElementIt(Tree.RootNode.GetElementIt())
1320 {
1321 ProcessChildren();
1322 AdvanceToNextIntersectingElement();
1323 }
1324
1325 // Accessors.
1326 [[nodiscard]] const ElementType& GetCurrentElement() const
1327 {
1328 return *ElementIt;
1329 }
1330
1331 private:
1332
1334 FBoxCenterAndExtent IteratorBounds;
1335
1338
1340 ElementConstIt ElementIt;
1341
1343 void ProcessChildren()
1344 {
1345 // Add the child nodes that intersect the bounding box to the node iterator's stack.
1346 const FNode& CurrentNode = NodeIt.GetCurrentNode();
1348 const FOctreeChildNodeSubset IntersectingChildSubset = Context.GetIntersectingChildren(IteratorBounds);
1350 {
1351 if (IntersectingChildSubset.Contains(ChildRef) && CurrentNode.HasChild(ChildRef))
1352 {
1353 NodeIt.PushChild(ChildRef);
1354 }
1355 }
1356 }
1357
1359 void AdvanceToNextIntersectingElement()
1360 {
1361 check(NodeIt.HasPendingNodes()); // please don't call this after iteration has ended
1362
1363 while (1)
1364 {
1365 ElementConstIt LocalElementIt(ElementIt);
1366 if (LocalElementIt)
1367 {
1370
1371 // this is redundantly pull out of the while loop to prevent LHS on the iterator
1372 // Check if the current element intersects the bounding box.
1373 if (Intersect(OctreeSemantics::GetBoundingBox(*LocalElementIt), IteratorBounds))
1374 {
1375 // If it intersects, break out of the advancement loop.
1376 Move(ElementIt, LocalElementIt);
1377 return;
1378 }
1379
1380 // Check if we've advanced past the elements in the current node.
1381 while (++LocalElementIt)
1382 {
1384
1385 // Check if the current element intersects the bounding box.
1386 if (Intersect(OctreeSemantics::GetBoundingBox(*LocalElementIt), IteratorBounds))
1387
1388 {
1389 // If it intersects, break out of the advancement loop.
1390 Move(ElementIt, LocalElementIt);
1391 return;
1392 }
1393 }
1394 }
1395 // Advance to the next node.
1396 NodeIt.Advance();
1397 if (!NodeIt.HasPendingNodes())
1398 {
1399 Move(ElementIt, LocalElementIt);
1400 return;
1401 }
1402 ProcessChildren();
1403 // The element iterator can't be assigned to, but it can be replaced by Move.
1404 Move(ElementIt, NodeIt.GetCurrentNode().GetElementIt());
1405 }
1406 }
1407 };
1408
1415 {
1416 AddElementToNode(Element, RootNode, RootNodeContext);
1417 }
1418
1424 {
1425 check(ElementId.IsValidId());
1426
1427 FNode* ElementIdNode = (FNode*)ElementId.Node;
1428
1429 // Remove the element from the node's element list.
1430 ElementIdNode->Elements.RemoveAtSwap(ElementId.ElementIndex);
1431
1432 SetOctreeMemoryUsage(this, TotalSizeBytes - sizeof(ElementType));
1433
1434 if (ElementId.ElementIndex < ElementIdNode->Elements.Num())
1435 {
1436 // Update the external element id for the element that was swapped into the vacated element index.
1437 SetElementId(ElementIdNode->Elements[ElementId.ElementIndex], ElementId);
1438 }
1439
1440 // Update the inclusive element counts for the nodes between the element and the root node,
1441 // and find the largest node that is small enough to collapse.
1442 const FNode* CollapseNode = NULL;
1443 for (const FNode* Node = ElementIdNode; Node; Node = Node->Parent)
1444 {
1445 --Node->InclusiveNumElements;
1446 if (Node->InclusiveNumElements < OctreeSemantics::MinInclusiveElementsPerNode)
1447 {
1448 CollapseNode = Node;
1449 }
1450 }
1451
1452 // Collapse the largest node that was pushed below the threshold for collapse by the removal.
1453 if (CollapseNode && !CollapseNode->bIsLeaf)
1454 {
1455 if (CollapseNode->Elements.Num() < (int32)CollapseNode->InclusiveNumElements)
1456 {
1457 CollapseNode->Elements.Reserve(CollapseNode->InclusiveNumElements);
1458
1459 // Gather the elements contained in this node and its children.
1461 {
1462 const FNode& ChildNode = ChildNodeIt.GetCurrentNode();
1463
1464 if (&ChildNode != CollapseNode)
1465 {
1466 // Child node will be collapsed so move the child's elements to the collapse node element list.
1467 for (ElementType& Element : ChildNode.Elements)
1468 {
1469 const int32 NewElementIndex = CollapseNode->Elements.Add(MoveTemp(Element));
1470
1471 // Update the external element id for the element that's being collapsed.
1473 }
1474 }
1475
1476 // Recursively visit all child nodes.
1478 {
1479 if (ChildNode.HasChild(ChildRef))
1480 {
1481 ChildNodeIt.PushChild(ChildRef);
1482 }
1483 }
1484 }
1485
1486 // Free the child nodes.
1488 {
1489 if (CollapseNode->Children[ChildRef.Index])
1490 {
1491 SetOctreeMemoryUsage(this, TotalSizeBytes - sizeof(*CollapseNode->Children[ChildRef.Index]));
1492 }
1493
1494 delete CollapseNode->Children[ChildRef.Index];
1495 CollapseNode->Children[ChildRef.Index] = NULL;
1496 }
1497 }
1498
1499 // Mark the node as a leaf.
1500 CollapseNode->bIsLeaf = true;
1501 }
1502 }
1503
1504
1505 void Destroy()
1506 {
1507 RootNode.~FNode();
1508 new (&RootNode) FNode(NULL);
1509
1510 // this looks a bit @hacky, but FNode's destructor doesn't
1511 // update TotalSizeBytes so better to set it to 0 than
1512 // not do nothing with it (would contain obviously false value)
1513 SetOctreeMemoryUsage(this, 0);
1514 }
1515
1517 [[nodiscard]] ElementType& GetElementById(FOctreeElementId ElementId)
1518 {
1519 check(ElementId.IsValidId());
1520 FNode* ElementIdNode = (FNode*)ElementId.Node;
1521 return ElementIdNode->Elements[ElementId.ElementIndex];
1522 }
1523
1525 [[nodiscard]] const ElementType& GetElementById(FOctreeElementId ElementId) const
1526 {
1527 check(ElementId.IsValidId());
1528 FNode* ElementIdNode = (FNode*)ElementId.Node;
1529 return ElementIdNode->Elements[ElementId.ElementIndex];
1530 }
1531
1534 {
1535 return ElementId.IsValidId()
1536 && ElementId.ElementIndex != INDEX_NONE
1537 && ElementId.ElementIndex < ((FNode*)ElementId.Node)->Elements.Num();
1538 };
1539
1541 void DumpStats() const
1542 {
1543 int32 NumNodes = 0;
1544 int32 NumLeaves = 0;
1545 int32 NumElements = 0;
1548
1549 for (TConstIterator<> NodeIt(*this); NodeIt.HasPendingNodes(); NodeIt.Advance())
1550 {
1551 const FNode& CurrentNode = NodeIt.GetCurrentNode();
1552 const int32 CurrentNodeElementCount = CurrentNode.GetElementCount();
1553
1554 NumNodes++;
1555 if (CurrentNode.IsLeaf())
1556 {
1557 NumLeaves++;
1558 }
1559
1560 NumElements += CurrentNodeElementCount;
1562
1564 {
1566 }
1568
1570 {
1571 if (CurrentNode.HasChild(ChildRef))
1572 {
1573 NodeIt.PushChild(ChildRef);
1574 }
1575 }
1576 }
1577
1578 UE_LOG(LogGenericOctree, Log, TEXT("Octree overview:"));
1579 UE_LOG(LogGenericOctree, Log, TEXT("\t%i nodes"), NumNodes);
1580 UE_LOG(LogGenericOctree, Log, TEXT("\t%i leaves"), NumLeaves);
1581 UE_LOG(LogGenericOctree, Log, TEXT("\t%i elements"), NumElements);
1582 UE_LOG(LogGenericOctree, Log, TEXT("\t%i >= elements per node"), MaxElementsPerNode);
1583 UE_LOG(LogGenericOctree, Log, TEXT("Octree node element distribution:"));
1584 for (int32 i = 0; i < NodeElementDistribution.Num(); i++)
1585 {
1586 if (NodeElementDistribution[i] > 0)
1587 {
1588 UE_LOG(LogGenericOctree, Log, TEXT("\tElements: %3i, Nodes: %3i"), i, NodeElementDistribution[i]);
1589 }
1590 }
1591 }
1592
1593
1595 {
1596 return TotalSizeBytes;
1597 }
1598
1600 {
1601 const int32 ClampedLevel = FMath::Clamp<uint32>(Level, 0, OctreeSemantics::MaxNodeDepth);
1602 return RootNodeContext.Bounds.Extent.X * FMath::Pow((1.0f + 1.0f / (FReal)FOctreeNodeContext::LoosenessDenominator) / 2.0f, FReal(ClampedLevel));
1603 }
1604
1606 {
1607 return RootNodeContext.Bounds;
1608 }
1609
1611 {
1612 RootNode.ShrinkElements();
1613 }
1614
1621 void ApplyOffset(const FVector& InOffset, bool bGlobalOctree)
1622 {
1623 // Shift elements
1624 RootNode.ApplyOffset(InOffset);
1625
1626 // Make a local copy of all nodes
1627 FNode OldRootNode = RootNode;
1628
1629 // Assign to root node a NULL node, so Destroy procedure will not delete child nodes
1630 RootNode = FNode(nullptr);
1631 // Call destroy to clean up octree
1632 Destroy();
1633
1634 if (!bGlobalOctree)
1635 {
1636 RootNodeContext.Bounds.Center += FVector4(InOffset, 0.0f);
1637 }
1638
1639 // Add all elements from a saved nodes to a new empty octree
1640 for (TConstIterator<> NodeIt(OldRootNode, RootNodeContext); NodeIt.HasPendingNodes(); NodeIt.Advance())
1641 {
1642 const auto& CurrentNode = NodeIt.GetCurrentNode();
1643
1645 {
1646 if (CurrentNode.HasChild(ChildRef))
1647 {
1648 NodeIt.PushChild(ChildRef);
1649 }
1650 }
1651
1652 for (auto ElementIt = CurrentNode.GetElementIt(); ElementIt; ++ElementIt)
1653 {
1654 AddElement(*ElementIt);
1655 }
1656 }
1657
1658 // Saved nodes will be deleted on scope exit
1659 }
1660
1661
1664 : RootNode(NULL)
1665 , RootNodeContext(FBoxCenterAndExtent(InOrigin, FVector(InExtent, InExtent, InExtent)), 0, 0)
1666 , MinLeafExtent(InExtent* FMath::Pow((1.0f + 1.0f / (FReal)FOctreeNodeContext::LoosenessDenominator) / 2.0f, FReal(OctreeSemantics::MaxNodeDepth)))
1667 , TotalSizeBytes(0)
1668 {
1669 }
1670
1672 TOctree_DEPRECATED() : RootNode(nullptr)
1673 {
1675 }
1676
1677private:
1678
1680 FNode RootNode;
1681
1683 FOctreeNodeContext RootNodeContext;
1684
1686 FReal MinLeafExtent;
1687
1690 void SetOctreeMemoryUsage(TOctree_DEPRECATED<ElementType, OctreeSemantics>* Octree, int32 NewSize)
1691 {
1692 Octree->TotalSizeBytes = NewSize;
1693 }
1694
1695 SIZE_T TotalSizeBytes;
1696
1698 void AddElementToNode(
1700 const FNode& InNode,
1702 )
1703 {
1704 const FBoxCenterAndExtent ElementBounds(OctreeSemantics::GetBoundingBox(Element));
1705
1706 for (TConstIterator<TInlineAllocator<1> > NodeIt(InNode, InContext); NodeIt.HasPendingNodes(); NodeIt.Advance())
1707 {
1708 const FNode& Node = NodeIt.GetCurrentNode();
1710 const bool bIsLeaf = Node.IsLeaf();
1711
1712 bool bAddElementToThisNode = false;
1713
1714 // Increment the number of elements included in this node and its children.
1715 Node.InclusiveNumElements++;
1716
1717 if (bIsLeaf)
1718 {
1719 // If this is a leaf, check if adding this element would turn it into a node by overflowing its element list.
1720 if (Node.Elements.Num() + 1 > OctreeSemantics::MaxElementsPerLeaf && Context.Bounds.Extent.X > MinLeafExtent)
1721 {
1722 // Copy the leaf's elements, remove them from the leaf, and turn it into a node.
1724 Exchange(ChildElements, Node.Elements);
1725 SetOctreeMemoryUsage(this, TotalSizeBytes - ChildElements.Num() * sizeof(ElementType));
1726 Node.InclusiveNumElements = 0;
1727
1728 // Allow elements to be added to children of this node.
1729 Node.bIsLeaf = false;
1730
1731 // Re-add all of the node's child elements, potentially creating children of this node for them.
1732 for (ElementConstIt ElementIt(ChildElements); ElementIt; ++ElementIt)
1733 {
1734 AddElementToNode(*ElementIt, Node, Context);
1735 }
1736
1737 // Add the element to this node.
1738 AddElementToNode(Element, Node, Context);
1739 return;
1740 }
1741 else
1742 {
1743 // If the leaf has room for the new element, simply add it to the list.
1744 bAddElementToThisNode = true;
1745 }
1746 }
1747 else
1748 {
1749 // If this isn't a leaf, find a child that entirely contains the element.
1750 const FOctreeChildNodeRef ChildRef = Context.GetContainingChild(ElementBounds);
1751 if (ChildRef.IsNULL())
1752 {
1753 // If none of the children completely contain the element, add it to this node directly.
1754 bAddElementToThisNode = true;
1755 }
1756 else
1757 {
1758 // Create the child node if it hasn't been created yet.
1759 if (!Node.Children[ChildRef.Index])
1760 {
1761 Node.Children[ChildRef.Index] = new typename TOctree_DEPRECATED<ElementType, OctreeSemantics>::FNode(&Node);
1762 SetOctreeMemoryUsage(this, TotalSizeBytes + sizeof(*Node.Children[ChildRef.Index]));
1763 }
1764
1765 // Push the node onto the stack to visit.
1766 NodeIt.PushChild(ChildRef);
1767 }
1768 }
1769
1771 {
1772 // Add the element to this node.
1773 new(Node.Elements) ElementType(Element);
1774
1775 SetOctreeMemoryUsage(this, TotalSizeBytes + sizeof(ElementType));
1776
1777 // Set the element's ID.
1778 SetElementId(Element, FOctreeElementId(&Node, Node.Elements.Num() - 1));
1779 return;
1780 }
1781 }
1782
1784 TEXT("Failed to find an octree node for an element with bounds (%f,%f,%f) +/- (%f,%f,%f)!"),
1785 ElementBounds.Center.X,
1786 ElementBounds.Center.Y,
1787 ElementBounds.Center.Z,
1788 ElementBounds.Extent.X,
1789 ElementBounds.Extent.Y,
1790 ElementBounds.Extent.Z
1791 );
1792 }
1793
1794 // Concept definition for the new octree semantics, which adds a new TOctree parameter
1795 struct COctreeSemanticsV2
1796 {
1797 template<typename Semantics>
1798 auto Requires(typename Semantics::FOctree& OctreeInstance, const ElementType& Element, FOctreeElementId Id)
1799 -> decltype(Semantics::SetElementId(OctreeInstance, Element, Id));
1800 };
1801
1802 // Calls the V2 version if it's supported or the old version if it's not
1803 template <typename Semantics>
1804 void SetOctreeSemanticsElementId(const ElementType& Element, FOctreeElementId Id)
1805 {
1807 {
1808 Semantics::SetElementId(*this, Element, Id);
1809 }
1810 else
1811 {
1812 Semantics::SetElementId(Element, Id);
1813 }
1814 }
1815
1816protected:
1817 // redirects SetElementId call to the proper implementation
1818 void SetElementId(const ElementType& Element, FOctreeElementId Id)
1819 {
1821 }
1822};
1823
1824template<typename ElementType, typename OctreeSemantics>
1825class UE_DEPRECATED(4.26, "The old Octree is deprecated use TOctree2.") TOctree : public TOctree_DEPRECATED<ElementType, OctreeSemantics>
1826{
1827public:
1829 {
1830 }
1831
1832 TOctree() : TOctree_DEPRECATED<ElementType, OctreeSemantics>()
1833 {
1834 }
1835};
1836
1837#include "Math/GenericOctree.inl" // IWYU pragma: export
1838
1839#include <stddef.h> // IWYU pragma: export
#define NULL
Definition oodle2base.h:134
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
void EnsureRetrievingVTablePtrDuringCtor(const TCHAR *CtorSignature)
Definition CoreMisc.cpp:436
FPlatformTypes::int8 int8
An 8-bit signed integer.
Definition Platform.h:1121
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
#define PLATFORM_CACHE_LINE_SIZE
Definition Platform.h:938
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
return true
Definition ExternalRpcRegistry.cpp:601
#define X(Name, Desc)
Definition FormatStringSan.h:47
#define FOREACH_OCTREE_CHILD_NODE(ChildRef)
Definition GenericOctree.h:35
#define FVector
Definition IOSSystemIncludes.h:8
#define DECLARE_LOG_CATEGORY_EXTERN(CategoryName, DefaultVerbosity, CompileTimeVerbosity)
Definition LogMacros.h:361
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
UE::Math::TBox< double > FBox
Definition MathFwd.h:55
UE::Math::TVector4< double > FVector4
Definition MathFwd.h:49
@ Num
Definition MetalRHIPrivate.h:234
FORCEINLINE VectorRegister4Float VectorSubtract(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:731
FORCEINLINE uint32 VectorAnyGreaterThan(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1917
FORCEINLINE VectorRegister4Float MakeVectorRegister(uint32 X, uint32 Y, uint32 Z, uint32 W)
Definition UnrealMathFPU.h:195
FORCEINLINE VectorRegister4Float VectorSetFloat1(float F)
Definition UnrealMathFPU.h:518
FORCEINLINE VectorRegister4Int VectorIntLoad1(const void *Ptr)
Definition UnrealMathFPU.h:2609
FORCEINLINE VectorRegister4Float VectorMultiply(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:758
FORCEINLINE VectorRegister4Float VectorLoadFloat1(const float *Ptr)
Definition UnrealMathFPU.h:468
VectorRegister4Float VectorLoadAligned(const float *Ptr)
Definition UnrealMathFPU.h:451
FORCEINLINE VectorRegister4Float VectorSelect(const VectorRegister4Float &Mask, const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:1105
FORCEINLINE VectorRegister4Int VectorIntCompareEQ(const VectorRegister4Int &A, const VectorRegister4Int &B)
Definition UnrealMathFPU.h:2356
FORCEINLINE VectorRegister4Float VectorSet_W0(const VectorRegister4Float &Vec)
Definition UnrealMathFPU.h:1391
FORCEINLINE VectorRegister4Float VectorAbs(const VectorRegister4Float &Vec)
Definition UnrealMathFPU.h:661
FORCEINLINE VectorRegister4Float VectorAdd(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:704
void VectorStoreAligned(const VectorRegister4Float &Vec, float *Ptr)
Definition UnrealMathFPU.h:534
FORCEINLINE VectorRegister4Int VectorIntAnd(const VectorRegister4Int &A, const VectorRegister4Int &B)
Definition UnrealMathFPU.h:2308
FORCEINLINE VectorRegister4Float VectorLoadFloat3_W0(const float *Ptr)
VectorLoadFloat3_W0.
Definition UnrealMathVectorCommon.h.inl:129
void Move(T &A, typename TMoveSupportTraits< T >::Copy B)
Definition UnrealTemplate.h:24
UE_REWRITE constexpr void Exchange(T &A, T &B)
Definition UnrealTemplate.h:627
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32 Size
Definition VulkanMemory.cpp:4034
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition GenericOctree.h:42
friend bool Intersect(const UE::Math::TBoxSphereBounds< FReal, TExtent > &A, const FBoxCenterAndExtent &B)
Definition GenericOctree.h:112
FBox GetBox() const
Definition GenericOctree.h:84
FVector4 Center
Definition GenericOctree.h:46
FVector4 Extent
Definition GenericOctree.h:47
FBoxCenterAndExtent(const FVector &InCenter, const FVector &InExtent)
Definition GenericOctree.h:53
FBoxCenterAndExtent(const UE::Math::TBoxSphereBounds< FReal, TExtent > &BoxSphere)
Definition GenericOctree.h:69
FBoxCenterAndExtent(const float PositionRadius[4])
Definition GenericOctree.h:77
FBoxCenterAndExtent(const FBox &Box)
Definition GenericOctree.h:59
FVector4::FReal FReal
Definition GenericOctree.h:44
friend bool Intersect(const float A[4], const FBoxCenterAndExtent &B)
Definition GenericOctree.h:130
friend bool Intersect(const FBoxCenterAndExtent &A, const FBoxCenterAndExtent &B)
Definition GenericOctree.h:94
FBoxCenterAndExtent()
Definition GenericOctree.h:50
Definition GenericOctree.h:146
UE_FORCEINLINE_HINT void SetNULL()
Definition GenericOctree.h:178
UE_FORCEINLINE_HINT void Advance()
Definition GenericOctree.h:167
FOctreeChildNodeRef(int8 InX, int8 InY, int8 InZ)
Definition GenericOctree.h:151
UE_FORCEINLINE_HINT int32 Y() const
Definition GenericOctree.h:188
int8 Index
Definition GenericOctree.h:148
UE_FORCEINLINE_HINT int32 X() const
Definition GenericOctree.h:183
FOctreeChildNodeRef(int8 InIndex=0)
Definition GenericOctree.h:160
UE_FORCEINLINE_HINT bool IsNULL() const
Definition GenericOctree.h:173
UE_FORCEINLINE_HINT int32 Z() const
Definition GenericOctree.h:193
Definition GenericOctree.h:201
FOctreeChildNodeSubset()
Definition GenericOctree.h:233
uint32 ChildBits
Definition GenericOctree.h:226
bool Contains(FOctreeChildNodeRef ChildRef) const
Definition GenericOctree.inl:20
uint32 PositiveChildBits
Definition GenericOctree.h:219
uint32 NegativeChildBits
Definition GenericOctree.h:222
FOctreeChildNodeSubset(FOctreeChildNodeRef ChildRef)
Definition GenericOctree.h:238
uint32 bPositiveY
Definition GenericOctree.h:209
uint32 bNegativeZ
Definition GenericOctree.h:213
uint32 bNegativeX
Definition GenericOctree.h:211
uint32 AllBits
Definition GenericOctree.h:229
uint32 bPositiveX
Definition GenericOctree.h:208
uint32 bNegativeY
Definition GenericOctree.h:212
uint32 bPositiveZ
Definition GenericOctree.h:210
Definition GenericOctreePublic.h:15
bool IsValidId() const
Definition GenericOctreePublic.h:28
Definition GenericOctreePublic.h:68
bool IsValidId() const
Definition GenericOctreePublic.h:81
Definition GenericOctree.h:252
FOctreeNodeContext(const FBoxCenterAndExtent &InBounds, uint32 InInCullBits, uint32 InOutCullBits)
Definition GenericOctree.h:299
FOctreeNodeContext GetChildContext(FOctreeChildNodeRef ChildRef) const
Definition GenericOctree.h:326
uint32 OutCullBits
Definition GenericOctree.h:273
FOctreeChildNodeRef GetContainingChild(const FBoxCenterAndExtent &BoundingBox) const
Definition GenericOctree.inl:55
FOctreeNodeContext(uint32 InInCullBits, uint32 InOutCullBits)
Definition GenericOctree.h:280
FOctreeNodeContext GetChildContext(FOctreeChildNodeRef ChildRef, uint32 InInCullBits, uint32 InOutCullBits) const
Definition GenericOctree.h:349
FReal ChildCenterOffset
Definition GenericOctree.h:267
FOctreeNodeContext(const FBoxCenterAndExtent &InBounds)
Definition GenericOctree.h:287
void GetChildContext(FOctreeChildNodeRef ChildRef, FOctreeNodeContext *ChildContext) const
Definition GenericOctree.h:336
FOctreeNodeContext()
Definition GenericOctree.h:276
VectorRegister GetChildOffsetVec(int i) const
Definition GenericOctree.h:312
@ LoosenessDenominator
Definition GenericOctree.h:258
FReal ChildExtent
Definition GenericOctree.h:264
FVector4::FReal FReal
Definition GenericOctree.h:255
FBoxCenterAndExtent Bounds
Definition GenericOctree.h:261
uint32 InCullBits
Definition GenericOctree.h:270
FOctreeChildNodeSubset GetIntersectingChildren(const FBoxCenterAndExtent &BoundingBox) const
Definition GenericOctree.inl:27
Definition ContainerAllocationPolicies.h:447
Definition ArrayView.h:139
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Last(SizeType IndexFromTheEnd=0) UE_LIFETIMEBOUND
Definition Array.h:1263
void RemoveAt(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2083
UE_NODEBUG UE_FORCEINLINE_HINT void Push(ElementType &&Item)
Definition Array.h:1224
void Reset(SizeType NewSize=0)
Definition Array.h:2246
SizeType AddDefaulted()
Definition Array.h:2795
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT SIZE_T GetAllocatedSize(void) const
Definition Array.h:1059
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
UE_FORCEINLINE_HINT void Shrink()
Definition Array.h:1278
SizeType Insert(std::initializer_list< ElementType > InitList, const SizeType InIndex)
Definition Array.h:1875
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition Array.h:64
Definition GenericOctree.h:378
FBoxCenterAndExtent GetRootBounds() const
Definition GenericOctree.h:988
void Destroy()
Definition GenericOctree.h:890
FOctreeElementId2 FindFirstElementWithBoundsTest(const FBoxCenterAndExtent &BoxBounds, const IterateBoundsFunc &Func) const
Definition GenericOctree.h:800
void FindNearbyElements(const FVector &Position, const IterateBoundsFunc &Func) const
Definition GenericOctree.h:811
void FindElementsWithBoundsTest(const FBoxCenterAndExtent &BoxBounds, const IterateBoundsFunc &Func) const
Definition GenericOctree.h:788
void SetElementId(const ElementType &Element, FOctreeElementId2 Id)
Definition GenericOctree.h:1073
TOctree2(const FVector &InOrigin, FVector::FReal InExtent)
Definition GenericOctree.h:1031
void ShrinkElements()
Definition GenericOctree.h:993
ElementType & GetElementById(FOctreeElementId2 ElementId)
Definition GenericOctree.h:901
void AddElement(typename TCallTraits< ElementType >::ConstReference Element)
Definition GenericOctree.h:821
void RemoveElement(FOctreeElementId2 ElementId)
Definition GenericOctree.h:832
bool IsValidElementId(FOctreeElementId2 ElementId) const
Definition GenericOctree.h:916
const ElementType & GetElementById(FOctreeElementId2 ElementId) const
Definition GenericOctree.h:907
TOctree2()
Definition GenericOctree.h:1040
void FindAllElements(const IterateAllElementsFunc &Func) const
Definition GenericOctree.h:743
SIZE_T GetSizeBytes() const
Definition GenericOctree.h:974
FReal GetNodeLevelExtent(int32 Level) const
Definition GenericOctree.h:982
uint32 FNodeIndex
Definition GenericOctree.h:381
void FindElementsWithPredicate(const PredicateFunc &Predicate, const IterateFunc &Func) const
Definition GenericOctree.h:771
int32 GetNumNodes() const
Definition GenericOctree.h:733
void FindNodesWithPredicate(const PredicateFunc &Predicate, const IterateFunc &Func) const
Definition GenericOctree.h:760
void DumpStats() const
Definition GenericOctree.h:931
FVector::FReal FReal
Definition GenericOctree.h:382
void ApplyOffset(const FVector &InOffset, bool bGlobalOctree=false)
Definition GenericOctree.h:1007
TArrayView< const ElementType > GetElementsForNode(FNodeIndex NodeIndex) const
Definition GenericOctree.h:925
Definition GenericOctree.h:1196
FNodeReference()
Definition GenericOctree.h:1203
const FNode * Node
Definition GenericOctree.h:1199
FNodeReference(const FNode *InNode, const FOctreeNodeContext &InContext)
Definition GenericOctree.h:1209
FOctreeNodeContext Context
Definition GenericOctree.h:1200
Definition GenericOctree.h:1091
UE_FORCEINLINE_HINT FNode * GetChild(FOctreeChildNodeRef ChildRef) const
Definition GenericOctree.h:1130
FNode(const FNode *InParent)
Definition GenericOctree.h:1097
UE_FORCEINLINE_HINT bool HasChild(FOctreeChildNodeRef ChildRef) const
Definition GenericOctree.h:1126
UE_FORCEINLINE_HINT int32 GetInclusiveElementCount() const
Definition GenericOctree.h:1138
UE_FORCEINLINE_HINT ElementConstIt GetElementIt() const
Definition GenericOctree.h:1118
~FNode()
Definition GenericOctree.h:1109
UE_FORCEINLINE_HINT const ElementArrayType & GetElements() const
Definition GenericOctree.h:1142
UE_FORCEINLINE_HINT bool IsLeaf() const
Definition GenericOctree.h:1122
void ShrinkElements()
Definition GenericOctree.h:1146
void ApplyOffset(const FVector &InOffset)
Definition GenericOctree.h:1158
UE_FORCEINLINE_HINT int32 GetElementCount() const
Definition GenericOctree.h:1134
Definition GenericOctree.h:1299
const ElementType & GetCurrentElement() const
Definition GenericOctree.h:1326
bool HasPendingElements() const
Definition GenericOctree.h:1310
TConstElementBoxIterator(const TOctree_DEPRECATED &Tree, const FBoxCenterAndExtent &InBoundingBox)
Definition GenericOctree.h:1316
void Advance()
Definition GenericOctree.h:1303
Definition GenericOctree.h:1221
void Advance()
Definition GenericOctree.h:1248
const FOctreeNodeContext & GetCurrentContext() const
Definition GenericOctree.h:1282
TConstIterator(const TOctree_DEPRECATED &Tree)
Definition GenericOctree.h:1268
TConstIterator(const FNode &Node, const FOctreeNodeContext &Context)
Definition GenericOctree.h:1273
void PushChild(FOctreeChildNodeRef ChildRef)
Definition GenericOctree.h:1225
void PushChild(FOctreeChildNodeRef ChildRef, const FOctreeNodeContext &Context)
Definition GenericOctree.h:1241
const FNode & GetCurrentNode() const
Definition GenericOctree.h:1278
bool HasPendingNodes() const
Definition GenericOctree.h:1262
void PushChild(FOctreeChildNodeRef ChildRef, uint32 FullyInsideView, uint32 FullyOutsideView)
Definition GenericOctree.h:1232
Definition GenericOctree.h:1082
FVector4::FReal FReal
Definition GenericOctree.h:1085
TOctree_DEPRECATED(const FVector &InOrigin, FReal InExtent)
Definition GenericOctree.h:1663
ElementType & GetElementById(FOctreeElementId ElementId)
Definition GenericOctree.h:1517
FReal GetNodeLevelExtent(int32 Level) const
Definition GenericOctree.h:1599
SIZE_T GetSizeBytes() const
Definition GenericOctree.h:1594
FBoxCenterAndExtent GetRootBounds() const
Definition GenericOctree.h:1605
const ElementType & GetElementById(FOctreeElementId ElementId) const
Definition GenericOctree.h:1525
void Destroy()
Definition GenericOctree.h:1505
void ShrinkElements()
Definition GenericOctree.h:1610
void RemoveElement(FOctreeElementId ElementId)
Definition GenericOctree.h:1423
void ApplyOffset(const FVector &InOffset, bool bGlobalOctree)
Definition GenericOctree.h:1621
bool IsValidElementId(FOctreeElementId ElementId) const
Definition GenericOctree.h:1533
void DumpStats() const
Definition GenericOctree.h:1541
ElementArrayType::TConstIterator ElementConstIt
Definition GenericOctree.h:1087
TArray< ElementType, typename OctreeSemantics::ElementAllocator > ElementArrayType
Definition GenericOctree.h:1086
void SetElementId(const ElementType &Element, FOctreeElementId Id)
Definition GenericOctree.h:1818
TOctree_DEPRECATED()
Definition GenericOctree.h:1672
void AddElement(typename TTypeTraits< ElementType >::ConstInitType Element)
Definition GenericOctree.h:1414
Definition ContainerAllocationPolicies.h:894
@ Element
Definition Visu.h:18
float v
Definition radaudio_mdct.cpp:62
U16 Index
Definition radfft.cpp:71
static FORCEINLINE void Prefetch(const void *Ptr)
Definition GenericPlatformMisc.h:1443
Definition UnrealMathUtility.h:270
const T & ConstReference
Definition UnrealTypeTraits.h:274
TCallTraits< T >::ParamType ConstInitType
Definition UnrealTypeTraits.h:336
Definition BoxSphereBounds.h:25
T W
Definition Vector4.h:52
T X
Definition Vector4.h:43
double FReal
Definition Vector4.h:36
static CORE_API const TVector< double > ZeroVector
Definition Vector.h:79
double FReal
Definition Vector.h:55
Definition UnrealMathFPU.h:42
Definition UnrealMathFPU.h:20
Definition UnrealMathFPU.h:28