bvh_logic.inc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // for slow incremental optimization, we will periodically remove each
  2. // item from the tree and reinsert, to give it a chance to find a better position
  3. void _logic_item_remove_and_reinsert(uint32_t p_ref_id) {
  4. // get the reference
  5. ItemRef &ref = _refs[p_ref_id];
  6. // no need to optimize inactive items
  7. if (!ref.is_active()) {
  8. return;
  9. }
  10. // special case of debug draw
  11. if (ref.item_id == BVHCommon::INVALID) {
  12. return;
  13. }
  14. BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID);
  15. // some overlay elaborate way to find out which tree the node is in!
  16. BVHHandle temp_handle;
  17. temp_handle.set_id(p_ref_id);
  18. uint32_t tree_id = _handle_get_tree_id(temp_handle);
  19. // remove and reinsert
  20. BVHABB_CLASS abb;
  21. node_remove_item(p_ref_id, tree_id, &abb);
  22. // we must choose where to add to tree
  23. ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
  24. _node_add_item(ref.tnode_id, p_ref_id, abb);
  25. refit_upward_and_balance(ref.tnode_id, tree_id);
  26. }
  27. // from randy gaul balance function
  28. BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) {
  29. BVHABB_CLASS c = a;
  30. c.merge(b);
  31. return c;
  32. }
  33. //--------------------------------------------------------------------------------------------------
  34. /**
  35. * @file q3DynamicAABBTree.h
  36. * @author Randy Gaul
  37. * @date 10/10/2014
  38. * Copyright (c) 2014 Randy Gaul http://www.randygaul.net
  39. * This software is provided 'as-is', without any express or implied
  40. * warranty. In no event will the authors be held liable for any damages
  41. * arising from the use of this software.
  42. * Permission is granted to anyone to use this software for any purpose,
  43. * including commercial applications, and to alter it and redistribute it
  44. * freely, subject to the following restrictions:
  45. * 1. The origin of this software must not be misrepresented; you must not
  46. * claim that you wrote the original software. If you use this software
  47. * in a product, an acknowledgment in the product documentation would be
  48. * appreciated but is not required.
  49. * 2. Altered source versions must be plainly marked as such, and must not
  50. * be misrepresented as being the original software.
  51. * 3. This notice may not be removed or altered from any source distribution.
  52. */
  53. //--------------------------------------------------------------------------------------------------
  54. // This function is based on the 'Balance' function from Randy Gaul's qu3e
  55. // https://github.com/RandyGaul/qu3e
  56. // It is MODIFIED from qu3e version.
  57. // This is the only function used (and _logic_abb_merge helper function).
  58. int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) {
  59. //return iA; // uncomment this to bypass balance
  60. TNode *A = &_nodes[iA];
  61. if (A->is_leaf() || A->height == 1) {
  62. return iA;
  63. }
  64. /* A
  65. * / \
  66. * B C
  67. * / \ / \
  68. * D E F G
  69. */
  70. CRASH_COND(A->num_children != 2);
  71. int32_t iB = A->children[0];
  72. int32_t iC = A->children[1];
  73. TNode *B = &_nodes[iB];
  74. TNode *C = &_nodes[iC];
  75. int32_t balance = C->height - B->height;
  76. // C is higher, promote C
  77. if (balance > 1) {
  78. int32_t iF = C->children[0];
  79. int32_t iG = C->children[1];
  80. TNode *F = &_nodes[iF];
  81. TNode *G = &_nodes[iG];
  82. // grandParent point to C
  83. if (A->parent_id != BVHCommon::INVALID) {
  84. if (_nodes[A->parent_id].children[0] == iA) {
  85. _nodes[A->parent_id].children[0] = iC;
  86. } else {
  87. _nodes[A->parent_id].children[1] = iC;
  88. }
  89. } else {
  90. // check this .. seems dodgy
  91. change_root_node(iC, p_tree_id);
  92. }
  93. // Swap A and C
  94. C->children[0] = iA;
  95. C->parent_id = A->parent_id;
  96. A->parent_id = iC;
  97. // Finish rotation
  98. if (F->height > G->height) {
  99. C->children[1] = iF;
  100. A->children[1] = iG;
  101. G->parent_id = iA;
  102. A->aabb = _logic_abb_merge(B->aabb, G->aabb);
  103. C->aabb = _logic_abb_merge(A->aabb, F->aabb);
  104. A->height = 1 + MAX(B->height, G->height);
  105. C->height = 1 + MAX(A->height, F->height);
  106. }
  107. else {
  108. C->children[1] = iG;
  109. A->children[1] = iF;
  110. F->parent_id = iA;
  111. A->aabb = _logic_abb_merge(B->aabb, F->aabb);
  112. C->aabb = _logic_abb_merge(A->aabb, G->aabb);
  113. A->height = 1 + MAX(B->height, F->height);
  114. C->height = 1 + MAX(A->height, G->height);
  115. }
  116. return iC;
  117. }
  118. // B is higher, promote B
  119. else if (balance < -1) {
  120. int32_t iD = B->children[0];
  121. int32_t iE = B->children[1];
  122. TNode *D = &_nodes[iD];
  123. TNode *E = &_nodes[iE];
  124. // grandParent point to B
  125. if (A->parent_id != BVHCommon::INVALID) {
  126. if (_nodes[A->parent_id].children[0] == iA) {
  127. _nodes[A->parent_id].children[0] = iB;
  128. } else {
  129. _nodes[A->parent_id].children[1] = iB;
  130. }
  131. }
  132. else {
  133. // check this .. seems dodgy
  134. change_root_node(iB, p_tree_id);
  135. }
  136. // Swap A and B
  137. B->children[1] = iA;
  138. B->parent_id = A->parent_id;
  139. A->parent_id = iB;
  140. // Finish rotation
  141. if (D->height > E->height) {
  142. B->children[0] = iD;
  143. A->children[0] = iE;
  144. E->parent_id = iA;
  145. A->aabb = _logic_abb_merge(C->aabb, E->aabb);
  146. B->aabb = _logic_abb_merge(A->aabb, D->aabb);
  147. A->height = 1 + MAX(C->height, E->height);
  148. B->height = 1 + MAX(A->height, D->height);
  149. }
  150. else {
  151. B->children[0] = iE;
  152. A->children[0] = iD;
  153. D->parent_id = iA;
  154. A->aabb = _logic_abb_merge(C->aabb, D->aabb);
  155. B->aabb = _logic_abb_merge(A->aabb, E->aabb);
  156. A->height = 1 + MAX(C->height, D->height);
  157. B->height = 1 + MAX(A->height, E->height);
  158. }
  159. return iB;
  160. }
  161. return iA;
  162. }
  163. // either choose an existing node to add item to, or create a new node and return this
  164. uint32_t _logic_choose_item_add_node(uint32_t p_node_id, const BVHABB_CLASS &p_aabb) {
  165. while (true) {
  166. BVH_ASSERT(p_node_id != BVHCommon::INVALID);
  167. TNode &tnode = _nodes[p_node_id];
  168. if (tnode.is_leaf()) {
  169. // if a leaf, and non full, use this to add to
  170. if (!node_is_leaf_full(tnode)) {
  171. return p_node_id;
  172. }
  173. // else split the leaf, and use one of the children to add to
  174. return split_leaf(p_node_id, p_aabb);
  175. }
  176. // this should not happen???
  177. // is still happening, need to debug and find circumstances. Is not that serious
  178. // but would be nice to prevent. I think it only happens with the root node.
  179. if (tnode.num_children == 1) {
  180. WARN_PRINT_ONCE("BVH::recursive_choose_item_add_node, node with 1 child, recovering");
  181. p_node_id = tnode.children[0];
  182. } else {
  183. BVH_ASSERT(tnode.num_children == 2);
  184. TNode &childA = _nodes[tnode.children[0]];
  185. TNode &childB = _nodes[tnode.children[1]];
  186. int which = p_aabb.select_by_proximity(childA.aabb, childB.aabb);
  187. p_node_id = tnode.children[which];
  188. }
  189. }
  190. }