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 const typename NodeCodec::EncodingContext node_ctx;
37 typename TriangleCodec::EncodingContext tri_ctx(inVertices);
38
39 // Estimate the amount of memory required
40 uint tri_count = inRoot->GetTriangleCountInTree(inNodes);
41 uint node_count = inRoot->GetNodeCount(inNodes);
42 uint nodes_size = node_ctx.GetPessimisticMemoryEstimate(node_count);
43 uint total_size = HeaderSize + TriangleHeaderSize + nodes_size + tri_ctx.GetPessimisticMemoryEstimate(tri_count, inStoreUserData);
44 mTree.reserve(total_size);
45
46 // Reset counters
47 mNodesSize = 0;
48
49 // Add headers
50 NodeHeader *header = HeaderSize > 0? mTree.Allocate<NodeHeader>() : nullptr;
51 TriangleHeader *triangle_header = TriangleHeaderSize > 0? mTree.Allocate<TriangleHeader>() : nullptr;
52
53 struct NodeData
54 {
55 const AABBTreeBuilder::Node * mNode = nullptr; // Node that this entry belongs to
56 Vec3 mNodeBoundsMin; // Quantized node bounds
57 Vec3 mNodeBoundsMax;
58 uint mNodeStart = uint(-1); // Start of node in mTree
59 uint mTriangleStart = uint(-1); // Start of the triangle data in mTree
60 uint mNumChildren = 0; // Number of children
61 uint mChildNodeStart[NumChildrenPerNode]; // Start of the children of the node in mTree
62 uint mChildTrianglesStart[NumChildrenPerNode]; // Start of the triangle data in mTree
63 uint * mParentChildNodeStart = nullptr; // Where to store mNodeStart (to patch mChildNodeStart of my parent)
64 uint * mParentTrianglesStart = nullptr; // Where to store mTriangleStart (to patch mChildTrianglesStart of my parent)
65 };
66
67 Array<NodeData *> to_process;
68 Array<NodeData *> to_process_triangles;
69 Array<NodeData> node_list;
70
71 node_list.reserve(node_count); // Needed to ensure that array is not reallocated, so we can keep pointers in the array
72
73 NodeData root;
74 root.mNode = inRoot;
75 root.mNodeBoundsMin = inRoot->mBounds.mMin;
76 root.mNodeBoundsMax = inRoot->mBounds.mMax;
77 node_list.push_back(root);
78 to_process.push_back(&node_list.back());
79
80 // Child nodes out of loop so we don't constantly realloc it
82 child_nodes.reserve(NumChildrenPerNode);
83
84 for (;;)
85 {
86 while (!to_process.empty())
87 {
88 // Get the next node to process
89 NodeData *node_data = to_process.back();
90 to_process.pop_back();
91
92 // Due to quantization box could have become bigger, not smaller
93 JPH_ASSERT(AABox(node_data->mNodeBoundsMin, node_data->mNodeBoundsMax).Contains(node_data->mNode->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
94
95 // Collect the first NumChildrenPerNode sub-nodes in the tree
96 child_nodes.clear(); // Won't free the memory
97 node_data->mNode->GetNChildren(inNodes, NumChildrenPerNode, child_nodes);
98 node_data->mNumChildren = (uint)child_nodes.size();
99
100 // Fill in default child bounds
101 Vec3 child_bounds_min[NumChildrenPerNode], child_bounds_max[NumChildrenPerNode];
102 for (size_t i = 0; i < NumChildrenPerNode; ++i)
103 if (i < child_nodes.size())
104 {
105 child_bounds_min[i] = child_nodes[i]->mBounds.mMin;
106 child_bounds_max[i] = child_nodes[i]->mBounds.mMax;
107 }
108 else
109 {
110 child_bounds_min[i] = Vec3::sZero();
111 child_bounds_max[i] = Vec3::sZero();
112 }
113
114 // Start a new node
115 uint old_size = (uint)mTree.size();
116 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);
117 if (node_data->mNodeStart == uint(-1))
118 return false;
119 mNodesSize += (uint)mTree.size() - old_size;
120
121 if (node_data->mNode->HasChildren())
122 {
123 // Insert in reverse order so we process left child first when taking nodes from the back
124 for (int idx = int(child_nodes.size()) - 1; idx >= 0; --idx)
125 {
126 // Due to quantization box could have become bigger, not smaller
127 JPH_ASSERT(AABox(child_bounds_min[idx], child_bounds_max[idx]).Contains(child_nodes[idx]->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
128
129 // Add child to list of nodes to be processed
130 NodeData child;
131 child.mNode = child_nodes[idx];
132 child.mNodeBoundsMin = child_bounds_min[idx];
133 child.mNodeBoundsMax = child_bounds_max[idx];
134 child.mParentChildNodeStart = &node_data->mChildNodeStart[idx];
135 child.mParentTrianglesStart = &node_data->mChildTrianglesStart[idx];
136 NodeData *old = &node_list[0];
137 node_list.push_back(child);
138 if (old != &node_list[0])
139 {
140 outError = "Internal Error: Array reallocated, memory corruption!";
141 return false;
142 }
143
144 // Store triangles in separate list so we process them last
145 if (node_list.back().mNode->HasChildren())
146 to_process.push_back(&node_list.back());
147 else
148 to_process_triangles.push_back(&node_list.back());
149 }
150 }
151 else
152 {
153 // Add triangles
154 node_data->mTriangleStart = tri_ctx.Pack(&inTriangles[node_data->mNode->mTrianglesBegin], node_data->mNode->mNumTriangles, inStoreUserData, mTree, outError);
155 if (node_data->mTriangleStart == uint(-1))
156 return false;
157 }
158
159 // Patch offset into parent
160 if (node_data->mParentChildNodeStart != nullptr)
161 {
162 *node_data->mParentChildNodeStart = node_data->mNodeStart;
163 *node_data->mParentTrianglesStart = node_data->mTriangleStart;
164 }
165 }
166
167 // If we've got triangles to process, loop again with just the triangles
168 if (to_process_triangles.empty())
169 break;
170 else
171 to_process.swap(to_process_triangles);
172 }
173
174 // Finalize all nodes
175 for (NodeData &n : node_list)
176 if (!node_ctx.NodeFinalize(n.mNode, n.mNodeStart, n.mNumChildren, n.mChildNodeStart, n.mChildTrianglesStart, mTree, outError))
177 return false;
178
179 // Finalize the triangles
180 tri_ctx.Finalize(inVertices, triangle_header, mTree);
181
182 // Validate that we reserved enough memory
183 if (nodes_size < mNodesSize)
184 {
185 outError = "Internal Error: Not enough memory reserved for nodes!";
186 return false;
187 }
188 if (total_size < (uint)mTree.size())
189 {
190 outError = "Internal Error: Not enough memory reserved for triangles!";
191 return false;
192 }
193
194 // Finalize the nodes
195 if (!node_ctx.Finalize(header, inRoot, node_list[0].mNodeStart, node_list[0].mTriangleStart, outError))
196 return false;
197
198 // Shrink the tree, this will invalidate the header and triangle_header variables
199 mTree.shrink_to_fit();
200
201 return true;
202 }
203
205 inline const ByteBuffer & GetBuffer() const
206 {
207 return mTree;
208 }
209
212 {
213 return mTree;
214 }
215
217 inline const NodeHeader * GetNodeHeader() const
218 {
219 return mTree.Get<NodeHeader>(0);
220 }
221
223 inline const TriangleHeader * GetTriangleHeader() const
224 {
225 return mTree.Get<TriangleHeader>(HeaderSize);
226 }
227
229 inline const void * GetRoot() const
230 {
231 return mTree.Get<void>(HeaderSize + TriangleHeaderSize);
232 }
233
234private:
235 ByteBuffer mTree;
236 uint mNodesSize;
237};
238
unsigned int uint
Definition Core.h:453
#define JPH_NAMESPACE_END
Definition Core.h:379
#define JPH_NAMESPACE_BEGIN
Definition Core.h:373
#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
AABox mBounds
Bounding box.
Definition AABBTreeBuilder.h:78
uint GetTriangleCountInTree(const Array< Node > &inNodes) const
Get triangle count in tree.
Definition AABBTreeBuilder.cpp:51
uint GetNodeCount(const Array< Node > &inNodes) const
Number of nodes in tree.
Definition AABBTreeBuilder.cpp:35
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:205
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:223
const NodeHeader * GetNodeHeader() const
Get header for tree.
Definition AABBTreeToBuffer.h:217
ByteBuffer & GetBuffer()
Get resulting data.
Definition AABBTreeToBuffer.h:211
const void * GetRoot() const
Get root of resulting tree.
Definition AABBTreeToBuffer.h:229
Axis aligned box.
Definition AABox.h:16
Vec3 mMin
Bounding box min and max.
Definition AABox.h:308
bool Contains(const AABox &inOther) const
Check if this box contains another box.
Definition AABox.h:145
Vec3 mMax
Definition AABox.h:309
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
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 shrink_to_fit()
Reduce the capacity of the array to match its size.
Definition Array.h:332
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: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
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
static constexpr int NumChildrenPerNode
Number of child nodes of this node.
Definition NodeCodecQuadTreeHalfFloat.h:18
This class is used to encode and compress triangle data into a byte buffer.
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:133
uint Pack(const IndexedTriangle *inTriangles, uint inNumTriangles, bool inStoreUserData, ByteBuffer &ioBuffer, const char *&outError)
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:152
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:234
uint GetPessimisticMemoryEstimate(uint inTriangleCount, bool inStoreUserData) const
Get an upper bound on the amount of bytes needed to store inTriangleCount triangles.
Definition TriangleCodecIndexed8BitPackSOA4Flags.h:144
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:107
Header for the tree.
Definition NodeCodecQuadTreeHalfFloat.h:22