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
14{
15public:
17 static constexpr int NumChildrenPerNode = 4;
18
28
30 static constexpr int HeaderSize = sizeof(Header);
31
33 static constexpr int StackSize = 128;
34
36 enum : uint32
37 {
45 };
46
58
59 static_assert(sizeof(Node) == 64, "Node should be 64 bytes");
60
63 {
64 public:
66 void PrepareNodeAllocate(const AABBTreeBuilder::Node *inNode, uint64 &ioBufferSize) const
67 {
68 // We don't emit nodes for leafs
69 if (!inNode->HasChildren())
70 return;
71
72 // Add size of node
73 ioBufferSize += sizeof(Node);
74 }
75
81 size_t 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
82 {
83 // We don't emit nodes for leafs
84 if (!inNode->HasChildren())
85 return ioBuffer.size();
86
87 // Remember the start of the node
88 size_t node_start = ioBuffer.size();
89
90 // Fill in bounds
91 Node *node = ioBuffer.Allocate<Node>();
92
93 for (size_t i = 0; i < 4; ++i)
94 {
95 if (i < ioChildren.size())
96 {
97 const AABBTreeBuilder::Node *this_node = ioChildren[i];
98
99 // Copy bounding box
106
107 // Store triangle count
108 node->mNodeProperties[i] = this_node->GetTriangleCount() << TRIANGLE_COUNT_SHIFT;
109 if (this_node->GetTriangleCount() >= TRIANGLE_COUNT_MASK)
110 {
111 outError = "NodeCodecQuadTreeHalfFloat: Too many triangles";
112 return size_t(-1);
113 }
114 }
115 else
116 {
117 // Make this an invalid triangle node
119
120 // Make bounding box invalid
121 node->mBoundsMinX[i] = HALF_FLT_MAX;
122 node->mBoundsMinY[i] = HALF_FLT_MAX;
123 node->mBoundsMinZ[i] = HALF_FLT_MAX;
124 node->mBoundsMaxX[i] = HALF_FLT_MAX;
125 node->mBoundsMaxY[i] = HALF_FLT_MAX;
126 node->mBoundsMaxZ[i] = HALF_FLT_MAX;
127 }
128 }
129
130 // 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
131 for (int i = 0; i < NumChildrenPerNode; ++i)
132 {
133 outChildBoundsMin[i] = inNodeBoundsMin;
134 outChildBoundsMax[i] = inNodeBoundsMax;
135 }
136
137 return node_start;
138 }
139
141 bool NodeFinalize(const AABBTreeBuilder::Node *inNode, size_t inNodeStart, uint inNumChildren, const size_t *inChildrenNodeStart, const size_t *inChildrenTrianglesStart, ByteBuffer &ioBuffer, const char *&outError)
142 {
143 if (!inNode->HasChildren())
144 return true;
145
146 Node *node = ioBuffer.Get<Node>(inNodeStart);
147 for (uint i = 0; i < inNumChildren; ++i)
148 {
149 size_t offset;
150 if (node->mNodeProperties[i] != 0)
151 {
152 // This is a triangle block
153 offset = inChildrenTrianglesStart[i];
154
155 // Store highest block with triangles so we can count the number of bits we need
156 mHighestTriangleBlock = max(mHighestTriangleBlock, offset);
157 }
158 else
159 {
160 // This is a node block
161 offset = inChildrenNodeStart[i];
162 }
163
164 // Store offset of next node / triangles
165 if (offset & OFFSET_NON_SIGNIFICANT_MASK)
166 {
167 outError = "NodeCodecQuadTreeHalfFloat: Internal Error: Offset has non-significant bits set";
168 return false;
169 }
171 if (offset > OFFSET_MASK)
172 {
173 outError = "NodeCodecQuadTreeHalfFloat: Offset too large. Too much data.";
174 return false;
175 }
176 node->mNodeProperties[i] |= uint32(offset);
177 }
178
179 return true;
180 }
181
183 bool Finalize(Header *outHeader, const AABBTreeBuilder::Node *inRoot, size_t inRootNodeStart, size_t inRootTrianglesStart, const char *&outError) const
184 {
185 // Check if we can address the root node
186 size_t offset = inRoot->HasChildren()? inRootNodeStart : inRootTrianglesStart;
187 if (offset & OFFSET_NON_SIGNIFICANT_MASK)
188 {
189 outError = "NodeCodecQuadTreeHalfFloat: Internal Error: Offset has non-significant bits set";
190 return false;
191 }
193 if (offset > OFFSET_MASK)
194 {
195 outError = "NodeCodecQuadTreeHalfFloat: Offset too large. Too much data.";
196 return false;
197 }
198
199 // If the root has triangles, we need to take that offset instead since the mHighestTriangleBlock will be zero
200 size_t highest_triangle_block = inRootTrianglesStart != size_t(-1)? inRootTrianglesStart : mHighestTriangleBlock;
201 highest_triangle_block >>= OFFSET_NON_SIGNIFICANT_BITS;
202
203 inRoot->mBounds.mMin.StoreFloat3(&outHeader->mRootBoundsMin);
204 inRoot->mBounds.mMax.StoreFloat3(&outHeader->mRootBoundsMax);
205 outHeader->mRootProperties = uint32(offset) + (inRoot->GetTriangleCount() << TRIANGLE_COUNT_SHIFT);
206 outHeader->mBlockIDBits = uint8(32 - CountLeadingZeros(uint32(highest_triangle_block)));
207 if (inRoot->GetTriangleCount() >= TRIANGLE_COUNT_MASK)
208 {
209 outError = "NodeCodecQuadTreeHalfFloat: Too many triangles";
210 return false;
211 }
212
213 return true;
214 }
215
216 private:
217 size_t mHighestTriangleBlock = 0;
218 };
219
222 {
223 public:
225 inline static uint sTriangleBlockIDBits(const Header *inHeader)
226 {
227 return inHeader->mBlockIDBits;
228 }
229
231 inline static const void * sGetTriangleBlockStart(const uint8 *inBufferStart, uint inTriangleBlockID)
232 {
233 return inBufferStart + (inTriangleBlockID << OFFSET_NON_SIGNIFICANT_BITS);
234 }
235
237 JPH_INLINE explicit DecodingContext(const Header *inHeader)
238 {
239 // Start with the root node on the stack
240 mNodeStack[0] = inHeader->mRootProperties;
241 }
242
244 template <class TriangleContext, class Visitor>
245 JPH_INLINE void WalkTree(const uint8 *inBufferStart, const TriangleContext &inTriangleContext, Visitor &ioVisitor)
246 {
247 do
248 {
249 // Test if node contains triangles
250 uint32 node_properties = mNodeStack[mTop];
251 uint32 tri_count = node_properties >> TRIANGLE_COUNT_SHIFT;
252 if (tri_count == 0)
253 {
254 const Node *node = reinterpret_cast<const Node *>(inBufferStart + (node_properties << OFFSET_NON_SIGNIFICANT_BITS));
255
256 // Unpack bounds
257 #ifdef JPH_CPU_BIG_ENDIAN
258 Vec4 bounds_minx = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMinX[0] + (node->mBoundsMinX[1] << 16), node->mBoundsMinX[2] + (node->mBoundsMinX[3] << 16), 0, 0));
259 Vec4 bounds_miny = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMinY[0] + (node->mBoundsMinY[1] << 16), node->mBoundsMinY[2] + (node->mBoundsMinY[3] << 16), 0, 0));
260 Vec4 bounds_minz = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMinZ[0] + (node->mBoundsMinZ[1] << 16), node->mBoundsMinZ[2] + (node->mBoundsMinZ[3] << 16), 0, 0));
261
262 Vec4 bounds_maxx = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMaxX[0] + (node->mBoundsMaxX[1] << 16), node->mBoundsMaxX[2] + (node->mBoundsMaxX[3] << 16), 0, 0));
263 Vec4 bounds_maxy = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMaxY[0] + (node->mBoundsMaxY[1] << 16), node->mBoundsMaxY[2] + (node->mBoundsMaxY[3] << 16), 0, 0));
264 Vec4 bounds_maxz = HalfFloatConversion::ToFloat(UVec4(node->mBoundsMaxZ[0] + (node->mBoundsMaxZ[1] << 16), node->mBoundsMaxZ[2] + (node->mBoundsMaxZ[3] << 16), 0, 0));
265 #else
266 UVec4 bounds_minxy = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMinX[0]));
267 Vec4 bounds_minx = HalfFloatConversion::ToFloat(bounds_minxy);
269
270 UVec4 bounds_minzmaxx = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMinZ[0]));
271 Vec4 bounds_minz = HalfFloatConversion::ToFloat(bounds_minzmaxx);
273
274 UVec4 bounds_maxyz = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&node->mBoundsMaxY[0]));
275 Vec4 bounds_maxy = HalfFloatConversion::ToFloat(bounds_maxyz);
277 #endif
278
279 // Load properties for 4 children
280 UVec4 properties = UVec4::sLoadInt4(&node->mNodeProperties[0]);
281
282 // Check which sub nodes to visit
283 int num_results = ioVisitor.VisitNodes(bounds_minx, bounds_miny, bounds_minz, bounds_maxx, bounds_maxy, bounds_maxz, properties, mTop);
284
285 // Push them onto the stack
286 JPH_ASSERT(mTop + 4 < StackSize);
287 properties.StoreInt4(&mNodeStack[mTop]);
288 mTop += num_results;
289 }
290 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)
291 {
292 // Node contains triangles, do individual tests
293 uint32 triangle_block_id = node_properties & OFFSET_MASK;
294 const void *triangles = sGetTriangleBlockStart(inBufferStart, triangle_block_id);
295
296 ioVisitor.VisitTriangles(inTriangleContext, triangles, tri_count, triangle_block_id);
297 }
298
299 // Check if we're done
300 if (ioVisitor.ShouldAbort())
301 break;
302
303 // Fetch next node until we find one that the visitor wants to see
304 do
305 --mTop;
306 while (mTop >= 0 && !ioVisitor.ShouldVisitNode(mTop));
307 }
308 while (mTop >= 0);
309 }
310
312 bool IsDoneWalking() const
313 {
314 return mTop < 0;
315 }
316
317 private:
318 uint32 mNodeStack[StackSize];
319 int mTop = 0;
320 };
321};
322
std::uint8_t uint8
Definition Core.h:482
std::uint64_t uint64
Definition Core.h:485
unsigned int uint
Definition Core.h:481
#define JPH_NAMESPACE_END
Definition Core.h:414
std::uint32_t uint32
Definition Core.h:484
#define JPH_NAMESPACE_BEGIN
Definition Core.h:408
uint16 HalfFloat
Definition HalfFloat.h:12
#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:134
@ 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:78
uint GetTriangleCount() const
Get number of triangles in this node.
Definition AABBTreeBuilder.h:48
bool HasChildren() const
Check if this node has any children.
Definition AABBTreeBuilder.h:51
Vec3 mMin
Bounding box min and max.
Definition AABox.h:309
Vec3 mMax
Definition AABox.h:310
Definition Array.h:36
size_type size() const
Returns amount of elements in the array.
Definition Array.h:320
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
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:222
bool IsDoneWalking() const
This can be used to have the visitor early out (ioVisitor.ShouldAbort() returns true) and later conti...
Definition NodeCodecQuadTreeHalfFloat.h:312
static uint sTriangleBlockIDBits(const Header *inHeader)
Get the amount of bits needed to store an ID to a triangle block.
Definition NodeCodecQuadTreeHalfFloat.h:225
JPH_INLINE DecodingContext(const Header *inHeader)
Constructor.
Definition NodeCodecQuadTreeHalfFloat.h:237
static const void * sGetTriangleBlockStart(const uint8 *inBufferStart, uint inTriangleBlockID)
Convert a triangle block ID to the start of the triangle buffer.
Definition NodeCodecQuadTreeHalfFloat.h:231
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:245
This class encodes and compresses quad tree nodes.
Definition NodeCodecQuadTreeHalfFloat.h:63
bool NodeFinalize(const AABBTreeBuilder::Node *inNode, size_t inNodeStart, uint inNumChildren, const size_t *inChildrenNodeStart, const size_t *inChildrenTrianglesStart, ByteBuffer &ioBuffer, const char *&outError)
Once all nodes have been added, this call finalizes all nodes by patching in the offsets of the child...
Definition NodeCodecQuadTreeHalfFloat.h:141
size_t 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:81
bool Finalize(Header *outHeader, const AABBTreeBuilder::Node *inRoot, size_t inRootNodeStart, size_t inRootTrianglesStart, const char *&outError) const
Once all nodes have been finalized, this will finalize the header of the nodes.
Definition NodeCodecQuadTreeHalfFloat.h:183
void PrepareNodeAllocate(const AABBTreeBuilder::Node *inNode, uint64 &ioBufferSize) const
Mimics the size a call to NodeAllocate() would add to the buffer.
Definition NodeCodecQuadTreeHalfFloat.h:66
Definition NodeCodecQuadTreeHalfFloat.h:14
static constexpr int StackSize
Stack size to use during DecodingContext::sWalkTree.
Definition NodeCodecQuadTreeHalfFloat.h:33
static constexpr int HeaderSize
Size of the header (an empty struct is always > 0 bytes so this needs a separate variable)
Definition NodeCodecQuadTreeHalfFloat.h:30
static constexpr int NumChildrenPerNode
Number of child nodes of this node.
Definition NodeCodecQuadTreeHalfFloat.h:17
@ OFFSET_BITS
Definition NodeCodecQuadTreeHalfFloat.h:41
@ OFFSET_MASK
Definition NodeCodecQuadTreeHalfFloat.h:42
@ TRIANGLE_COUNT_MASK
Definition NodeCodecQuadTreeHalfFloat.h:40
@ OFFSET_NON_SIGNIFICANT_MASK
Definition NodeCodecQuadTreeHalfFloat.h:44
@ OFFSET_NON_SIGNIFICANT_BITS
Definition NodeCodecQuadTreeHalfFloat.h:43
@ TRIANGLE_COUNT_SHIFT
Definition NodeCodecQuadTreeHalfFloat.h:39
@ TRIANGLE_COUNT_BITS
Definition NodeCodecQuadTreeHalfFloat.h:38
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:767
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:195
JPH_INLINE HalfFloat FromFloat(float inV)
Convert a float (32-bits) to a half float (16-bits)
Definition HalfFloat.h:133
Header for the tree.
Definition NodeCodecQuadTreeHalfFloat.h:21
Float3 mRootBoundsMax
Definition NodeCodecQuadTreeHalfFloat.h:23
uint8 mBlockIDBits
Number of bits to address a triangle block.
Definition NodeCodecQuadTreeHalfFloat.h:25
uint32 mRootProperties
Definition NodeCodecQuadTreeHalfFloat.h:24
uint8 mPadding[3]
Definition NodeCodecQuadTreeHalfFloat.h:26
Float3 mRootBoundsMin
Definition NodeCodecQuadTreeHalfFloat.h:22
Node structure.
Definition NodeCodecQuadTreeHalfFloat.h:49
HalfFloat mBoundsMaxY[4]
Definition NodeCodecQuadTreeHalfFloat.h:54
HalfFloat mBoundsMinY[4]
Definition NodeCodecQuadTreeHalfFloat.h:51
HalfFloat mBoundsMaxX[4]
Definition NodeCodecQuadTreeHalfFloat.h:53
HalfFloat mBoundsMaxZ[4]
Definition NodeCodecQuadTreeHalfFloat.h:55
HalfFloat mBoundsMinZ[4]
Definition NodeCodecQuadTreeHalfFloat.h:52
uint32 mNodeProperties[4]
4 child node properties
Definition NodeCodecQuadTreeHalfFloat.h:56
HalfFloat mBoundsMinX[4]
4 child bounding boxes
Definition NodeCodecQuadTreeHalfFloat.h:50