Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
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"
10#include "Containers/ArrayView.h"
11#include "Containers/ContainerAllocationPolicies.h"
12#include "CoreGlobals.h"
13#include "CoreMinimal.h"
14#include "CoreTypes.h"
16#include "HAL/PlatformMisc.h"
17#include "Logging/LogCategory.h"
18#include "Logging/LogMacros.h"
19#include "Math/Box.h"
20#include "Math/BoxSphereBounds.h"
21#include "Math/MathFwd.h"
22#include "Math/UnrealMathSSE.h"
23#include "Math/UnrealMathUtility.h"
24#include "Math/Vector.h"
25#include "Math/Vector4.h"
26#include "Math/VectorRegister.h"
27#include "Misc/AssertionMacros.h"
28#include "Templates/EnableIf.h"
29#include "Templates/Models.h"
30#include "Templates/UnrealTemplate.h"
31#include "Templates/UnrealTypeTraits.h"
32#include "Trace/Detail/Channel.h"
33
34/** A concise iteration over the children of an octree node. */
35#define FOREACH_OCTREE_CHILD_NODE(ChildRef)
36 for(FOctreeChildNodeRef ChildRef(0);!ChildRef.IsNULL();ChildRef.Advance())
37
39
40/** An unquantized bounding box. */
41class FBoxCenterAndExtent
42{
43public:
44 using FReal = FVector4::FReal;
45
46 FVector4 Center; // LWC_TODO: Case for FVector4d
47 FVector4 Extent;
48
49 /** Default constructor. */
50 FBoxCenterAndExtent() {}
51
52 /** Initialization constructor. */
53 FBoxCenterAndExtent(const FVector& InCenter,const FVector& InExtent)
54 : Center(InCenter,0)
55 , Extent(InExtent,0)
56 {}
57
58 /** FBox conversion constructor. */
59 FBoxCenterAndExtent(const FBox& Box)
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
67 /** FBoxSphereBounds conversion constructor. */
68 template<typename TExtent>
69 explicit FBoxCenterAndExtent(const UE::Math::TBoxSphereBounds<FReal, TExtent>& BoxSphere)
70 {
71 Center = BoxSphere.Origin;
72 Extent = FVector(BoxSphere.BoxExtent);
73 Center.W = Extent.W = 0;
74 }
75
76 /** Center - radius as four contiguous floats conversion constructor. */
77 explicit FBoxCenterAndExtent(const float PositionRadius[4])
78 {
79 Center = FVector4(PositionRadius[0],PositionRadius[1],PositionRadius[2], 0);
80 Extent = FVector4(PositionRadius[3],PositionRadius[3],PositionRadius[3], 0);
81 }
82
83 /** Converts to a FBox. */
84 FBox GetBox() const
85 {
86 return FBox(Center - Extent,Center + Extent);
87 }
88
89 /**
90 * Determines whether two boxes intersect.
91 * Warning: this operates on the W of the bounds positions!
92 * @return true if the boxes intersect, or false.
93 */
94 friend FORCEINLINE bool Intersect(const FBoxCenterAndExtent& A,const FBoxCenterAndExtent& B)
95 {
96 // CenterDifference is the vector between the centers of the bounding boxes.
97 const VectorRegister CenterDifference = VectorAbs(VectorSubtract(VectorLoadAligned(&A.Center),VectorLoadAligned(&B.Center)));
98
99 // CompositeExtent is the extent of the bounding box which is the convolution of A with B.
100 const VectorRegister CompositeExtent = VectorAdd(VectorLoadAligned(&A.Extent),VectorLoadAligned(&B.Extent));
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.
104 return VectorAnyGreaterThan(CenterDifference,CompositeExtent) == false;
105 }
106 /**
107 * Determines whether two boxes intersect.
108 * Warning: this operates on the W of the bounds positions!
109 * @return true if the boxes intersect, or false.
110 */
111 template<typename TExtent>
112 friend FORCEINLINE bool Intersect(const UE::Math::TBoxSphereBounds<FReal, TExtent>& A,const FBoxCenterAndExtent& B)
113 {
114 // CenterDifference is the vector between the centers of the bounding boxes.
115 const VectorRegister CenterDifference = VectorAbs(VectorSubtract(VectorLoadFloat3_W0(&A.Origin),VectorLoadAligned(&B.Center)));
116
117 // CompositeExtent is the extent of the bounding box which is the convolution of A with B.
118 const VectorRegister CompositeExtent = VectorAdd(VectorLoadFloat3_W0(&A.BoxExtent),VectorLoadAligned(&B.Extent));
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.
122 return VectorAnyGreaterThan(CenterDifference,CompositeExtent) == false;
123 }
124 /**
125 * Determines whether two boxes intersect.
126 * Warning: this operates on the W of the bounds positions!
127 * @param A box given in center - radius form as four contiguous floats
128 * @return true if the boxes intersect, or false.
129 */
130 friend FORCEINLINE bool Intersect(const float A[4],const FBoxCenterAndExtent& B)
131 {
132 // CenterDifference is the vector between the centers of the bounding boxes.
133 const VectorRegister CenterDifference = VectorAbs(VectorSubtract(VectorLoadFloat3_W0(A),VectorLoadAligned(&B.Center)));
134
135 // CompositeExtent is the extent of the bounding box which is the convolution of A with B.
136 const VectorRegister CompositeExtent = VectorAdd(VectorSet_W0(VectorLoadFloat1(A+3)),VectorLoadAligned(&B.Extent));
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.
140 return VectorAnyGreaterThan(CenterDifference,CompositeExtent) == false;
141 }
142};
143
144/** A reference to a child of an octree node. */
146{
147public:
148 int8 Index;
149
150 /** Initialization constructor. */
151 FOctreeChildNodeRef(int8 InX, int8 InY, int8 InZ)
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
159 /** Initialized the reference with a child index. */
160 FOctreeChildNodeRef(int8 InIndex = 0)
161 : Index(InIndex)
162 {
163 checkSlow(Index < 8);
164 }
165
166 /** Advances the reference to the next child node. If this was the last node remain, Index will be 8 which represents null. */
168 {
169 ++Index;
170 }
171
172 /** @return true if the reference isn't set. */
173 FORCEINLINE bool IsNULL() const
174 {
175 return Index >= 8;
176 }
177
179 {
180 Index = 8;
181 }
182
183 FORCEINLINE int32 X() const
184 {
185 return (Index >> 0) & 1;
186 }
187
188 FORCEINLINE int32 Y() const
189 {
190 return (Index >> 1) & 1;
191 }
192
193 FORCEINLINE int32 Z() const
194 {
195 return (Index >> 2) & 1;
196 }
197};
198
199/** A subset of an octree node's children that intersect a bounding box. */
201{
202public:
203
204 union
205 {
206 struct
207 {
208 uint32 bPositiveX : 1;
209 uint32 bPositiveY : 1;
210 uint32 bPositiveZ : 1;
211 uint32 bNegativeX : 1;
212 uint32 bNegativeY : 1;
213 uint32 bNegativeZ : 1;
214 };
215
216 struct
217 {
218 /** Only the bits for the children on the positive side of the splits. */
220
221 /** Only the bits for the children on the negative side of the splits. */
223 };
224
225 /** All the bits corresponding to the child bits. */
226 uint32 ChildBits : 6;
227
228 /** All the bits used to store the subset. */
229 uint32 AllBits;
230 };
231
232 /** Initializes the subset to be empty. */
234 : AllBits(0)
235 {}
236
237 /** Initializes the subset to contain a single node. */
239 : AllBits(0)
240 {
241 // The positive child bits correspond to the child index, and the negative to the NOT of the child index.
242 PositiveChildBits = ChildRef.Index;
243 NegativeChildBits = ~ChildRef.Index;
244 }
245
246 /** Determines whether the subset contains a specific node. */
247 bool Contains(FOctreeChildNodeRef ChildRef) const;
248};
249
250/** The context of an octree node, derived from the traversal of the tree. */
252{
253public:
254
256
257 /** The node bounds are expanded by their extent divided by LoosenessDenominator. */
258 enum { LoosenessDenominator = 16 };
259
260 /** The bounds of the node. */
262
263 /** The extent of the node's children. */
265
266 /** The offset of the childrens' centers from the center of this node. */
268
269 /** Bits used for culling, semantics left up to the caller (except that it is always set to zero at the root). This does not consume storage because it is leftover in the padding.*/
271
272 /** Bits used for culling, semantics left up to the caller (except that it is always set to zero at the root). This does not consume storage because it is leftover in the padding.*/
274
275 /** Default constructor. */
277 {}
278
279 /** Initialization constructor, this one is used when we done care about the box anymore */
280 FOctreeNodeContext(uint32 InInCullBits, uint32 InOutCullBits)
281 : InCullBits(InInCullBits)
282 , OutCullBits(InOutCullBits)
283 {
284 }
285
286 /** Initialization constructor. */
288 : Bounds(InBounds)
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;
292 const FReal LooseChildExtent = TightChildExtent * (1.0f + 1.0f / (FReal)LoosenessDenominator);
293
294 ChildExtent = LooseChildExtent;
295 ChildCenterOffset = Bounds.Extent.X - LooseChildExtent;
296 }
297
298 /** Initialization constructor. */
299 FOctreeNodeContext(const FBoxCenterAndExtent& InBounds, uint32 InInCullBits, uint32 InOutCullBits)
300 : Bounds(InBounds)
301 , InCullBits(InInCullBits)
302 , OutCullBits(InOutCullBits)
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;
306 const FReal LooseChildExtent = TightChildExtent * (1.0f + 1.0f / (FReal)LoosenessDenominator);
307
308 ChildExtent = LooseChildExtent;
309 ChildCenterOffset = Bounds.Extent.X - LooseChildExtent;
310 }
311
312 inline VectorRegister GetChildOffsetVec(int i) const
313 {
314 // LWC_TODO: not sure this is correct for VectorRegister = VectorRegister4Double
315 union MaskType { VectorRegister4Float v; VectorRegister4Int i;
317 MaskType()
318 : v(MakeVectorRegister(0.0f, 0.0f, 0.0f, 0.0f))
319 {}
320#endif
321 } Mask;
322
323 Mask.v = MakeVectorRegister(1u, 2u, 4u, 8u);
324 VectorRegister4Int X = VectorIntLoad1(&i);
325 VectorRegister4Int A = VectorIntAnd(X, Mask.i);
326 Mask.i = VectorIntCompareEQ(Mask.i, A);
327 return VectorSelect(Mask.v, VectorSetFloat1(ChildCenterOffset), VectorSetFloat1(-ChildCenterOffset));
328 }
329
330 /** Child node initialization constructor. */
332 {
333 FBoxCenterAndExtent LocalBounds;
334 VectorRegister ZeroW = MakeVectorRegister(1.0f, 1.0f, 1.0f, 0.0f);
335 VectorStoreAligned(VectorMultiply(ZeroW, VectorAdd(VectorLoadAligned(&Bounds.Center), GetChildOffsetVec(ChildRef.Index))), &(LocalBounds.Center.X));
336 VectorStoreAligned(VectorMultiply(ZeroW, VectorSetFloat1(ChildExtent)), &(LocalBounds.Extent.X));
337 return FOctreeNodeContext(LocalBounds);
338 }
339
340 /** Construct a child context given the child ref. Optimized to remove all LHS. */
341 inline void GetChildContext(FOctreeChildNodeRef ChildRef, FOctreeNodeContext* ChildContext) const
342 {
343 VectorRegister ZeroW = MakeVectorRegister(1.0f, 1.0f, 1.0f, 0.0f);
344 VectorStoreAligned(VectorMultiply(ZeroW, VectorAdd(VectorLoadAligned(&Bounds.Center), GetChildOffsetVec(ChildRef.Index))), &(ChildContext->Bounds.Center.X));
345 VectorStoreAligned(VectorMultiply(ZeroW, VectorSetFloat1(ChildExtent)), &(ChildContext->Bounds.Extent.X));
346
347 const FReal TightChildExtent = ChildExtent * 0.5f;
348 const FReal LooseChildExtent = TightChildExtent * (1.0f + 1.0f / (FReal)LoosenessDenominator);
349 ChildContext->ChildExtent = LooseChildExtent;
350 ChildContext->ChildCenterOffset = ChildExtent - LooseChildExtent;
351 }
352
353 /** Child node initialization constructor. */
354 inline FOctreeNodeContext GetChildContext(FOctreeChildNodeRef ChildRef, uint32 InInCullBits, uint32 InOutCullBits) const
355 {
356 FBoxCenterAndExtent LocalBounds;
357 VectorRegister ZeroW = MakeVectorRegister(1.0f, 1.0f, 1.0f, 0.0f);
358 VectorStoreAligned(VectorMultiply(ZeroW, VectorAdd(VectorLoadAligned(&Bounds.Center), GetChildOffsetVec(ChildRef.Index))), &(LocalBounds.Center.X));
359 VectorStoreAligned(VectorMultiply(ZeroW, VectorSetFloat1(ChildExtent)), &(LocalBounds.Extent.X));
360 return FOctreeNodeContext(LocalBounds, InInCullBits, InOutCullBits);
361 }
362 /**
363 * Determines which of the octree node's children intersect with a bounding box.
364 * @param BoundingBox - The bounding box to check for intersection with.
365 * @return A subset of the children's nodes that intersect the bounding box.
366 */
368
369 /**
370 * Determines which of the octree node's children contain the whole bounding box, if any.
371 * @param BoundingBox - The bounding box to check for intersection with.
372 * @return The octree's node that the bounding box is farthest from the outside edge of, or an invalid node ref if it's not contained
373 * by any of the children.
374 */
376};
377
379
380/** An octree. */
381template<typename ElementType,typename OctreeSemantics>
383{
384 using ElementArrayType = TArray<ElementType, typename OctreeSemantics::ElementAllocator>;
385public:
386 using FNodeIndex = uint32;
388
389private:
390 struct FNode
391 {
392 FNodeIndex ChildNodes = INDEX_NONE;
394
395 bool IsLeaf() const
396 {
397 return ChildNodes == INDEX_NONE;
398 }
399 };
400
404 TArray<ElementArrayType, TAlignedHeapAllocator<alignof(ElementArrayType)>> TreeElements;
405
407 {
408 struct FSpan
409 {
410 FNodeIndex Start;
411 FNodeIndex End;
412 };
413
415
416 public:
418 {
419 Reset();
420 }
421
422 void Push(FNodeIndex NodeIndex)
423 {
424 //find the index that points to our right side node
425 int Index = 1; //exclude the dummy
426 int Size = FreeList.Num() - 1;
427
428 //start with binary search for larger lists
429 while (Size > 32)
430 {
431 const int LeftoverSize = Size % 2;
432 Size = Size / 2;
433
434 const int CheckIndex = Index + Size;
435 const int IndexIfLess = CheckIndex + LeftoverSize;
436
438 }
439
440 //small size array optimization
441 int ArrayEnd = FMath::Min(Index + Size + 1, FreeList.Num());
442 while (Index < ArrayEnd)
443 {
445 {
446 break;
447 }
448 Index++;
449 }
450
451 //can we merge with the right node
452 if (Index < FreeList.Num() && FreeList[Index].End + 1 == NodeIndex)
453 {
455
456 //are we filling the gap between the left and right node
457 if (FreeList[Index - 1].Start - 1 == NodeIndex)
458 {
461 }
462 return;
463 }
464
465 //can we merge with the left node
466 if (FreeList[Index - 1].Start - 1 == NodeIndex)
467 {
469 return;
470 }
471
472 //we are node that could not be merged
474 }
475
476 FNodeIndex Pop()
477 {
478 FSpan& Span = FreeList.Last();
481 if (Span.Start == Span.End)
482 {
483 FreeList.Pop();
484 return Index;
485 }
486 else
487 {
488 Span.Start++;
489 return Index;
490 }
491 }
492
493 void Reset()
494 {
495 FreeList.Reset(1);
496 //push a dummy
498 }
499
500 int Num() const
501 {
502 //includes one dummy
503 return FreeList.Num() - 1;
504 }
505 };
506
508 /** The extent of a leaf at the maximum allowed depth of the tree. */
510
512 {
514 if (FreeList.Num())
515 {
516 Index = (FreeList.Pop() * 8) + 1;
517 }
518 else
519 {
524 }
525 return Index;
526 }
527
528 void FreeEightNodes(FNodeIndex Index)
529 {
530 checkSlow(Index != INDEX_NONE && Index != 0);
531 for (int8 i = 0; i < 8; i++)
532 {
533 TreeNodes[Index + i] = FNode();
534 checkSlow(TreeElements[Index + i].Num() == 0);
535 }
536 ParentLinks[(Index - 1) / 8] = INDEX_NONE;
537 //TODO shrink the TreeNodes as well as the TreeElements and ParentLinks to reduce high watermark memory footprint.
538 FreeList.Push((Index - 1) / 8);
539 }
540
541 void AddElementInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& ElementBounds, typename TCallTraits<ElementType>::ConstReference Element, ElementArrayType& TempElementStorage)
542 {
546 {
548 {
550
555
557 {
560 }
561
564 return;
565 }
566 else
567 {
569
571 return;
572 }
573 }
574 else
575 {
577 if (ChildRef.IsNULL())
578 {
581 return;
582 }
583 else
584 {
588 return;
589 }
590 }
591 }
592
593 void CollapseNodesInternal(FNodeIndex CurrentNodeIndex, ElementArrayType& CollapsedNodeElements)
594 {
597
599 {
601 for (int8 i = 0; i < 8; i++)
602 {
604 }
606 }
607 }
608
609 template<typename PredicateFunc, typename IterateFunc>
610 void FindNodesWithPredicateInternal(FNodeIndex ParentNodeIndex, FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const PredicateFunc& Predicate, const IterateFunc& Func) const
611 {
613 {
615 {
617
619 {
621 for (int8 i = 0; i < 8; i++)
622 {
624 }
625 }
626 }
627 }
628 }
629
630 template<typename IterateFunc>
631 void FindElementsWithBoundsTestInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& BoxBounds, const IterateFunc& Func) const
632 {
634 {
636 {
638 {
639 Func(Element);
640 }
641 }
642
644 {
647 for (int8 i = 0; i < 8; i++)
648 {
650 {
652 }
653 }
654 }
655 }
656 }
657
658 template<typename IterateFunc>
659 void FindFirstElementWithBoundsTestInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& BoxBounds, const IterateFunc& Func, bool& ContinueTraversal) const
660 {
662 {
664 {
667 {
669 }
670 }
671
673 {
676 for (int8 i = 0; i < 8; i++)
677 {
679 {
681 }
682 }
683 }
684 }
685 }
686
687 template<typename IterateFunc>
688 void FindNearbyElementsInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext& NodeContext, const FBoxCenterAndExtent& BoxBounds, const IterateFunc& Func) const
689 {
691 {
692 for (int Index = 0; Index < TreeElements[CurrentNodeIndex].Num(); Index++)
693 {
695 }
696
698 {
699 // Find the child of the current node, if any, that contains the current new point
701 if (!ChildRef.IsNULL())
702 {
704 // If the specified child node exists and contains any match, push it than process it
706 {
708 }
709 // If the child node doesn't is a match, it's not worth pursuing any further. In an attempt to find
710 // anything to match vs. the new point, process all of the children of the current octree node
711 else
712 {
713 for (int8 i = 0; i < 8; i++)
714 {
716 }
717 }
718 }
719 }
720 }
721 }
722public:
723
724 int32 GetNumNodes() const { return TreeNodes.Num(); }
725
726 /**
727 * this function will call the passed in function for all elements in the Octree in node by node in no specified order.
728 * @param Func - Function to call with each Element.
729 */
730 template<typename IterateAllElementsFunc>
731 inline void FindAllElements(const IterateAllElementsFunc& Func) const
732 {
734 {
736 {
737 Func(Element);
738 }
739 }
740 }
741
742 /**
743 * this function will traverse the Octree starting from the root in depth first order and the predicate can be used to implement custom culling for each node.
744 * @param Predicate - a Function when given the bounds of the currently traversed node that returns true if traversal should continue or false to skip that branch.
745 * @param Func - Function that will receive the node ID which can be stored and later used to get the elements using GetElementsForNode for all nodes that passed the predicate.
746 */
747 template<typename PredicateFunc, typename IterateFunc>
748 inline void FindNodesWithPredicate(const PredicateFunc& Predicate, const IterateFunc& Func) const
749 {
751 }
752
753 /**
754 * this function will traverse the Octree starting from the root in depth first order and the predicate can be used to implement custom culling for each node.
755 * @param Predicate - a Function when given the bounds of the currently traversed node that returns true if traversal should continue or false to skip that branch.
756 * @param Func - Function to call with each Element for nodes that passed the predicate.
757 */
758 template<typename PredicateFunc, typename IterateFunc>
759 inline void FindElementsWithPredicate(const PredicateFunc& Predicate, const IterateFunc& Func) const
760 {
762 {
764 {
766 }
767 });
768 }
769
770 /**
771 * this function will traverse the Octree using a fast box-box intersection this should be the preferred way of traversing the tree.
772 * @param BoxBounds - the bounds to test if a node is traversed or skipped.
773 * @param Func - Function to call with each Element for nodes that passed bounds test.
774 */
775 template<typename IterateBoundsFunc>
776 inline void FindElementsWithBoundsTest(const FBoxCenterAndExtent& BoxBounds, const IterateBoundsFunc& Func) const
777 {
779 }
780
781 /**
782 * this function will traverse the Octree using a fast box-box intersection and aborts traversal as soon as the Element function returns false.
783 * @param BoxBounds - the bounds to test if a node is traversed or skipped.
784 * @param Func - Function to call with each Element for nodes that passed bounds test.
785 */
786 template<typename IterateBoundsFunc>
787 inline void FindFirstElementWithBoundsTest(const FBoxCenterAndExtent& BoxBounds, const IterateBoundsFunc& Func) const
788 {
789 bool ContinueTraversal = true;
791 }
792
793 /**
794 * this function will traverse the Octree using a tryint to find nearby nodes that contain any elements.
795 * @param Position - the position to look nearby.
796 * @param Func - Function to call with each Element for nodes that passed bounds test.
797 */
798 template<typename IterateBoundsFunc>
799 inline void FindNearbyElements(const FVector& Position, const IterateBoundsFunc& Func) const
800 {
802 }
803
804
805 /**
806 * Adds an element to the octree.
807 * @param Element - The element to add.
808 */
809 inline void AddElement(typename TCallTraits<ElementType>::ConstReference Element)
810 {
814 }
815
816 /**
817 * Removes an element from the octree.
818 * @param ElementId - The element to remove from the octree.
819 */
820 inline void RemoveElement(FOctreeElementId2 ElementId)
821 {
823
824 // Remove the element from the node's element list.
826
828 {
829 // Update the external element id for the element that was swapped into the vacated element index.
831 }
832
834 {
835 // Update the inclusive element counts for the nodes between the element and the root node,
836 // and find the largest node that is small enough to collapse.
838 while (true)
839 {
842 {
844 }
845
846 if (NodeIndex == 0)
847 {
848 break;
849 }
850
851 NodeIndex = ParentLinks[(NodeIndex - 1) / 8];
852 }
853 }
854
855 // Collapse the largest node that was pushed below the threshold for collapse by the removal.
857 {
859 {
862 // Gather the elements contained in this node and its children.
865
867 {
868 // Update the external element id for the element that's being collapsed.
870 }
871
872 // Mark the node as a leaf.
874 }
875 }
876 }
877
878 /**
879 * this function resets the octree to empty.
880 */
881 void Destroy()
882 {
883 TreeNodes.Reset(1);
885 FreeList.Reset();
889 }
890
891 /** Accesses an octree element by ID. */
892 ElementType& GetElementById(FOctreeElementId2 ElementId)
893 {
895 }
896
897 /** Accesses an octree element by ID. */
898 const ElementType& GetElementById(FOctreeElementId2 ElementId) const
899 {
901 }
902
903 /**
904 * check if a FOctreeElementId2 is valid.
905 * @param ElementId - The ElementId to check.
906 */
907 bool IsValidElementId(FOctreeElementId2 ElementId) const
908 {
910 };
911
912 /**
913 * return all elements for a given node.
914 * @param NodeIndex - The the index of the node can be obtained using FindNodesWithPredicate.
915 */
917 {
918 return TreeElements[NodeIndex];
919 }
920
921 /** Writes stats for the octree to the log. */
922 void DumpStats() const
923 {
924 int32 NumNodes = 0;
925 int32 NumLeaves = 0;
926 int32 NumElements = 0;
929
930 FindNodesWithPredicateInternal(INDEX_NONE, 0, RootNodeContext, [](FNodeIndex /*ParentNodeIndex*/, FNodeIndex /*NodeIndex*/, const FBoxCenterAndExtent&) { return true; }, [&, this](FNodeIndex /*ParentNodeIndex*/, FNodeIndex NodeIndex, const FBoxCenterAndExtent&)
931 {
933
934 NumNodes++;
936 {
937 NumLeaves++;
938 }
939
942
944 {
946 }
948 });
949
950 UE_LOG(LogGenericOctree, Log, TEXT("Octree overview:"));
951 UE_LOG(LogGenericOctree, Log, TEXT("\t%i nodes"), NumNodes);
952 UE_LOG(LogGenericOctree, Log, TEXT("\t%i leaves"), NumLeaves);
953 UE_LOG(LogGenericOctree, Log, TEXT("\t%i elements"), NumElements);
954 UE_LOG(LogGenericOctree, Log, TEXT("\t%i >= elements per node"), MaxElementsPerNode);
955 UE_LOG(LogGenericOctree, Log, TEXT("Octree node element distribution:"));
956 for (int32 i = 0; i < NodeElementDistribution.Num(); i++)
957 {
958 if (NodeElementDistribution[i] > 0)
959 {
960 UE_LOG(LogGenericOctree, Log, TEXT("\tElements: %3i, Nodes: %3i"), i, NodeElementDistribution[i]);
961 }
962 }
963 }
964
965 SIZE_T GetSizeBytes() const
966 {
970 return TotalSizeBytes;
971 }
972
974 {
977 }
978
980 {
981 return RootNodeContext.Bounds;
982 }
983
985 {
987 {
989 }
990 }
991
992 /**
993 * Apply an arbitrary offset to all elements in the tree
994 * InOffset - offset to apply
995 * bGlobalOctree - hint that this octree is used as a boundless global volume,
996 * so only content will be shifted but not origin of the octree
997 */
998 void ApplyOffset(const FVector& InOffset, bool bGlobalOctree = false)
999 {
1002
1003 //collect all elements
1006 Destroy();
1007
1008 if (!bGlobalOctree)
1009 {
1011 }
1012
1013 // Offset & Add all elements from a saved nodes to a new empty octree
1015 {
1018 }
1019 }
1020
1021 /** Initialization constructor. */
1022 TOctree2(const FVector& InOrigin,FVector::FReal InExtent)
1025 {
1028 }
1029
1030 /** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */
1032 {
1035 }
1036
1037private:
1038
1039
1040 // Concept definition for the new octree semantics, which adds a new TOctree parameter
1042 {
1043 template<typename Semantics>
1046 };
1047
1048 // Function overload set which calls the V2 version if it's supported or the old version if it's not
1049 template <typename Semantics>
1051 {
1053 }
1054 template <typename Semantics>
1056 {
1057 Semantics::SetElementId(static_cast<typename Semantics::FOctree&>(*this), Element, Id);
1058 }
1059
1060protected:
1061 // redirects SetElementId call to the proper implementation
1062 void SetElementId(const ElementType& Element, FOctreeElementId2 Id)
1063 {
1065 }
1066};
1067
1068/** An octree. */
1069template<typename ElementType, typename OctreeSemantics>
1071{
1072public:
1073
1075 typedef TArray<ElementType, typename OctreeSemantics::ElementAllocator> ElementArrayType;
1077
1078 /** A node in the octree. */
1079 class FNode
1080 {
1081 public:
1082
1084
1085 /** Initialization constructor. */
1086 explicit FNode(const FNode* InParent)
1087 : Parent(InParent)
1089 , bIsLeaf(true)
1090 {
1092 {
1093 Children[ChildRef.Index] = NULL;
1094 }
1095 }
1096
1097 /** Destructor. */
1099 {
1101 {
1102 delete Children[ChildRef.Index];
1103 }
1104 }
1105
1106 // Accessors.
1108 FORCEINLINE bool IsLeaf() const { return bIsLeaf; }
1110 {
1112 }
1114 {
1115 return Children[ChildRef.Index];
1116 }
1118 {
1119 return Elements.Num();
1120 }
1122 {
1123 return InclusiveNumElements;
1124 }
1126 {
1127 return Elements;
1128 }
1130 {
1131 Elements.Shrink();
1133 {
1134 if (Children[ChildRef.Index])
1135 {
1137 }
1138 }
1139 }
1140
1141 void ApplyOffset(const FVector& InOffset)
1142 {
1143 for (auto& Element : Elements)
1144 {
1146 }
1147
1149 {
1150 if (Children[ChildRef.Index])
1151 {
1153 }
1154 }
1155 }
1156
1157 private:
1158
1159 /** The elements in this node. */
1161
1162 /** The parent of this node. */
1164
1165 /** The children of the node. */
1166 mutable FNode* Children[8];
1167
1168 /** The number of elements contained by the node and its child nodes. */
1169 mutable uint32 InclusiveNumElements : 31;
1170
1171 /** true if the meshes should be added directly to the node, rather than subdividing when possible. */
1172 mutable uint32 bIsLeaf : 1;
1173 };
1174
1175
1176
1177 /** A reference to an octree node, its context, and a read lock. */
1179 {
1180 public:
1181
1182 const FNode* Node;
1184
1185 /** Default constructor. */
1187 Node(NULL),
1188 Context()
1189 {}
1190
1191 /** Initialization constructor. */
1192 FNodeReference(const FNode* InNode, const FOctreeNodeContext& InContext) :
1193 Node(InNode),
1195 {}
1196 };
1197
1198 /** The default iterator allocator gives the stack enough inline space to contain a path and its siblings from root to leaf. */
1199 typedef TInlineAllocator<7 * (14 - 1) + 8> DefaultStackAllocator;
1200
1201 /** An octree node iterator. */
1202 template<typename StackAllocator = DefaultStackAllocator>
1204 {
1205 public:
1206
1207 /** Pushes a child of the current node onto the stack of nodes to visit. */
1209 {
1213 }
1214 /** Pushes a child of the current node onto the stack of nodes to visit. */
1215 void PushChild(FOctreeChildNodeRef ChildRef, uint32 FullyInsideView, uint32 FullyOutsideView)
1216 {
1222 }
1223 /** Pushes a child of the current node onto the stack of nodes to visit. */
1224 void PushChild(FOctreeChildNodeRef ChildRef, const FOctreeNodeContext& Context)
1225 {
1227 }
1228
1229
1230 /** Iterates to the next node. */
1231 void Advance()
1232 {
1233 if (NodeStack.Num())
1234 {
1237 }
1238 else
1239 {
1241 }
1242 }
1243
1244 /** Checks if there are any nodes left to iterate over. */
1245 bool HasPendingNodes() const
1246 {
1247 return CurrentNode.Node != NULL;
1248 }
1249
1250 /** Starts iterating at the root of an octree. */
1253 {}
1254
1255 /** Starts iterating at a particular node of an octree. */
1256 TConstIterator(const FNode& Node, const FOctreeNodeContext& Context) :
1258 {}
1259
1260 // Accessors.
1261 const FNode& GetCurrentNode() const
1262 {
1263 return *CurrentNode.Node;
1264 }
1266 {
1267 return CurrentNode.Context;
1268 }
1269
1270 private:
1271
1272 /** The node that is currently being visited. */
1274
1275 /** The nodes which are pending iteration. */
1277 };
1278
1279 /** Iterates over the elements in the octree that intersect a bounding box. */
1280 template<typename StackAllocator = DefaultStackAllocator>
1282 {
1283 public:
1284
1285 /** Iterates to the next element. */
1286 void Advance()
1287 {
1288 ++ElementIt;
1290 }
1291
1292 /** Checks if there are any elements left to iterate over. */
1294 {
1295 return NodeIt.HasPendingNodes();
1296 }
1297
1298 /** Initialization constructor. */
1301 , NodeIt(Tree)
1303 {
1306 }
1307
1308 // Accessors.
1309 const ElementType& GetCurrentElement() const
1310 {
1311 return *ElementIt;
1312 }
1313
1314 private:
1315
1316 /** The bounding box to check for intersection with. */
1318
1319 /** The octree node iterator. */
1320 TConstIterator<StackAllocator> NodeIt;
1321
1322 /** The element iterator for the current node. */
1324
1325 /** Processes the children of the current node. */
1327 {
1328 // Add the child nodes that intersect the bounding box to the node iterator's stack.
1333 {
1335 {
1337 }
1338 }
1339 }
1340
1341 /** Advances the iterator to the next intersecting primitive, starting at a primitive in the current node. */
1343 {
1344 check(NodeIt.HasPendingNodes()); // please don't call this after iteration has ended
1345
1346 while (1)
1347 {
1349 if (LocalElementIt)
1350 {
1353
1354 // this is redundantly pull out of the while loop to prevent LHS on the iterator
1355 // Check if the current element intersects the bounding box.
1357 {
1358 // If it intersects, break out of the advancement loop.
1360 return;
1361 }
1362
1363 // Check if we've advanced past the elements in the current node.
1364 while (++LocalElementIt)
1365 {
1367
1368 // Check if the current element intersects the bounding box.
1370
1371 {
1372 // If it intersects, break out of the advancement loop.
1374 return;
1375 }
1376 }
1377 }
1378 // Advance to the next node.
1379 NodeIt.Advance();
1380 if (!NodeIt.HasPendingNodes())
1381 {
1383 return;
1384 }
1386 // The element iterator can't be assigned to, but it can be replaced by Move.
1388 }
1389 }
1390 };
1391
1392 /**
1393 * Adds an element to the octree.
1394 * @param Element - The element to add.
1395 * @return An identifier for the element in the octree.
1396 */
1397 void AddElement(typename TTypeTraits<ElementType>::ConstInitType Element)
1398 {
1400 }
1401
1402 /**
1403 * Removes an element from the octree.
1404 * @param ElementId - The element to remove from the octree.
1405 */
1407 {
1409
1411
1412 // Remove the element from the node's element list.
1414
1416
1418 {
1419 // Update the external element id for the element that was swapped into the vacated element index.
1421 }
1422
1423 // Update the inclusive element counts for the nodes between the element and the root node,
1424 // and find the largest node that is small enough to collapse.
1425 const FNode* CollapseNode = NULL;
1426 for (const FNode* Node = ElementIdNode; Node; Node = Node->Parent)
1427 {
1430 {
1432 }
1433 }
1434
1435 // Collapse the largest node that was pushed below the threshold for collapse by the removal.
1437 {
1439 {
1441
1442 // Gather the elements contained in this node and its children.
1444 {
1446
1447 if (&ChildNode != CollapseNode)
1448 {
1449 // Child node will be collapsed so move the child's elements to the collapse node element list.
1451 {
1453
1454 // Update the external element id for the element that's being collapsed.
1456 }
1457 }
1458
1459 // Recursively visit all child nodes.
1461 {
1463 {
1465 }
1466 }
1467 }
1468
1469 // Free the child nodes.
1471 {
1473 {
1475 }
1476
1479 }
1480 }
1481
1482 // Mark the node as a leaf.
1483 CollapseNode->bIsLeaf = true;
1484 }
1485 }
1486
1487
1488 void Destroy()
1489 {
1490 RootNode.~FNode();
1491 new (&RootNode) FNode(NULL);
1492
1493 // this looks a bit @hacky, but FNode's destructor doesn't
1494 // update TotalSizeBytes so better to set it to 0 than
1495 // not do nothing with it (would contain obviously false value)
1496 SetOctreeMemoryUsage(this, 0);
1497 }
1498
1499 /** Accesses an octree element by ID. */
1500 ElementType& GetElementById(FOctreeElementId ElementId)
1501 {
1505 }
1506
1507 /** Accesses an octree element by ID. */
1508 const ElementType& GetElementById(FOctreeElementId ElementId) const
1509 {
1513 }
1514
1515 /** Checks if given ElementId represents a valid Octree element */
1517 {
1518 return ElementId.IsValidId()
1521 };
1522
1523 /** Writes stats for the octree to the log. */
1524 void DumpStats() const
1525 {
1526 int32 NumNodes = 0;
1527 int32 NumLeaves = 0;
1528 int32 NumElements = 0;
1531
1533 {
1536
1537 NumNodes++;
1538 if (CurrentNode.IsLeaf())
1539 {
1540 NumLeaves++;
1541 }
1542
1545
1547 {
1549 }
1551
1553 {
1555 {
1557 }
1558 }
1559 }
1560
1561 UE_LOG(LogGenericOctree, Log, TEXT("Octree overview:"));
1562 UE_LOG(LogGenericOctree, Log, TEXT("\t%i nodes"), NumNodes);
1563 UE_LOG(LogGenericOctree, Log, TEXT("\t%i leaves"), NumLeaves);
1564 UE_LOG(LogGenericOctree, Log, TEXT("\t%i elements"), NumElements);
1565 UE_LOG(LogGenericOctree, Log, TEXT("\t%i >= elements per node"), MaxElementsPerNode);
1566 UE_LOG(LogGenericOctree, Log, TEXT("Octree node element distribution:"));
1567 for (int32 i = 0; i < NodeElementDistribution.Num(); i++)
1568 {
1569 if (NodeElementDistribution[i] > 0)
1570 {
1571 UE_LOG(LogGenericOctree, Log, TEXT("\tElements: %3i, Nodes: %3i"), i, NodeElementDistribution[i]);
1572 }
1573 }
1574 }
1575
1576
1577 SIZE_T GetSizeBytes() const
1578 {
1579 return TotalSizeBytes;
1580 }
1581
1583 {
1586 }
1587
1589 {
1590 return RootNodeContext.Bounds;
1591 }
1592
1594 {
1596 }
1597
1598 /**
1599 * Apply an arbitrary offset to all elements in the tree
1600 * InOffset - offset to apply
1601 * bGlobalOctree - hint that this octree is used as a boundless global volume,
1602 * so only content will be shifted but not origin of the octree
1603 */
1604 void ApplyOffset(const FVector& InOffset, bool bGlobalOctree)
1605 {
1606 // Shift elements
1608
1609 // Make a local copy of all nodes
1611
1612 // Assign to root node a NULL node, so Destroy procedure will not delete child nodes
1613 RootNode = FNode(nullptr);
1614 // Call destroy to clean up octree
1615 Destroy();
1616
1617 if (!bGlobalOctree)
1618 {
1620 }
1621
1622 // Add all elements from a saved nodes to a new empty octree
1624 {
1625 const auto& CurrentNode = NodeIt.GetCurrentNode();
1626
1628 {
1630 {
1632 }
1633 }
1634
1636 {
1638 }
1639 }
1640
1641 // Saved nodes will be deleted on scope exit
1642 }
1643
1644
1645 /** Initialization constructor. */
1646 TOctree_DEPRECATED(const FVector& InOrigin, FReal InExtent)
1647 : RootNode(NULL)
1650 , TotalSizeBytes(0)
1651 {
1652 }
1653
1654 /** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */
1656 {
1658 }
1659
1660private:
1661
1662 /** The octree's root node. */
1664
1665 /** The octree's root node's context. */
1667
1668 /** The extent of a leaf at the maximum allowed depth of the tree. */
1670
1671 /** this function basically set TotalSizeBytes, but gives opportunity to
1672 * include this Octree in memory stats */
1673 void SetOctreeMemoryUsage(TOctree_DEPRECATED<ElementType, OctreeSemantics>* Octree, int32 NewSize)
1674 {
1676 }
1677
1679
1680 /** Adds an element to a node or its children. */
1682 typename TTypeTraits<ElementType>::ConstInitType Element,
1683 const FNode& InNode,
1684 const FOctreeNodeContext& InContext
1685 )
1686 {
1688
1690 {
1691 const FNode& Node = NodeIt.GetCurrentNode();
1693 const bool bIsLeaf = Node.IsLeaf();
1694
1695 bool bAddElementToThisNode = false;
1696
1697 // Increment the number of elements included in this node and its children.
1699
1700 if (bIsLeaf)
1701 {
1702 // If this is a leaf, check if adding this element would turn it into a node by overflowing its element list.
1704 {
1705 // Copy the leaf's elements, remove them from the leaf, and turn it into a node.
1710
1711 // Allow elements to be added to children of this node.
1712 Node.bIsLeaf = false;
1713
1714 // Re-add all of the node's child elements, potentially creating children of this node for them.
1716 {
1718 }
1719
1720 // Add the element to this node.
1722 return;
1723 }
1724 else
1725 {
1726 // If the leaf has room for the new element, simply add it to the list.
1727 bAddElementToThisNode = true;
1728 }
1729 }
1730 else
1731 {
1732 // If this isn't a leaf, find a child that entirely contains the element.
1734 if (ChildRef.IsNULL())
1735 {
1736 // If none of the children completely contain the element, add it to this node directly.
1737 bAddElementToThisNode = true;
1738 }
1739 else
1740 {
1741 // Create the child node if it hasn't been created yet.
1743 {
1746 }
1747
1748 // Push the node onto the stack to visit.
1750 }
1751 }
1752
1754 {
1755 // Add the element to this node.
1757
1759
1760 // Set the element's ID.
1762 return;
1763 }
1764 }
1765
1767 TEXT("Failed to find an octree node for an element with bounds (%f,%f,%f) +/- (%f,%f,%f)!"),
1774 );
1775 }
1776
1777 // Concept definition for the new octree semantics, which adds a new TOctree parameter
1779 {
1780 template<typename Semantics>
1781 auto Requires(typename Semantics::FOctree& OctreeInstance, const ElementType& Element, FOctreeElementId Id)
1782 -> decltype(Semantics::SetElementId(OctreeInstance, Element, Id));
1783 };
1784
1785 // Function overload set which calls the V2 version if it's supported or the old version if it's not
1786 template <typename Semantics>
1788 {
1790 }
1791 template <typename Semantics>
1793 {
1794 Semantics::SetElementId(*this, Element, Id);
1795 }
1796
1797protected:
1798 // redirects SetElementId call to the proper implementation
1799 void SetElementId(const ElementType& Element, FOctreeElementId Id)
1800 {
1802 }
1803};
1804
1805template<typename ElementType, typename OctreeSemantics>
1806class UE_DEPRECATED(4.26, "The old Octree is deprecated use TOctree2.") TOctree : public TOctree_DEPRECATED<ElementType, OctreeSemantics>
1807{
1808public:
1809 TOctree(const FVector& InOrigin, FVector::FReal InExtent) : TOctree_DEPRECATED<ElementType, OctreeSemantics>(InOrigin, InExtent)
1810 {
1811 }
1812
1813 TOctree() : TOctree_DEPRECATED<ElementType, OctreeSemantics>()
1814 {
1815 }
1816};
1817
1818#include "Math/GenericOctree.inl" // IWYU pragma: export
1819
1820#include <stddef.h> // IWYU pragma: export
#define checkSlow(expr)
#define check(expr)
@ INDEX_NONE
#define UE_DEPRECATED(Version, Message)
#define FOREACH_OCTREE_CHILD_NODE(ChildRef)
DECLARE_LOG_CATEGORY_EXTERN(LogChunkInstaller, Log, All)
#define PLATFORM_HOLOLENS
Definition Platform.h:65
#define TEXT(x)
Definition Platform.h:1108
#define FORCEINLINE
Definition Platform.h:644
#define PLATFORM_CACHE_LINE_SIZE
Definition Platform.h:818
#define VectorIntCompareEQ(A, B)
#define VectorIntAnd(A, B)
#define VectorIntLoad1(Ptr)
FORCEINLINE VectorRegister4Float MakeVectorRegister(uint32 X, uint32 Y, uint32 Z, uint32 W)
FORCEINLINE VectorRegister4Float MakeVectorRegister(float X, float Y, float Z, float W)
FORCEINLINE void Advance()
FOctreeChildNodeRef(int8 InX, int8 InY, int8 InZ)
FORCEINLINE bool IsNULL() const
FOctreeChildNodeRef(int8 InIndex=0)
FORCEINLINE void SetNULL()
FORCEINLINE int32 Z() const
FORCEINLINE int32 X() const
FORCEINLINE int32 Y() const
FOctreeChildNodeSubset(FOctreeChildNodeRef ChildRef)
bool Contains(FOctreeChildNodeRef ChildRef) const
FOctreeNodeContext(const FBoxCenterAndExtent &InBounds, uint32 InInCullBits, uint32 InOutCullBits)
FOctreeNodeContext GetChildContext(FOctreeChildNodeRef ChildRef) const
FOctreeNodeContext(uint32 InInCullBits, uint32 InOutCullBits)
FOctreeNodeContext GetChildContext(FOctreeChildNodeRef ChildRef, uint32 InInCullBits, uint32 InOutCullBits) const
FOctreeChildNodeSubset GetIntersectingChildren(const FBoxCenterAndExtent &BoundingBox) const
FOctreeNodeContext(const FBoxCenterAndExtent &InBounds)
void GetChildContext(FOctreeChildNodeRef ChildRef, FOctreeNodeContext *ChildContext) const
VectorRegister GetChildOffsetVec(int i) const
FBoxCenterAndExtent Bounds
FOctreeChildNodeRef GetContainingChild(const FBoxCenterAndExtent &BoundingBox) const
void Push(FNodeIndex NodeIndex)
TArray< FSpan > FreeList
FBoxCenterAndExtent GetRootBounds() const
void Destroy()
TArray< FNodeIndex > FreeList
void FindNearbyElements(const FVector &Position, const IterateBoundsFunc &Func) const
void FindElementsWithBoundsTest(const FBoxCenterAndExtent &BoxBounds, const IterateBoundsFunc &Func) const
void SetElementId(const ElementType &Element, FOctreeElementId2 Id)
TOctree2(const FVector &InOrigin, FVector::FReal InExtent)
void ShrinkElements()
void CollapseNodesInternal(FNodeIndex CurrentNodeIndex, ElementArrayType &CollapsedNodeElements)
void FindNearbyElementsInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext &NodeContext, const FBoxCenterAndExtent &BoxBounds, const IterateFunc &Func) const
ElementType & GetElementById(FOctreeElementId2 ElementId)
void AddElement(typename TCallTraits< ElementType >::ConstReference Element)
void RemoveElement(FOctreeElementId2 ElementId)
bool IsValidElementId(FOctreeElementId2 ElementId) const
void AddElementInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext &NodeContext, const FBoxCenterAndExtent &ElementBounds, typename TCallTraits< ElementType >::ConstReference Element, ElementArrayType &TempElementStorage)
const ElementType & GetElementById(FOctreeElementId2 ElementId) const
void FindAllElements(const IterateAllElementsFunc &Func) const
FNodeIndex AllocateEightNodes()
SIZE_T GetSizeBytes() const
FReal GetNodeLevelExtent(int32 Level) const
void FindFirstElementWithBoundsTestInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext &NodeContext, const FBoxCenterAndExtent &BoxBounds, const IterateFunc &Func, bool &ContinueTraversal) const
void FreeEightNodes(FNodeIndex Index)
TArray< FNode > TreeNodes
FOctreeNodeContext RootNodeContext
TArray< ElementArrayType, TAlignedHeapAllocator< alignof(ElementArrayType)> > TreeElements
void FindElementsWithPredicate(const PredicateFunc &Predicate, const IterateFunc &Func) const
int32 GetNumNodes() const
void FindNodesWithPredicate(const PredicateFunc &Predicate, const IterateFunc &Func) const
void FindNodesWithPredicateInternal(FNodeIndex ParentNodeIndex, FNodeIndex CurrentNodeIndex, const FOctreeNodeContext &NodeContext, const PredicateFunc &Predicate, const IterateFunc &Func) const
void DumpStats() const
FVector::FReal MinLeafExtent
void FindElementsWithBoundsTestInternal(FNodeIndex CurrentNodeIndex, const FOctreeNodeContext &NodeContext, const FBoxCenterAndExtent &BoxBounds, const IterateFunc &Func) const
void FindFirstElementWithBoundsTest(const FBoxCenterAndExtent &BoxBounds, const IterateBoundsFunc &Func) const
TEnableIf<!TModels< COctreeSemanticsV2, Semantics >::Value >::Type SetOctreeSemanticsElementId(const ElementType &Element, FOctreeElementId2 Id)
void ApplyOffset(const FVector &InOffset, bool bGlobalOctree=false)
TArray< FNodeIndex > ParentLinks
TArrayView< const ElementType > GetElementsForNode(FNodeIndex NodeIndex) const
FORCEINLINE const ElementArrayType & GetElements() const
FNode(const FNode *InParent)
FORCEINLINE int32 GetInclusiveElementCount() const
FORCEINLINE bool IsLeaf() const
FORCEINLINE int32 GetElementCount() const
FORCEINLINE ElementConstIt GetElementIt() const
FORCEINLINE bool HasChild(FOctreeChildNodeRef ChildRef) const
void ApplyOffset(const FVector &InOffset)
FORCEINLINE FNode * GetChild(FOctreeChildNodeRef ChildRef) const
FNodeReference(const FNode *InNode, const FOctreeNodeContext &InContext)
const ElementType & GetCurrentElement() const
TConstElementBoxIterator(const TOctree_DEPRECATED &Tree, const FBoxCenterAndExtent &InBoundingBox)
TConstIterator< StackAllocator > NodeIt
TArray< FNodeReference, StackAllocator > NodeStack
const FOctreeNodeContext & GetCurrentContext() const
TConstIterator(const TOctree_DEPRECATED &Tree)
TConstIterator(const FNode &Node, const FOctreeNodeContext &Context)
void PushChild(FOctreeChildNodeRef ChildRef)
void PushChild(FOctreeChildNodeRef ChildRef, const FOctreeNodeContext &Context)
const FNode & GetCurrentNode() const
void PushChild(FOctreeChildNodeRef ChildRef, uint32 FullyInsideView, uint32 FullyOutsideView)
TOctree_DEPRECATED(const FVector &InOrigin, FReal InExtent)
ElementType & GetElementById(FOctreeElementId ElementId)
FReal GetNodeLevelExtent(int32 Level) const
void SetOctreeMemoryUsage(TOctree_DEPRECATED< ElementType, OctreeSemantics > *Octree, int32 NewSize)
SIZE_T GetSizeBytes() const
FBoxCenterAndExtent GetRootBounds() const
const ElementType & GetElementById(FOctreeElementId ElementId) const
void RemoveElement(FOctreeElementId ElementId)
void ApplyOffset(const FVector &InOffset, bool bGlobalOctree)
bool IsValidElementId(FOctreeElementId ElementId) const
void DumpStats() const
ElementArrayType::TConstIterator ElementConstIt
TArray< ElementType, typename OctreeSemantics::ElementAllocator > ElementArrayType
void SetElementId(const ElementType &Element, FOctreeElementId Id)
void AddElementToNode(typename TTypeTraits< ElementType >::ConstInitType Element, const FNode &InNode, const FOctreeNodeContext &InContext)
TEnableIf<!TModels< COctreeSemanticsV2, Semantics >::Value >::Type SetOctreeSemanticsElementId(const ElementType &Element, FOctreeElementId Id)
TInlineAllocator< 7 *(14 - 1)+8 > DefaultStackAllocator
FOctreeNodeContext RootNodeContext
void AddElement(typename TTypeTraits< ElementType >::ConstInitType Element)
auto Requires(typename Semantics::FOctree &OctreeInstance, const ElementType &Element, FOctreeElementId2 Id) -> decltype(Semantics::SetElementId(OctreeInstance, Element, Id))
uint32 InclusiveNumElements
bool IsLeaf() const
FNodeIndex ChildNodes
auto Requires(typename Semantics::FOctree &OctreeInstance, const ElementType &Element, FOctreeElementId Id) -> decltype(Semantics::SetElementId(OctreeInstance, Element, Id))