Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
AABBTreeToBuffer.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
14template <class TriangleCodec, class NodeCodec>
16{
17public:
19 using NodeHeader = typename NodeCodec::Header;
20
23
26
29
32
34 bool Convert(const Array<IndexedTriangle> &inTriangles, const Array<AABBTreeBuilder::Node> &inNodes, const VertexList &inVertices, const AABBTreeBuilder::Node *inRoot, bool inStoreUserData, const char *&outError)
35 {
36 typename NodeCodec::EncodingContext node_ctx;
37 typename TriangleCodec::EncodingContext tri_ctx(inVertices);
38
39 // Child nodes out of loop so we don't constantly realloc it
41 child_nodes.reserve(NumChildrenPerNode);
42
43 // First calculate how big the tree is going to be.
44 // Since the tree can be huge for very large meshes, we don't want
45 // to reallocate the buffer as it may cause out of memory situations.
46 // This loop mimics the construction loop below.
48 size_t node_count = 1; // Start with root node
49 size_t to_process_max_size = 1; // Track size of queues so we can do a single reserve below
50 size_t to_process_triangles_max_size = 0;
51 { // A scope to free the memory associated with to_estimate and to_estimate_triangles
53 Array<const AABBTreeBuilder::Node *> to_estimate_triangles;
54 to_estimate.push_back(inRoot);
55 for (;;)
56 {
57 while (!to_estimate.empty())
58 {
59 // Get the next node to process
60 const AABBTreeBuilder::Node *node = to_estimate.back();
61 to_estimate.pop_back();
62
63 // Update total size
64 node_ctx.PrepareNodeAllocate(node, total_size);
65
66 if (node->HasChildren())
67 {
68 // Collect the first NumChildrenPerNode sub-nodes in the tree
69 child_nodes.clear(); // Won't free the memory
70 node->GetNChildren(inNodes, NumChildrenPerNode, child_nodes);
71
72 // Increment the number of nodes we're going to store
73 node_count += child_nodes.size();
74
75 // Insert in reverse order so we estimate left child first when taking nodes from the back
76 for (int idx = int(child_nodes.size()) - 1; idx >= 0; --idx)
77 {
78 // Store triangles in separate list so we process them last
79 const AABBTreeBuilder::Node *child = child_nodes[idx];
80 if (child->HasChildren())
81 {
82 to_estimate.push_back(child);
83 to_process_max_size = max(to_estimate.size(), to_process_max_size);
84 }
85 else
86 {
87 to_estimate_triangles.push_back(child);
88 to_process_triangles_max_size = max(to_estimate_triangles.size(), to_process_triangles_max_size);
89 }
90 }
91 }
92 else
93 {
94 // Update total size
95 tri_ctx.PreparePack(&inTriangles[node->mTrianglesBegin], node->mNumTriangles, inStoreUserData, total_size);
96 }
97 }
98
99 // If we've got triangles to estimate, loop again with just the triangles
100 if (to_estimate_triangles.empty())
101 break;
102 else
103 to_estimate.swap(to_estimate_triangles);
104 }
105 }
106
107 // Finalize the prepare stage for the triangle context
108 tri_ctx.FinalizePreparePack(total_size);
109
110 // Reserve the buffer
111 if (size_t(total_size) != total_size)
112 {
113 outError = "AABBTreeToBuffer: Out of memory!";
114 return false;
115 }
116 mTree.reserve(size_t(total_size));
117
118 // Add headers
119 NodeHeader *header = HeaderSize > 0? mTree.Allocate<NodeHeader>() : nullptr;
120 TriangleHeader *triangle_header = TriangleHeaderSize > 0? mTree.Allocate<TriangleHeader>() : nullptr;
121
122 struct NodeData
123 {
124 const AABBTreeBuilder::Node * mNode = nullptr; // Node that this entry belongs to
125 Vec3 mNodeBoundsMin; // Quantized node bounds
126 Vec3 mNodeBoundsMax;
127 size_t mNodeStart = size_t(-1); // Start of node in mTree
128 size_t mTriangleStart = size_t(-1); // Start of the triangle data in mTree
129 size_t mChildNodeStart[NumChildrenPerNode]; // Start of the children of the node in mTree
130 size_t mChildTrianglesStart[NumChildrenPerNode]; // Start of the triangle data in mTree
131 size_t * mParentChildNodeStart = nullptr; // Where to store mNodeStart (to patch mChildNodeStart of my parent)
132 size_t * mParentTrianglesStart = nullptr; // Where to store mTriangleStart (to patch mChildTrianglesStart of my parent)
133 uint mNumChildren = 0; // Number of children
134 };
135
136 Array<NodeData *> to_process;
137 to_process.reserve(to_process_max_size);
138 Array<NodeData *> to_process_triangles;
139 to_process_triangles.reserve(to_process_triangles_max_size);
140 Array<NodeData> node_list;
141 node_list.reserve(node_count); // Needed to ensure that array is not reallocated, so we can keep pointers in the array
142
143 NodeData root;
144 root.mNode = inRoot;
145 root.mNodeBoundsMin = inRoot->mBounds.mMin;
146 root.mNodeBoundsMax = inRoot->mBounds.mMax;
147 node_list.push_back(root);
148 to_process.push_back(&node_list.back());
149
150 for (;;)
151 {
152 while (!to_process.empty())
153 {
154 // Get the next node to process
155 NodeData *node_data = to_process.back();
156 to_process.pop_back();
157
158 // Due to quantization box could have become bigger, not smaller
159 JPH_ASSERT(AABox(node_data->mNodeBoundsMin, node_data->mNodeBoundsMax).Contains(node_data->mNode->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
160
161 // Collect the first NumChildrenPerNode sub-nodes in the tree
162 child_nodes.clear(); // Won't free the memory
163 node_data->mNode->GetNChildren(inNodes, NumChildrenPerNode, child_nodes);
164 node_data->mNumChildren = (uint)child_nodes.size();
165
166 // Fill in default child bounds
167 Vec3 child_bounds_min[NumChildrenPerNode], child_bounds_max[NumChildrenPerNode];
168 for (size_t i = 0; i < NumChildrenPerNode; ++i)
169 if (i < child_nodes.size())
170 {
171 child_bounds_min[i] = child_nodes[i]->mBounds.mMin;
172 child_bounds_max[i] = child_nodes[i]->mBounds.mMax;
173 }
174 else
175 {
176 child_bounds_min[i] = Vec3::sZero();
177 child_bounds_max[i] = Vec3::sZero();
178 }
179
180 // Start a new node
181 node_data->mNodeStart = node_ctx.NodeAllocate(node_data->mNode, node_data->mNodeBoundsMin, node_data->mNodeBoundsMax, child_nodes, child_bounds_min, child_bounds_max, mTree, outError);
182 if (node_data->mNodeStart == size_t(-1))
183 return false;
184
185 if (node_data->mNode->HasChildren())
186 {
187 // Insert in reverse order so we process left child first when taking nodes from the back
188 for (int idx = int(child_nodes.size()) - 1; idx >= 0; --idx)
189 {
190 const AABBTreeBuilder::Node *child_node = child_nodes[idx];
191
192 // Due to quantization box could have become bigger, not smaller
193 JPH_ASSERT(AABox(child_bounds_min[idx], child_bounds_max[idx]).Contains(child_node->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
194
195 // Add child to list of nodes to be processed
196 NodeData child;
197 child.mNode = child_node;
198 child.mNodeBoundsMin = child_bounds_min[idx];
199 child.mNodeBoundsMax = child_bounds_max[idx];
200 child.mParentChildNodeStart = &node_data->mChildNodeStart[idx];
201 child.mParentTrianglesStart = &node_data->mChildTrianglesStart[idx];
202 node_list.push_back(child);
203
204 // Store triangles in separate list so we process them last
205 if (child_node->HasChildren())
206 to_process.push_back(&node_list.back());
207 else
208 to_process_triangles.push_back(&node_list.back());
209 }
210 }
211 else
212 {
213 // Add triangles
214 node_data->mTriangleStart = tri_ctx.Pack(&inTriangles[node_data->mNode->mTrianglesBegin], node_data->mNode->mNumTriangles, inStoreUserData, mTree, outError);
215 if (node_data->mTriangleStart == size_t(-1))
216 return false;
217 }
218
219 // Patch offset into parent
220 if (node_data->mParentChildNodeStart != nullptr)
221 {
222 *node_data->mParentChildNodeStart = node_data->mNodeStart;
223 *node_data->mParentTrianglesStart = node_data->mTriangleStart;
224 }
225 }
226
227 // If we've got triangles to process, loop again with just the triangles
228 if (to_process_triangles.empty())
229 break;
230 else
231 to_process.swap(to_process_triangles);
232 }
233
234 // Assert that our reservation was correct (we don't know if we swapped the arrays or not)
235 JPH_ASSERT(to_process_max_size == to_process.capacity() || to_process_triangles_max_size == to_process.capacity());
236 JPH_ASSERT(to_process_max_size == to_process_triangles.capacity() || to_process_triangles_max_size == to_process_triangles.capacity());
237
238 // Finalize all nodes
239 for (NodeData &n : node_list)
240 if (!node_ctx.NodeFinalize(n.mNode, n.mNodeStart, n.mNumChildren, n.mChildNodeStart, n.mChildTrianglesStart, mTree, outError))
241 return false;
242
243 // Finalize the triangles
244 tri_ctx.Finalize(inVertices, triangle_header, mTree);
245
246 // Validate that our reservations were correct
247 if (node_count != node_list.size())
248 {
249 outError = "Internal Error: Node memory estimate was incorrect, memory corruption!";
250 return false;
251 }
252 if (total_size != mTree.size())
253 {
254 outError = "Internal Error: Tree memory estimate was incorrect, memory corruption!";
255 return false;
256 }
257
258 // Finalize the nodes
259 return node_ctx.Finalize(header, inRoot, node_list[0].mNodeStart, node_list[0].mTriangleStart, outError);
260 }
261
263 inline const ByteBuffer & GetBuffer() const
264 {
265 return mTree;
266 }
267
270 {
271 return mTree;
272 }
273
275 inline const NodeHeader * GetNodeHeader() const
276 {
277 return mTree.Get<NodeHeader>(0);
278 }
279
281 inline const TriangleHeader * GetTriangleHeader() const
282 {
283 return mTree.Get<TriangleHeader>(HeaderSize);
284 }
285
287 inline const void * GetRoot() const
288 {
289 return mTree.Get<void>(HeaderSize + TriangleHeaderSize);
290 }
291
292private:
293 ByteBuffer mTree;
294};
295
std::uint64_t uint64
Definition Core.h:485
unsigned int uint
Definition Core.h:481
#define JPH_NAMESPACE_END
Definition Core.h:414
#define JPH_NAMESPACE_BEGIN
Definition Core.h:408
#define JPH_ASSERT(...)
Definition IssueReporting.h:33
A node in the tree, contains the AABox for the tree and any child nodes or triangles.
Definition AABBTreeBuilder.h:40
uint mTrianglesBegin
Triangles (if no child nodes)
Definition AABBTreeBuilder.h:81
AABox mBounds
Bounding box.
Definition AABBTreeBuilder.h:78
uint mNumTriangles
Definition AABBTreeBuilder.h:82
void GetNChildren(const Array< Node > &inNodes, uint inN, Array< const Node * > &outChildren) const
Recursively get children (breadth first) to get in total inN children (or less if there are no more)
Definition AABBTreeBuilder.cpp:76
bool HasChildren() const
Check if this node has any children.
Definition AABBTreeBuilder.h:51
Conversion algorithm that converts an AABB tree to an optimized binary buffer.
Definition AABBTreeToBuffer.h:16
static const int TriangleHeaderSize
Size in bytes of the header for the triangles.
Definition AABBTreeToBuffer.h:31
typename TriangleCodec::TriangleHeader TriangleHeader
Header for the triangles.
Definition AABBTreeToBuffer.h:28
const ByteBuffer & GetBuffer() const
Get resulting data.
Definition AABBTreeToBuffer.h:263
typename NodeCodec::Header NodeHeader
Header for the tree.
Definition AABBTreeToBuffer.h:19
static const int HeaderSize
Size in bytes of the header of the tree.
Definition AABBTreeToBuffer.h:22
static const int NumChildrenPerNode
Maximum number of children per node in the tree.
Definition AABBTreeToBuffer.h:25
bool Convert(const Array< IndexedTriangle > &inTriangles, const Array< AABBTreeBuilder::Node > &inNodes, const VertexList &inVertices, const AABBTreeBuilder::Node *inRoot, bool inStoreUserData, const char *&outError)
Convert AABB tree. Returns false if failed.
Definition AABBTreeToBuffer.h:34
const TriangleHeader * GetTriangleHeader() const
Get header for triangles.
Definition AABBTreeToBuffer.h:281
const NodeHeader * GetNodeHeader() const
Get header for tree.
Definition AABBTreeToBuffer.h:275
ByteBuffer & GetBuffer()
Get resulting data.
Definition AABBTreeToBuffer.h:269
const void * GetRoot() const
Get root of resulting tree.
Definition AABBTreeToBuffer.h:287
Axis aligned box.
Definition AABox.h:16
Vec3 mMin
Bounding box min and max.
Definition AABox.h:309
bool Contains(const AABox &inOther) const
Check if this box contains another box.
Definition AABox.h:146
Vec3 mMax
Definition AABox.h:310
Definition Array.h:36
void pop_back()
Remove element from the back of the array.
Definition Array.h:307
bool empty() const
Returns true if there are no elements in the array.
Definition Array.h:314
size_type capacity() const
Returns maximum amount of elements the array can hold.
Definition Array.h:326
const T & back() const
Last element in the array.
Definition Array.h:494
void swap(Array< T, Allocator > &inRHS) noexcept
Swap the contents of two arrays.
Definition Array.h:344
size_type size() const
Returns amount of elements in the array.
Definition Array.h:320
void clear()
Destruct all elements and set length to zero.
Definition Array.h:145
void push_back(const T &inValue)
Add element to the back of the array.
Definition Array.h:277
void reserve(size_type inNewSize)
Reserve array space.
Definition Array.h:113
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
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
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
This class is used to encode and compress triangle data into a byte buffer.
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:135
void FinalizePreparePack(uint64 &ioBufferSize)
Mimics the size the Finalize() call would add to ioBufferSize.
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:186
void Finalize(const VertexList &inVertices, TriangleHeader *ioHeader, ByteBuffer &ioBuffer) const
After all triangles have been packed, this finalizes the header and triangle buffer.
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:294
size_t Pack(const IndexedTriangle *inTriangles, uint inNumTriangles, bool inStoreUserData, ByteBuffer &ioBuffer, const char *&outError)
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:205
void PreparePack(const IndexedTriangle *inTriangles, uint inNumTriangles, bool inStoreUserData, uint64 &ioBufferSize)
Mimics the size a call to Pack() would add to the buffer.
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:147
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:28
static constexpr int TriangleHeaderSize
Size of the header (an empty struct is always > 0 bytes so this needs a separate variable)
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:35
Definition Vec3.h:17
static JPH_INLINE Vec3 sZero()
Vector with all zeros.
Definition Vec3.inl:103
Header for the tree.
Definition NodeCodecQuadTreeHalfFloat.h:21