Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
NodeCodecQuadTreeHalfFloat.h
Go to the documentation of this file.
1// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
10
12
13template <int Alignment>
15{
16public:
18 static constexpr int NumChildrenPerNode = 4;
19
21 struct Header
22 {
26 };
27
29 static constexpr int HeaderSize = sizeof(Header);
30
32 static constexpr int StackSize = 128;
33
35 enum : uint32
36 {
44 };
45
47 struct Node
48 {
56 };
57
58 static_assert(sizeof(Node) == 64, "Node should be 64 bytes");
59
62 {
63 public:
66 {
67 return inNodeCount * (sizeof(Node) + Alignment - 1);
68 }
69
75 uint NodeAllocate(const AABBTreeBuilder::Node *inNode, Vec3Arg inNodeBoundsMin, Vec3Arg inNodeBoundsMax, Array<const AABBTreeBuilder::Node *> &ioChildren, Vec3 outChildBoundsMin[NumChildrenPerNode], Vec3 outChildBoundsMax[NumChildrenPerNode], ByteBuffer &ioBuffer, const char *&outError) const
76 {
77 // We don't emit nodes for leafs
78 if (!inNode->HasChildren())
79 return (uint)ioBuffer.size();
80
81 // Align the buffer
82 ioBuffer.Align(Alignment);
83 uint node_start = (uint)ioBuffer.size();
84
85 // Fill in bounds
86 Node *node = ioBuffer.Allocate<Node>();
87
88 for (size_t i = 0; i < 4; ++i)
89 {
90 if (i < ioChildren.size())
91 {
92 const AABBTreeBuilder::Node *this_node = ioChildren[i];
93
94 // Copy bounding box
95 node->mBoundsMinX[i] = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_NEG_INF>(this_node->mBounds.mMin.GetX());
96 node->mBoundsMinY[i] = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_NEG_INF>(this_node->mBounds.mMin.GetY());
97 node->mBoundsMinZ[i] = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_NEG_INF>(this_node->mBounds.mMin.GetZ());
98 node->mBoundsMaxX[i] = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_POS_INF>(this_node->mBounds.mMax.GetX());
99 node->mBoundsMaxY[i] = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_POS_INF>(this_node->mBounds.mMax.GetY());
100 node->mBoundsMaxZ[i] = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_POS_INF>(this_node->mBounds.mMax.GetZ());
101
102 // Store triangle count
103 node->mNodeProperties[i] = this_node->GetTriangleCount() << TRIANGLE_COUNT_SHIFT;
104 if (this_node->GetTriangleCount() >= TRIANGLE_COUNT_MASK)
105 {
106 outError = "NodeCodecQuadTreeHalfFloat: Too many triangles";
107 return uint(-1);
108 }
109 }
110 else
111 {
112 // Make this an invalid triangle node
114
115 // Make bounding box invalid
116 node->mBoundsMinX[i] = HALF_FLT_MAX;
117 node->mBoundsMinY[i] = HALF_FLT_MAX;
118 node->mBoundsMinZ[i] = HALF_FLT_MAX;
119 node->mBoundsMaxX[i] = HALF_FLT_MAX;
120 node->mBoundsMaxY[i] = HALF_FLT_MAX;
121 node->mBoundsMaxZ[i] = HALF_FLT_MAX;
122 }
123 }
124
125 // Since we don't keep track of the bounding box while descending the tree, we keep the root bounds at all levels for triangle compression
126 for (int i = 0; i < NumChildrenPerNode; ++i)
127 {
128 outChildBoundsMin[i] = inNodeBoundsMin;
129 outChildBoundsMax[i] = inNodeBoundsMax;
130 }
131
132 return node_start;
133 }
134
136 bool NodeFinalize(const AABBTreeBuilder::Node *inNode, uint inNodeStart, uint inNumChildren, const uint *inChildrenNodeStart, const uint *inChildrenTrianglesStart, ByteBuffer &ioBuffer, const char *&outError) const
137 {
138 if (!inNode->HasChildren())
139 return true;
140
141 Node *node = ioBuffer.Get<Node>(inNodeStart);
142 for (uint i = 0; i < inNumChildren; ++i)
143 {
144 // If there are triangles, use the triangle offset otherwise use the node offset
145 uint offset = node->mNodeProperties[i] != 0? inChildrenTrianglesStart[i] : inChildrenNodeStart[i];
146 if (offset & OFFSET_NON_SIGNIFICANT_MASK)
147 {
148 outError = "NodeCodecQuadTreeHalfFloat: Internal Error: Offset has non-significant bits set";
149 return false;
150 }
152 if (offset & ~OFFSET_MASK)
153 {
154 outError = "NodeCodecQuadTreeHalfFloat: Offset too large. Too much data.";
155 return false;
156 }
157
158 // Store offset of next node / triangles
159 node->mNodeProperties[i] |= offset;
160 }
161
162 return true;
163 }
164
166 bool Finalize(Header *outHeader, const AABBTreeBuilder::Node *inRoot, uint inRootNodeStart, uint inRootTrianglesStart, const char *&outError) const
167 {
168 uint offset = inRoot->HasChildren()? inRootNodeStart : inRootTrianglesStart;
169 if (offset & OFFSET_NON_SIGNIFICANT_MASK)
170 {
171 outError = "NodeCodecQuadTreeHalfFloat: Internal Error: Offset has non-significant bits set";
172 return false;
173 }
175 if (offset & ~OFFSET_MASK)
176 {
177 outError = "NodeCodecQuadTreeHalfFloat: Offset too large. Too much data.";
178 return false;
179 }
180
181 inRoot->mBounds.mMin.StoreFloat3(&outHeader->mRootBoundsMin);
182 inRoot->mBounds.mMax.StoreFloat3(&outHeader->mRootBoundsMax);
183 outHeader->mRootProperties = offset + (inRoot->GetTriangleCount() << TRIANGLE_COUNT_SHIFT);
184 if (inRoot->GetTriangleCount() >= TRIANGLE_COUNT_MASK)
185 {
186 outError = "NodeCodecQuadTreeHalfFloat: Too many triangles";
187 return false;
188 }
189
190 return true;
191 }
192 };
193
196 {
197 public:
199 inline static uint sTriangleBlockIDBits(const ByteBuffer &inTree)
200 {
202 }
203
205 inline static const void * sGetTriangleBlockStart(const uint8 *inBufferStart, uint inTriangleBlockID)
206 {
207 return inBufferStart + (inTriangleBlockID << OFFSET_NON_SIGNIFICANT_BITS);
208 }
209
211 JPH_INLINE explicit DecodingContext(const Header *inHeader)
212 {
213 // Start with the root node on the stack
214 mNodeStack[0] = inHeader->mRootProperties;
215 }
216
218 template <class TriangleContext, class Visitor>
219 JPH_INLINE void WalkTree(const uint8 *inBufferStart, const TriangleContext &inTriangleContext, Visitor &ioVisitor)
220 {
221 do
222 {
223 // Test if node contains triangles
224 uint32 node_properties = mNodeStack[mTop];
225 uint32 tri_count = node_properties >> TRIANGLE_COUNT_SHIFT;
226 if (tri_count == 0)
227 {
228 const Node *node = reinterpret_cast<const Node *>(inBufferStart + (node_properties << OFFSET_NON_SIGNIFICANT_BITS));
229
230 // Unpack bounds
231 UVec4 bounds_minxy = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMinX[0]));
232 Vec4 bounds_minx = HalfFloatConversion::ToFloat(bounds_minxy);
234
235 UVec4 bounds_minzmaxx = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMinZ[0]));
236 Vec4 bounds_minz = HalfFloatConversion::ToFloat(bounds_minzmaxx);
238
239 UVec4 bounds_maxyz = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMaxY[0]));
240 Vec4 bounds_maxy = HalfFloatConversion::ToFloat(bounds_maxyz);
242
243 // Load properties for 4 children
244 UVec4 properties = UVec4::sLoadInt4(&node->mNodeProperties[0]);
245
246 // Check which sub nodes to visit
247 int num_results = ioVisitor.VisitNodes(bounds_minx, bounds_miny, bounds_minz, bounds_maxx, bounds_maxy, bounds_maxz, properties, mTop);
248
249 // Push them onto the stack
250 JPH_ASSERT(mTop + 4 < StackSize);
251 properties.StoreInt4(&mNodeStack[mTop]);
252 mTop += num_results;
253 }
254 else if (tri_count != TRIANGLE_COUNT_MASK) // TRIANGLE_COUNT_MASK indicates a padding node, normally we shouldn't visit these nodes but when querying with a big enough box you could touch HALF_FLT_MAX (about 65K)
255 {
256 // Node contains triangles, do individual tests
257 uint32 triangle_block_id = node_properties & OFFSET_MASK;
258 const void *triangles = sGetTriangleBlockStart(inBufferStart, triangle_block_id);
259
260 ioVisitor.VisitTriangles(inTriangleContext, triangles, tri_count, triangle_block_id);
261 }
262
263 // Check if we're done
264 if (ioVisitor.ShouldAbort())
265 break;
266
267 // Fetch next node until we find one that the visitor wants to see
268 do
269 --mTop;
270 while (mTop >= 0 && !ioVisitor.ShouldVisitNode(mTop));
271 }
272 while (mTop >= 0);
273 }
274
276 bool IsDoneWalking() const
277 {
278 return mTop < 0;
279 }
280
281 private:
282 uint32 mNodeStack[StackSize];
283 int mTop = 0;
284 };
285};
286
std::uint8_t uint8
Definition: Core.h:453
unsigned int uint
Definition: Core.h:452
#define JPH_NAMESPACE_END
Definition: Core.h:378
std::uint32_t uint32
Definition: Core.h:455
#define JPH_NAMESPACE_BEGIN
Definition: Core.h:372
uint16 HalfFloat
Definition: HalfFloat.h:11
#define JPH_ASSERT(...)
Definition: IssueReporting.h:33
uint CountLeadingZeros(uint32 inValue)
Compute the number of leading zero bits (how many high bits are zero)
Definition: Math.h:131
@ SWIZZLE_Z
Use the Z component.
Definition: Swizzle.h:14
@ SWIZZLE_W
Use the W component.
Definition: Swizzle.h:15
@ SWIZZLE_UNUSED
We always use the Z component when we don't specifically want to initialize a value,...
Definition: Swizzle.h:16
A node in the tree, contains the AABox for the tree and any child nodes or triangles.
Definition: AABBTreeBuilder.h:40
AABox mBounds
Bounding box.
Definition: AABBTreeBuilder.h:79
uint GetTriangleCount() const
Get number of triangles in this node.
Definition: AABBTreeBuilder.h:49
bool HasChildren() const
Check if this node has any children.
Definition: AABBTreeBuilder.h:52
Vec3 mMin
Bounding box min and max.
Definition: AABox.h:300
Vec3 mMax
Definition: AABox.h:301
Definition: Array.h:36
size_type size() const
Returns amount of elements in the array.
Definition: Array.h:318
Simple byte buffer, aligned to a cache line.
Definition: ByteBuffer.h:16
Type * Allocate(size_t inSize=1)
Allocate block of data of inSize elements and return the pointer.
Definition: ByteBuffer.h:33
size_t Align(size_t inSize)
Align the size to a multiple of inSize, returns the length after alignment.
Definition: ByteBuffer.h:19
const Type * Get(size_t inPosition) const
Get object at inPosition (an offset in bytes)
Definition: ByteBuffer.h:61
Class that holds 3 floats. Used as a storage class. Convert to Vec3 for calculations.
Definition: Float3.h:13
This class decodes and decompresses quad tree nodes.
Definition: NodeCodecQuadTreeHalfFloat.h:196
JPH_INLINE void WalkTree(const uint8 *inBufferStart, const TriangleContext &inTriangleContext, Visitor &ioVisitor)
Walk the node tree calling the Visitor::VisitNodes for each node encountered and Visitor::VisitTriang...
Definition: NodeCodecQuadTreeHalfFloat.h:219
bool IsDoneWalking() const
This can be used to have the visitor early out (ioVisitor.ShouldAbort() returns true) and later conti...
Definition: NodeCodecQuadTreeHalfFloat.h:276
static const void * sGetTriangleBlockStart(const uint8 *inBufferStart, uint inTriangleBlockID)
Convert a triangle block ID to the start of the triangle buffer.
Definition: NodeCodecQuadTreeHalfFloat.h:205
static uint sTriangleBlockIDBits(const ByteBuffer &inTree)
Get the amount of bits needed to store an ID to a triangle block.
Definition: NodeCodecQuadTreeHalfFloat.h:199
JPH_INLINE DecodingContext(const Header *inHeader)
Constructor.
Definition: NodeCodecQuadTreeHalfFloat.h:211
This class encodes and compresses quad tree nodes.
Definition: NodeCodecQuadTreeHalfFloat.h:62
bool NodeFinalize(const AABBTreeBuilder::Node *inNode, uint inNodeStart, uint inNumChildren, const uint *inChildrenNodeStart, const uint *inChildrenTrianglesStart, ByteBuffer &ioBuffer, const char *&outError) const
Once all nodes have been added, this call finalizes all nodes by patching in the offsets of the child...
Definition: NodeCodecQuadTreeHalfFloat.h:136
uint GetPessimisticMemoryEstimate(uint inNodeCount) const
Get an upper bound on the amount of bytes needed for a node tree with inNodeCount nodes.
Definition: NodeCodecQuadTreeHalfFloat.h:65
bool Finalize(Header *outHeader, const AABBTreeBuilder::Node *inRoot, uint inRootNodeStart, uint inRootTrianglesStart, const char *&outError) const
Once all nodes have been finalized, this will finalize the header of the nodes.
Definition: NodeCodecQuadTreeHalfFloat.h:166
uint NodeAllocate(const AABBTreeBuilder::Node *inNode, Vec3Arg inNodeBoundsMin, Vec3Arg inNodeBoundsMax, Array< const AABBTreeBuilder::Node * > &ioChildren, Vec3 outChildBoundsMin[NumChildrenPerNode], Vec3 outChildBoundsMax[NumChildrenPerNode], ByteBuffer &ioBuffer, const char *&outError) const
Definition: NodeCodecQuadTreeHalfFloat.h:75
Definition: NodeCodecQuadTreeHalfFloat.h:15
static constexpr int StackSize
Stack size to use during DecodingContext::sWalkTree.
Definition: NodeCodecQuadTreeHalfFloat.h:32
static constexpr int HeaderSize
Size of the header (an empty struct is always > 0 bytes so this needs a separate variable)
Definition: NodeCodecQuadTreeHalfFloat.h:29
@ TRIANGLE_COUNT_BITS
Definition: NodeCodecQuadTreeHalfFloat.h:37
@ OFFSET_BITS
Definition: NodeCodecQuadTreeHalfFloat.h:40
@ TRIANGLE_COUNT_SHIFT
Definition: NodeCodecQuadTreeHalfFloat.h:38
@ TRIANGLE_COUNT_MASK
Definition: NodeCodecQuadTreeHalfFloat.h:39
@ OFFSET_MASK
Definition: NodeCodecQuadTreeHalfFloat.h:41
@ OFFSET_NON_SIGNIFICANT_BITS
Definition: NodeCodecQuadTreeHalfFloat.h:42
@ OFFSET_NON_SIGNIFICANT_MASK
Definition: NodeCodecQuadTreeHalfFloat.h:43
static constexpr int NumChildrenPerNode
Number of child nodes of this node.
Definition: NodeCodecQuadTreeHalfFloat.h:18
Definition: UVec4.h:12
JPH_INLINE UVec4 Swizzle() const
Swizzle the elements in inV.
JPH_INLINE void StoreInt4(uint32 *outV) const
Store 4 ints to memory.
Definition: UVec4.inl:351
static JPH_INLINE UVec4 sLoadInt4(const uint32 *inV)
Load 4 ints from memory.
Definition: UVec4.inl:78
Definition: Vec3.h:17
JPH_INLINE float GetX() const
Get individual components.
Definition: Vec3.h:124
JPH_INLINE float GetY() const
Definition: Vec3.h:125
JPH_INLINE void StoreFloat3(Float3 *outV) const
Store 3 floats to memory.
Definition: Vec3.inl:769
JPH_INLINE float GetZ() const
Definition: Vec3.h:126
Definition: Vec4.h:14
JPH_INLINE Vec4 ToFloat(UVec4Arg inValue)
Convert 4 half floats (lower 64 bits) to floats.
Definition: HalfFloat.h:191
Header for the tree.
Definition: NodeCodecQuadTreeHalfFloat.h:22
Float3 mRootBoundsMin
Definition: NodeCodecQuadTreeHalfFloat.h:23
Float3 mRootBoundsMax
Definition: NodeCodecQuadTreeHalfFloat.h:24
uint32 mRootProperties
Definition: NodeCodecQuadTreeHalfFloat.h:25
Node structure.
Definition: NodeCodecQuadTreeHalfFloat.h:48
HalfFloat mBoundsMaxY[4]
Definition: NodeCodecQuadTreeHalfFloat.h:53
HalfFloat mBoundsMinX[4]
4 child bounding boxes
Definition: NodeCodecQuadTreeHalfFloat.h:49
HalfFloat mBoundsMinZ[4]
Definition: NodeCodecQuadTreeHalfFloat.h:51
HalfFloat mBoundsMaxX[4]
Definition: NodeCodecQuadTreeHalfFloat.h:52
uint32 mNodeProperties[4]
4 child node properties
Definition: NodeCodecQuadTreeHalfFloat.h:55
HalfFloat mBoundsMinY[4]
Definition: NodeCodecQuadTreeHalfFloat.h:50
HalfFloat mBoundsMaxZ[4]
Definition: NodeCodecQuadTreeHalfFloat.h:54