AABBTreeToBuffer.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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_SUPPRESS_WARNINGS_STD_BEGIN
  9. #include <deque>
  10. JPH_SUPPRESS_WARNINGS_STD_END
  11. JPH_NAMESPACE_BEGIN
  12. template <class T> using Deque = std::deque<T, STLAllocator<T>>;
  13. /// Conversion algorithm that converts an AABB tree to an optimized binary buffer
  14. template <class TriangleCodec, class NodeCodec>
  15. class AABBTreeToBuffer
  16. {
  17. public:
  18. /// Header for the tree
  19. using NodeHeader = typename NodeCodec::Header;
  20. /// Size in bytes of the header of the tree
  21. static const int HeaderSize = NodeCodec::HeaderSize;
  22. /// Maximum number of children per node in the tree
  23. static const int NumChildrenPerNode = NodeCodec::NumChildrenPerNode;
  24. /// Header for the triangles
  25. using TriangleHeader = typename TriangleCodec::TriangleHeader;
  26. /// Size in bytes of the header for the triangles
  27. static const int TriangleHeaderSize = TriangleCodec::TriangleHeaderSize;
  28. /// Convert AABB tree. Returns false if failed.
  29. bool Convert(const VertexList &inVertices, const AABBTreeBuilder::Node *inRoot, const char *&outError)
  30. {
  31. const typename NodeCodec::EncodingContext node_ctx;
  32. typename TriangleCodec::EncodingContext tri_ctx(inVertices);
  33. // Estimate the amount of memory required
  34. uint tri_count = inRoot->GetTriangleCountInTree();
  35. uint node_count = inRoot->GetNodeCount();
  36. uint nodes_size = node_ctx.GetPessimisticMemoryEstimate(node_count);
  37. uint total_size = HeaderSize + TriangleHeaderSize + nodes_size + tri_ctx.GetPessimisticMemoryEstimate(tri_count);
  38. mTree.reserve(total_size);
  39. // Reset counters
  40. mNodesSize = 0;
  41. // Add headers
  42. NodeHeader *header = HeaderSize > 0? mTree.Allocate<NodeHeader>() : nullptr;
  43. TriangleHeader *triangle_header = TriangleHeaderSize > 0? mTree.Allocate<TriangleHeader>() : nullptr;
  44. struct NodeData
  45. {
  46. const AABBTreeBuilder::Node * mNode = nullptr; // Node that this entry belongs to
  47. Vec3 mNodeBoundsMin; // Quantized node bounds
  48. Vec3 mNodeBoundsMax;
  49. uint mNodeStart = uint(-1); // Start of node in mTree
  50. uint mTriangleStart = uint(-1); // Start of the triangle data in mTree
  51. uint mNumChildren = 0; // Number of children
  52. uint mChildNodeStart[NumChildrenPerNode]; // Start of the children of the node in mTree
  53. uint mChildTrianglesStart[NumChildrenPerNode]; // Start of the triangle data in mTree
  54. uint * mParentChildNodeStart = nullptr; // Where to store mNodeStart (to patch mChildNodeStart of my parent)
  55. uint * mParentTrianglesStart = nullptr; // Where to store mTriangleStart (to patch mChildTrianglesStart of my parent)
  56. };
  57. Deque<NodeData *> to_process;
  58. Deque<NodeData *> to_process_triangles;
  59. Array<NodeData> node_list;
  60. node_list.reserve(node_count); // Needed to ensure that array is not reallocated, so we can keep pointers in the array
  61. NodeData root;
  62. root.mNode = inRoot;
  63. root.mNodeBoundsMin = inRoot->mBounds.mMin;
  64. root.mNodeBoundsMax = inRoot->mBounds.mMax;
  65. node_list.push_back(root);
  66. to_process.push_back(&node_list.back());
  67. // Child nodes out of loop so we don't constantly realloc it
  68. Array<const AABBTreeBuilder::Node *> child_nodes;
  69. child_nodes.reserve(NumChildrenPerNode);
  70. for (;;)
  71. {
  72. while (!to_process.empty())
  73. {
  74. // Get the next node to process
  75. NodeData *node_data = to_process.back();
  76. to_process.pop_back();
  77. // Due to quantization box could have become bigger, not smaller
  78. JPH_ASSERT(AABox(node_data->mNodeBoundsMin, node_data->mNodeBoundsMax).Contains(node_data->mNode->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
  79. // Collect the first NumChildrenPerNode sub-nodes in the tree
  80. child_nodes.clear(); // Won't free the memory
  81. node_data->mNode->GetNChildren(NumChildrenPerNode, child_nodes);
  82. node_data->mNumChildren = (uint)child_nodes.size();
  83. // Fill in default child bounds
  84. Vec3 child_bounds_min[NumChildrenPerNode], child_bounds_max[NumChildrenPerNode];
  85. for (size_t i = 0; i < NumChildrenPerNode; ++i)
  86. if (i < child_nodes.size())
  87. {
  88. child_bounds_min[i] = child_nodes[i]->mBounds.mMin;
  89. child_bounds_max[i] = child_nodes[i]->mBounds.mMax;
  90. }
  91. else
  92. {
  93. child_bounds_min[i] = Vec3::sZero();
  94. child_bounds_max[i] = Vec3::sZero();
  95. }
  96. // Start a new node
  97. uint old_size = (uint)mTree.size();
  98. 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);
  99. if (node_data->mNodeStart == uint(-1))
  100. return false;
  101. mNodesSize += (uint)mTree.size() - old_size;
  102. if (node_data->mNode->HasChildren())
  103. {
  104. // Insert in reverse order so we process left child first when taking nodes from the back
  105. for (int idx = int(child_nodes.size()) - 1; idx >= 0; --idx)
  106. {
  107. // Due to quantization box could have become bigger, not smaller
  108. JPH_ASSERT(AABox(child_bounds_min[idx], child_bounds_max[idx]).Contains(child_nodes[idx]->mBounds), "AABBTreeToBuffer: Bounding box became smaller!");
  109. // Add child to list of nodes to be processed
  110. NodeData child;
  111. child.mNode = child_nodes[idx];
  112. child.mNodeBoundsMin = child_bounds_min[idx];
  113. child.mNodeBoundsMax = child_bounds_max[idx];
  114. child.mParentChildNodeStart = &node_data->mChildNodeStart[idx];
  115. child.mParentTrianglesStart = &node_data->mChildTrianglesStart[idx];
  116. NodeData *old = &node_list[0];
  117. node_list.push_back(child);
  118. if (old != &node_list[0])
  119. {
  120. outError = "Internal Error: Array reallocated, memory corruption!";
  121. return false;
  122. }
  123. // Store triangles in separate list so we process them last
  124. if (node_list.back().mNode->HasChildren())
  125. to_process.push_back(&node_list.back());
  126. else
  127. to_process_triangles.push_back(&node_list.back());
  128. }
  129. }
  130. else
  131. {
  132. // Add triangles
  133. node_data->mTriangleStart = tri_ctx.Pack(node_data->mNode->mTriangles, mTree, outError);
  134. if (node_data->mTriangleStart == uint(-1))
  135. return false;
  136. }
  137. // Patch offset into parent
  138. if (node_data->mParentChildNodeStart != nullptr)
  139. {
  140. *node_data->mParentChildNodeStart = node_data->mNodeStart;
  141. *node_data->mParentTrianglesStart = node_data->mTriangleStart;
  142. }
  143. }
  144. // If we've got triangles to process, loop again with just the triangles
  145. if (to_process_triangles.empty())
  146. break;
  147. else
  148. to_process.swap(to_process_triangles);
  149. }
  150. // Finalize all nodes
  151. for (NodeData &n : node_list)
  152. if (!node_ctx.NodeFinalize(n.mNode, n.mNodeStart, n.mNumChildren, n.mChildNodeStart, n.mChildTrianglesStart, mTree, outError))
  153. return false;
  154. // Finalize the triangles
  155. tri_ctx.Finalize(inVertices, triangle_header, mTree);
  156. // Validate that we reserved enough memory
  157. if (nodes_size < mNodesSize)
  158. {
  159. outError = "Internal Error: Not enough memory reserved for nodes!";
  160. return false;
  161. }
  162. if (total_size < (uint)mTree.size())
  163. {
  164. outError = "Internal Error: Not enough memory reserved for triangles!";
  165. return false;
  166. }
  167. // Finalize the nodes
  168. if (!node_ctx.Finalize(header, inRoot, node_list[0].mNodeStart, node_list[0].mTriangleStart, outError))
  169. return false;
  170. // Shrink the tree, this will invalidate the header and triangle_header variables
  171. mTree.shrink_to_fit();
  172. return true;
  173. }
  174. /// Get resulting data
  175. inline const ByteBuffer & GetBuffer() const
  176. {
  177. return mTree;
  178. }
  179. /// Get resulting data
  180. inline ByteBuffer & GetBuffer()
  181. {
  182. return mTree;
  183. }
  184. /// Get header for tree
  185. inline const NodeHeader * GetNodeHeader() const
  186. {
  187. return mTree.Get<NodeHeader>(0);
  188. }
  189. /// Get header for triangles
  190. inline const TriangleHeader * GetTriangleHeader() const
  191. {
  192. return mTree.Get<TriangleHeader>(HeaderSize);
  193. }
  194. /// Get root of resulting tree
  195. inline const void * GetRoot() const
  196. {
  197. return mTree.Get<void>(HeaderSize + TriangleHeaderSize);
  198. }
  199. private:
  200. ByteBuffer mTree; ///< Resulting tree structure
  201. uint mNodesSize; ///< Size in bytes of the nodes in the buffer
  202. };
  203. JPH_NAMESPACE_END