AABBTreeToBuffer.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/AABBTree/AABBTreeBuilder.h>
  6. #include <Jolt/Core/ByteBuffer.h>
  7. #include <Jolt/Geometry/IndexedTriangle.h>
  8. JPH_NAMESPACE_BEGIN
  9. /// Conversion algorithm that converts an AABB tree to an optimized binary buffer
  10. template <class TriangleCodec, class NodeCodec>
  11. class AABBTreeToBuffer
  12. {
  13. public:
  14. /// Header for the tree
  15. using NodeHeader = typename NodeCodec::Header;
  16. /// Size in bytes of the header of the tree
  17. static const int HeaderSize = NodeCodec::HeaderSize;
  18. /// Maximum number of children per node in the tree
  19. static const int NumChildrenPerNode = NodeCodec::NumChildrenPerNode;
  20. /// Header for the triangles
  21. using TriangleHeader = typename TriangleCodec::TriangleHeader;
  22. /// Size in bytes of the header for the triangles
  23. static const int TriangleHeaderSize = TriangleCodec::TriangleHeaderSize;
  24. /// Convert AABB tree. Returns false if failed.
  25. bool Convert(const Array<IndexedTriangle> &inTriangles, const Array<AABBTreeBuilder::Node> &inNodes, const VertexList &inVertices, const AABBTreeBuilder::Node *inRoot, bool inStoreUserData, const char *&outError)
  26. {
  27. typename NodeCodec::EncodingContext node_ctx;
  28. typename TriangleCodec::EncodingContext tri_ctx(inVertices);
  29. // Child nodes out of loop so we don't constantly realloc it
  30. Array<const AABBTreeBuilder::Node *> child_nodes;
  31. child_nodes.reserve(NumChildrenPerNode);
  32. // First calculate how big the tree is going to be.
  33. // Since the tree can be huge for very large meshes, we don't want
  34. // to reallocate the buffer as it may cause out of memory situations.
  35. // This loop mimics the construction loop below.
  36. uint64 total_size = HeaderSize + TriangleHeaderSize;
  37. size_t node_count = 1; // Start with root node
  38. size_t to_process_max_size = 1; // Track size of queues so we can do a single reserve below
  39. size_t to_process_triangles_max_size = 0;
  40. { // A scope to free the memory associated with to_estimate and to_estimate_triangles
  41. Array<const AABBTreeBuilder::Node *> to_estimate;
  42. Array<const AABBTreeBuilder::Node *> to_estimate_triangles;
  43. to_estimate.push_back(inRoot);
  44. for (;;)
  45. {
  46. while (!to_estimate.empty())
  47. {
  48. // Get the next node to process
  49. const AABBTreeBuilder::Node *node = to_estimate.back();
  50. to_estimate.pop_back();
  51. // Update total size
  52. node_ctx.PrepareNodeAllocate(node, total_size);
  53. if (node->HasChildren())
  54. {
  55. // Collect the first NumChildrenPerNode sub-nodes in the tree
  56. child_nodes.clear(); // Won't free the memory
  57. node->GetNChildren(inNodes, NumChildrenPerNode, child_nodes);
  58. // Increment the number of nodes we're going to store
  59. node_count += child_nodes.size();
  60. // Insert in reverse order so we estimate left child first when taking nodes from the back
  61. for (int idx = int(child_nodes.size()) - 1; idx >= 0; --idx)
  62. {
  63. // Store triangles in separate list so we process them last
  64. const AABBTreeBuilder::Node *child = child_nodes[idx];
  65. if (child->HasChildren())
  66. {
  67. to_estimate.push_back(child);
  68. to_process_max_size = max(to_estimate.size(), to_process_max_size);
  69. }
  70. else
  71. {
  72. to_estimate_triangles.push_back(child);
  73. to_process_triangles_max_size = max(to_estimate_triangles.size(), to_process_triangles_max_size);
  74. }
  75. }
  76. }
  77. else
  78. {
  79. // Update total size
  80. tri_ctx.PreparePack(&inTriangles[node->mTrianglesBegin], node->mNumTriangles, inStoreUserData, total_size);
  81. }
  82. }
  83. // If we've got triangles to estimate, loop again with just the triangles
  84. if (to_estimate_triangles.empty())
  85. break;
  86. else
  87. to_estimate.swap(to_estimate_triangles);
  88. }
  89. }
  90. // Finalize the prepare stage for the triangle context
  91. tri_ctx.FinalizePreparePack(total_size);
  92. // Reserve the buffer
  93. if (size_t(total_size) != total_size)
  94. {
  95. outError = "AABBTreeToBuffer: Out of memory!";
  96. return false;
  97. }
  98. mTree.reserve(size_t(total_size));
  99. // Add headers
  100. NodeHeader *header = HeaderSize > 0? mTree.Allocate<NodeHeader>() : nullptr;
  101. TriangleHeader *triangle_header = TriangleHeaderSize > 0? mTree.Allocate<TriangleHeader>() : nullptr;
  102. struct NodeData
  103. {
  104. const AABBTreeBuilder::Node * mNode = nullptr; // Node that this entry belongs to
  105. Vec3 mNodeBoundsMin; // Quantized node bounds
  106. Vec3 mNodeBoundsMax;
  107. size_t mNodeStart = size_t(-1); // Start of node in mTree
  108. size_t mTriangleStart = size_t(-1); // Start of the triangle data in mTree
  109. size_t mChildNodeStart[NumChildrenPerNode]; // Start of the children of the node in mTree
  110. size_t mChildTrianglesStart[NumChildrenPerNode]; // Start of the triangle data in mTree
  111. size_t * mParentChildNodeStart = nullptr; // Where to store mNodeStart (to patch mChildNodeStart of my parent)
  112. size_t * mParentTrianglesStart = nullptr; // Where to store mTriangleStart (to patch mChildTrianglesStart of my parent)
  113. uint mNumChildren = 0; // Number of children
  114. };
  115. Array<NodeData *> to_process;
  116. to_process.reserve(to_process_max_size);
  117. Array<NodeData *> to_process_triangles;
  118. to_process_triangles.reserve(to_process_triangles_max_size);
  119. Array<NodeData> node_list;
  120. node_list.reserve(node_count); // Needed to ensure that array is not reallocated, so we can keep pointers in the array
  121. NodeData root;
  122. root.mNode = inRoot;
  123. root.mNodeBoundsMin = inRoot->mBounds.mMin;
  124. root.mNodeBoundsMax = inRoot->mBounds.mMax;
  125. node_list.push_back(root);
  126. to_process.push_back(&node_list.back());
  127. for (;;)
  128. {
  129. while (!to_process.empty())
  130. {
  131. // Get the next node to process
  132. NodeData *node_data = to_process.back();
  133. to_process.pop_back();
  134. // Due to quantization box could have become bigger, not smaller
  135. JPH_ASSERT(AABox(node_data->mNodeBoundsMin, node_data->mNodeBoundsMax).Contains(node_data->mNode->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
  136. // Collect the first NumChildrenPerNode sub-nodes in the tree
  137. child_nodes.clear(); // Won't free the memory
  138. node_data->mNode->GetNChildren(inNodes, NumChildrenPerNode, child_nodes);
  139. node_data->mNumChildren = (uint)child_nodes.size();
  140. // Fill in default child bounds
  141. Vec3 child_bounds_min[NumChildrenPerNode], child_bounds_max[NumChildrenPerNode];
  142. for (size_t i = 0; i < NumChildrenPerNode; ++i)
  143. if (i < child_nodes.size())
  144. {
  145. child_bounds_min[i] = child_nodes[i]->mBounds.mMin;
  146. child_bounds_max[i] = child_nodes[i]->mBounds.mMax;
  147. }
  148. else
  149. {
  150. child_bounds_min[i] = Vec3::sZero();
  151. child_bounds_max[i] = Vec3::sZero();
  152. }
  153. // Start a new node
  154. 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);
  155. if (node_data->mNodeStart == size_t(-1))
  156. return false;
  157. if (node_data->mNode->HasChildren())
  158. {
  159. // Insert in reverse order so we process left child first when taking nodes from the back
  160. for (int idx = int(child_nodes.size()) - 1; idx >= 0; --idx)
  161. {
  162. const AABBTreeBuilder::Node *child_node = child_nodes[idx];
  163. // Due to quantization box could have become bigger, not smaller
  164. JPH_ASSERT(AABox(child_bounds_min[idx], child_bounds_max[idx]).Contains(child_node->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
  165. // Add child to list of nodes to be processed
  166. NodeData child;
  167. child.mNode = child_node;
  168. child.mNodeBoundsMin = child_bounds_min[idx];
  169. child.mNodeBoundsMax = child_bounds_max[idx];
  170. child.mParentChildNodeStart = &node_data->mChildNodeStart[idx];
  171. child.mParentTrianglesStart = &node_data->mChildTrianglesStart[idx];
  172. node_list.push_back(child);
  173. // Store triangles in separate list so we process them last
  174. if (child_node->HasChildren())
  175. to_process.push_back(&node_list.back());
  176. else
  177. to_process_triangles.push_back(&node_list.back());
  178. }
  179. }
  180. else
  181. {
  182. // Add triangles
  183. node_data->mTriangleStart = tri_ctx.Pack(&inTriangles[node_data->mNode->mTrianglesBegin], node_data->mNode->mNumTriangles, inStoreUserData, mTree, outError);
  184. if (node_data->mTriangleStart == size_t(-1))
  185. return false;
  186. }
  187. // Patch offset into parent
  188. if (node_data->mParentChildNodeStart != nullptr)
  189. {
  190. *node_data->mParentChildNodeStart = node_data->mNodeStart;
  191. *node_data->mParentTrianglesStart = node_data->mTriangleStart;
  192. }
  193. }
  194. // If we've got triangles to process, loop again with just the triangles
  195. if (to_process_triangles.empty())
  196. break;
  197. else
  198. to_process.swap(to_process_triangles);
  199. }
  200. // Assert that our reservation was correct (we don't know if we swapped the arrays or not)
  201. JPH_ASSERT(to_process_max_size == to_process.capacity() || to_process_triangles_max_size == to_process.capacity());
  202. JPH_ASSERT(to_process_max_size == to_process_triangles.capacity() || to_process_triangles_max_size == to_process_triangles.capacity());
  203. // Finalize all nodes
  204. for (NodeData &n : node_list)
  205. if (!node_ctx.NodeFinalize(n.mNode, n.mNodeStart, n.mNumChildren, n.mChildNodeStart, n.mChildTrianglesStart, mTree, outError))
  206. return false;
  207. // Finalize the triangles
  208. tri_ctx.Finalize(inVertices, triangle_header, mTree);
  209. // Validate that our reservations were correct
  210. if (node_count != node_list.size())
  211. {
  212. outError = "Internal Error: Node memory estimate was incorrect, memory corruption!";
  213. return false;
  214. }
  215. if (total_size != mTree.size())
  216. {
  217. outError = "Internal Error: Tree memory estimate was incorrect, memory corruption!";
  218. return false;
  219. }
  220. // Finalize the nodes
  221. return node_ctx.Finalize(header, inRoot, node_list[0].mNodeStart, node_list[0].mTriangleStart, outError);
  222. }
  223. /// Get resulting data
  224. inline const ByteBuffer & GetBuffer() const
  225. {
  226. return mTree;
  227. }
  228. /// Get resulting data
  229. inline ByteBuffer & GetBuffer()
  230. {
  231. return mTree;
  232. }
  233. /// Get header for tree
  234. inline const NodeHeader * GetNodeHeader() const
  235. {
  236. return mTree.Get<NodeHeader>(0);
  237. }
  238. /// Get header for triangles
  239. inline const TriangleHeader * GetTriangleHeader() const
  240. {
  241. return mTree.Get<TriangleHeader>(HeaderSize);
  242. }
  243. /// Get root of resulting tree
  244. inline const void * GetRoot() const
  245. {
  246. return mTree.Get<void>(HeaderSize + TriangleHeaderSize);
  247. }
  248. private:
  249. ByteBuffer mTree; ///< Resulting tree structure
  250. };
  251. JPH_NAMESPACE_END