| 1 | /**************************************************************************/ |
| 2 | /* bvh.h */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #ifndef BVH_H |
| 32 | #define BVH_H |
| 33 | |
| 34 | // BVH |
| 35 | // This class provides a wrapper around BVH tree, which contains most of the functionality |
| 36 | // for a dynamic BVH with templated leaf size. |
| 37 | // However BVH also adds facilities for pairing, to maintain compatibility with Godot 3.2. |
| 38 | // Pairing is a collision pairing system, on top of the basic BVH. |
| 39 | |
| 40 | // Some notes on the use of BVH / Octree from Godot 3.2. |
| 41 | // This is not well explained elsewhere. |
| 42 | // The rendering tree mask and types that are sent to the BVH are NOT layer masks. |
| 43 | // They are INSTANCE_TYPES (defined in visual_server.h), e.g. MESH, MULTIMESH, PARTICLES etc. |
| 44 | // Thus the lights do no cull by layer mask in the BVH. |
| 45 | |
| 46 | // Layer masks are implemented in the renderers as a later step, and light_cull_mask appears to be |
| 47 | // implemented in GLES3 but not GLES2. Layer masks are not yet implemented for directional lights. |
| 48 | |
| 49 | // In the physics, the pairable_type is based on 1 << p_object->get_type() where: |
| 50 | // TYPE_AREA, |
| 51 | // TYPE_BODY |
| 52 | // and pairable_mask is either 0 if static, or set to all if non static |
| 53 | |
| 54 | #include "bvh_tree.h" |
| 55 | #include "core/os/mutex.h" |
| 56 | |
| 57 | #define BVHTREE_CLASS BVH_Tree<T, NUM_TREES, 2, MAX_ITEMS, USER_PAIR_TEST_FUNCTION, USER_CULL_TEST_FUNCTION, USE_PAIRS, BOUNDS, POINT> |
| 58 | #define BVH_LOCKED_FUNCTION BVHLockedFunction _lock_guard(&_mutex, BVH_THREAD_SAFE &&_thread_safe); |
| 59 | |
| 60 | template <class T, int NUM_TREES = 1, bool USE_PAIRS = false, int MAX_ITEMS = 32, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, class BOUNDS = AABB, class POINT = Vector3, bool BVH_THREAD_SAFE = true> |
| 61 | class BVH_Manager { |
| 62 | public: |
| 63 | // note we are using uint32_t instead of BVHHandle, losing type safety, but this |
| 64 | // is for compatibility with octree |
| 65 | typedef void *(*PairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int); |
| 66 | typedef void (*UnpairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *); |
| 67 | typedef void *(*CheckPairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *); |
| 68 | |
| 69 | // allow locally toggling thread safety if the template has been compiled with BVH_THREAD_SAFE |
| 70 | void params_set_thread_safe(bool p_enable) { |
| 71 | _thread_safe = p_enable; |
| 72 | } |
| 73 | |
| 74 | // these 2 are crucial for fine tuning, and can be applied manually |
| 75 | // see the variable declarations for more info. |
| 76 | void params_set_node_expansion(real_t p_value) { |
| 77 | BVH_LOCKED_FUNCTION |
| 78 | if (p_value >= 0.0) { |
| 79 | tree._node_expansion = p_value; |
| 80 | tree._auto_node_expansion = false; |
| 81 | } else { |
| 82 | tree._auto_node_expansion = true; |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | void params_set_pairing_expansion(real_t p_value) { |
| 87 | BVH_LOCKED_FUNCTION |
| 88 | tree.params_set_pairing_expansion(p_value); |
| 89 | } |
| 90 | |
| 91 | void set_pair_callback(PairCallback p_callback, void *p_userdata) { |
| 92 | BVH_LOCKED_FUNCTION |
| 93 | pair_callback = p_callback; |
| 94 | pair_callback_userdata = p_userdata; |
| 95 | } |
| 96 | void set_unpair_callback(UnpairCallback p_callback, void *p_userdata) { |
| 97 | BVH_LOCKED_FUNCTION |
| 98 | unpair_callback = p_callback; |
| 99 | unpair_callback_userdata = p_userdata; |
| 100 | } |
| 101 | void set_check_pair_callback(CheckPairCallback p_callback, void *p_userdata) { |
| 102 | BVH_LOCKED_FUNCTION |
| 103 | check_pair_callback = p_callback; |
| 104 | check_pair_callback_userdata = p_userdata; |
| 105 | } |
| 106 | |
| 107 | BVHHandle create(T *p_userdata, bool p_active = true, uint32_t p_tree_id = 0, uint32_t p_tree_collision_mask = 1, const BOUNDS &p_aabb = BOUNDS(), int p_subindex = 0) { |
| 108 | BVH_LOCKED_FUNCTION |
| 109 | |
| 110 | // not sure if absolutely necessary to flush collisions here. It will cost performance to, instead |
| 111 | // of waiting for update, so only uncomment this if there are bugs. |
| 112 | if (USE_PAIRS) { |
| 113 | //_check_for_collisions(); |
| 114 | } |
| 115 | |
| 116 | BVHHandle h = tree.item_add(p_userdata, p_active, p_aabb, p_subindex, p_tree_id, p_tree_collision_mask); |
| 117 | |
| 118 | if (USE_PAIRS) { |
| 119 | // for safety initialize the expanded AABB |
| 120 | BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb; |
| 121 | expanded_aabb = p_aabb; |
| 122 | expanded_aabb.grow_by(tree._pairing_expansion); |
| 123 | |
| 124 | // force a collision check no matter the AABB |
| 125 | if (p_active) { |
| 126 | _add_changed_item(h, p_aabb, false); |
| 127 | _check_for_collisions(true); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | return h; |
| 132 | } |
| 133 | |
| 134 | //////////////////////////////////////////////////// |
| 135 | // wrapper versions that use uint32_t instead of handle |
| 136 | // for backward compatibility. Less type safe |
| 137 | void move(uint32_t p_handle, const BOUNDS &p_aabb) { |
| 138 | BVHHandle h; |
| 139 | h.set(p_handle); |
| 140 | move(h, p_aabb); |
| 141 | } |
| 142 | |
| 143 | void recheck_pairs(uint32_t p_handle) { |
| 144 | BVHHandle h; |
| 145 | h.set(p_handle); |
| 146 | recheck_pairs(h); |
| 147 | } |
| 148 | |
| 149 | void erase(uint32_t p_handle) { |
| 150 | BVHHandle h; |
| 151 | h.set(p_handle); |
| 152 | erase(h); |
| 153 | } |
| 154 | |
| 155 | void force_collision_check(uint32_t p_handle) { |
| 156 | BVHHandle h; |
| 157 | h.set(p_handle); |
| 158 | force_collision_check(h); |
| 159 | } |
| 160 | |
| 161 | bool activate(uint32_t p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) { |
| 162 | BVHHandle h; |
| 163 | h.set(p_handle); |
| 164 | return activate(h, p_aabb, p_delay_collision_check); |
| 165 | } |
| 166 | |
| 167 | bool deactivate(uint32_t p_handle) { |
| 168 | BVHHandle h; |
| 169 | h.set(p_handle); |
| 170 | return deactivate(h); |
| 171 | } |
| 172 | |
| 173 | void set_tree(uint32_t p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) { |
| 174 | BVHHandle h; |
| 175 | h.set(p_handle); |
| 176 | set_tree(h, p_tree_id, p_tree_collision_mask, p_force_collision_check); |
| 177 | } |
| 178 | |
| 179 | uint32_t get_tree_id(uint32_t p_handle) const { |
| 180 | BVHHandle h; |
| 181 | h.set(p_handle); |
| 182 | return item_get_tree_id(h); |
| 183 | } |
| 184 | int get_subindex(uint32_t p_handle) const { |
| 185 | BVHHandle h; |
| 186 | h.set(p_handle); |
| 187 | return item_get_subindex(h); |
| 188 | } |
| 189 | |
| 190 | T *get(uint32_t p_handle) const { |
| 191 | BVHHandle h; |
| 192 | h.set(p_handle); |
| 193 | return item_get_userdata(h); |
| 194 | } |
| 195 | |
| 196 | //////////////////////////////////////////////////// |
| 197 | |
| 198 | void move(BVHHandle p_handle, const BOUNDS &p_aabb) { |
| 199 | DEV_ASSERT(!p_handle.is_invalid()); |
| 200 | BVH_LOCKED_FUNCTION |
| 201 | if (tree.item_move(p_handle, p_aabb)) { |
| 202 | if (USE_PAIRS) { |
| 203 | _add_changed_item(p_handle, p_aabb); |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | void recheck_pairs(BVHHandle p_handle) { |
| 209 | DEV_ASSERT(!p_handle.is_invalid()); |
| 210 | force_collision_check(p_handle); |
| 211 | } |
| 212 | |
| 213 | void erase(BVHHandle p_handle) { |
| 214 | DEV_ASSERT(!p_handle.is_invalid()); |
| 215 | BVH_LOCKED_FUNCTION |
| 216 | // call unpair and remove all references to the item |
| 217 | // before deleting from the tree |
| 218 | if (USE_PAIRS) { |
| 219 | _remove_changed_item(p_handle); |
| 220 | } |
| 221 | |
| 222 | tree.item_remove(p_handle); |
| 223 | |
| 224 | _check_for_collisions(true); |
| 225 | } |
| 226 | |
| 227 | // use in conjunction with activate if you have deferred the collision check, and |
| 228 | // set pairable has never been called. |
| 229 | // (deferred collision checks are a workaround for visual server for historical reasons) |
| 230 | void force_collision_check(BVHHandle p_handle) { |
| 231 | DEV_ASSERT(!p_handle.is_invalid()); |
| 232 | BVH_LOCKED_FUNCTION |
| 233 | if (USE_PAIRS) { |
| 234 | // the aabb should already be up to date in the BVH |
| 235 | BOUNDS aabb; |
| 236 | item_get_AABB(p_handle, aabb); |
| 237 | |
| 238 | // add it as changed even if aabb not different |
| 239 | _add_changed_item(p_handle, aabb, false); |
| 240 | |
| 241 | // force an immediate full collision check, much like calls to set_pairable |
| 242 | _check_for_collisions(true); |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | // these should be read as set_visible for render trees, |
| 247 | // but generically this makes items add or remove from the |
| 248 | // tree internally, to speed things up by ignoring inactive items |
| 249 | bool activate(BVHHandle p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) { |
| 250 | DEV_ASSERT(!p_handle.is_invalid()); |
| 251 | BVH_LOCKED_FUNCTION |
| 252 | // sending the aabb here prevents the need for the BVH to maintain |
| 253 | // a redundant copy of the aabb. |
| 254 | // returns success |
| 255 | if (tree.item_activate(p_handle, p_aabb)) { |
| 256 | if (USE_PAIRS) { |
| 257 | // in the special case of the render tree, when setting visibility we are using the combination of |
| 258 | // activate then set_pairable. This would case 2 sets of collision checks. For efficiency here we allow |
| 259 | // deferring to have a single collision check at the set_pairable call. |
| 260 | // Watch for bugs! This may cause bugs if set_pairable is not called. |
| 261 | if (!p_delay_collision_check) { |
| 262 | _add_changed_item(p_handle, p_aabb, false); |
| 263 | |
| 264 | // force an immediate collision check, much like calls to set_pairable |
| 265 | _check_for_collisions(true); |
| 266 | } |
| 267 | } |
| 268 | return true; |
| 269 | } |
| 270 | |
| 271 | return false; |
| 272 | } |
| 273 | |
| 274 | bool deactivate(BVHHandle p_handle) { |
| 275 | DEV_ASSERT(!p_handle.is_invalid()); |
| 276 | BVH_LOCKED_FUNCTION |
| 277 | // returns success |
| 278 | if (tree.item_deactivate(p_handle)) { |
| 279 | // call unpair and remove all references to the item |
| 280 | // before deleting from the tree |
| 281 | if (USE_PAIRS) { |
| 282 | _remove_changed_item(p_handle); |
| 283 | |
| 284 | // force check for collisions, much like an erase was called |
| 285 | _check_for_collisions(true); |
| 286 | } |
| 287 | return true; |
| 288 | } |
| 289 | |
| 290 | return false; |
| 291 | } |
| 292 | |
| 293 | bool get_active(BVHHandle p_handle) { |
| 294 | DEV_ASSERT(!p_handle.is_invalid()); |
| 295 | BVH_LOCKED_FUNCTION |
| 296 | return tree.item_get_active(p_handle); |
| 297 | } |
| 298 | |
| 299 | // call e.g. once per frame (this does a trickle optimize) |
| 300 | void update() { |
| 301 | BVH_LOCKED_FUNCTION |
| 302 | tree.update(); |
| 303 | _check_for_collisions(); |
| 304 | #ifdef BVH_INTEGRITY_CHECKS |
| 305 | tree._integrity_check_all(); |
| 306 | #endif |
| 307 | } |
| 308 | |
| 309 | // this can be called more frequently than per frame if necessary |
| 310 | void update_collisions() { |
| 311 | BVH_LOCKED_FUNCTION |
| 312 | _check_for_collisions(); |
| 313 | } |
| 314 | |
| 315 | // prefer calling this directly as type safe |
| 316 | void set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) { |
| 317 | DEV_ASSERT(!p_handle.is_invalid()); |
| 318 | BVH_LOCKED_FUNCTION |
| 319 | // Returns true if the pairing state has changed. |
| 320 | bool state_changed = tree.item_set_tree(p_handle, p_tree_id, p_tree_collision_mask); |
| 321 | |
| 322 | if (USE_PAIRS) { |
| 323 | // not sure if absolutely necessary to flush collisions here. It will cost performance to, instead |
| 324 | // of waiting for update, so only uncomment this if there are bugs. |
| 325 | //_check_for_collisions(); |
| 326 | |
| 327 | if ((p_force_collision_check || state_changed) && tree.item_get_active(p_handle)) { |
| 328 | // when the pairable state changes, we need to force a collision check because newly pairable |
| 329 | // items may be in collision, and unpairable items might move out of collision. |
| 330 | // We cannot depend on waiting for the next update, because that may come much later. |
| 331 | BOUNDS aabb; |
| 332 | item_get_AABB(p_handle, aabb); |
| 333 | |
| 334 | // passing false disables the optimization which prevents collision checks if |
| 335 | // the aabb hasn't changed |
| 336 | _add_changed_item(p_handle, aabb, false); |
| 337 | |
| 338 | // force an immediate collision check (probably just for this one item) |
| 339 | // but it must be a FULL collision check, also checking pairable state and masks. |
| 340 | // This is because AABB intersecting objects may have changed pairable state / mask |
| 341 | // such that they should no longer be paired. E.g. lights. |
| 342 | _check_for_collisions(true); |
| 343 | } // only if active |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | // cull tests |
| 348 | int cull_aabb(const BOUNDS &p_aabb, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) { |
| 349 | BVH_LOCKED_FUNCTION |
| 350 | typename BVHTREE_CLASS::CullParams params; |
| 351 | |
| 352 | params.result_count_overall = 0; |
| 353 | params.result_max = p_result_max; |
| 354 | params.result_array = p_result_array; |
| 355 | params.subindex_array = p_subindex_array; |
| 356 | params.tree_collision_mask = p_tree_collision_mask; |
| 357 | params.abb.from(p_aabb); |
| 358 | params.tester = p_tester; |
| 359 | |
| 360 | tree.cull_aabb(params); |
| 361 | |
| 362 | return params.result_count_overall; |
| 363 | } |
| 364 | |
| 365 | int cull_segment(const POINT &p_from, const POINT &p_to, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) { |
| 366 | BVH_LOCKED_FUNCTION |
| 367 | typename BVHTREE_CLASS::CullParams params; |
| 368 | |
| 369 | params.result_count_overall = 0; |
| 370 | params.result_max = p_result_max; |
| 371 | params.result_array = p_result_array; |
| 372 | params.subindex_array = p_subindex_array; |
| 373 | params.tester = p_tester; |
| 374 | params.tree_collision_mask = p_tree_collision_mask; |
| 375 | |
| 376 | params.segment.from = p_from; |
| 377 | params.segment.to = p_to; |
| 378 | |
| 379 | tree.cull_segment(params); |
| 380 | |
| 381 | return params.result_count_overall; |
| 382 | } |
| 383 | |
| 384 | int cull_point(const POINT &p_point, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF, int *p_subindex_array = nullptr) { |
| 385 | BVH_LOCKED_FUNCTION |
| 386 | typename BVHTREE_CLASS::CullParams params; |
| 387 | |
| 388 | params.result_count_overall = 0; |
| 389 | params.result_max = p_result_max; |
| 390 | params.result_array = p_result_array; |
| 391 | params.subindex_array = p_subindex_array; |
| 392 | params.tester = p_tester; |
| 393 | params.tree_collision_mask = p_tree_collision_mask; |
| 394 | |
| 395 | params.point = p_point; |
| 396 | |
| 397 | tree.cull_point(params); |
| 398 | return params.result_count_overall; |
| 399 | } |
| 400 | |
| 401 | int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, const T *p_tester, uint32_t p_tree_collision_mask = 0xFFFFFFFF) { |
| 402 | BVH_LOCKED_FUNCTION |
| 403 | if (!p_convex.size()) { |
| 404 | return 0; |
| 405 | } |
| 406 | |
| 407 | Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); |
| 408 | if (convex_points.size() == 0) { |
| 409 | return 0; |
| 410 | } |
| 411 | |
| 412 | typename BVHTREE_CLASS::CullParams params; |
| 413 | params.result_count_overall = 0; |
| 414 | params.result_max = p_result_max; |
| 415 | params.result_array = p_result_array; |
| 416 | params.subindex_array = nullptr; |
| 417 | params.tester = p_tester; |
| 418 | params.tree_collision_mask = p_tree_collision_mask; |
| 419 | |
| 420 | params.hull.planes = &p_convex[0]; |
| 421 | params.hull.num_planes = p_convex.size(); |
| 422 | params.hull.points = &convex_points[0]; |
| 423 | params.hull.num_points = convex_points.size(); |
| 424 | |
| 425 | tree.cull_convex(params); |
| 426 | |
| 427 | return params.result_count_overall; |
| 428 | } |
| 429 | |
| 430 | private: |
| 431 | // do this after moving etc. |
| 432 | void _check_for_collisions(bool p_full_check = false) { |
| 433 | if (!changed_items.size()) { |
| 434 | // noop |
| 435 | return; |
| 436 | } |
| 437 | |
| 438 | BOUNDS bb; |
| 439 | |
| 440 | typename BVHTREE_CLASS::CullParams params; |
| 441 | |
| 442 | params.result_count_overall = 0; |
| 443 | params.result_max = INT_MAX; |
| 444 | params.result_array = nullptr; |
| 445 | params.subindex_array = nullptr; |
| 446 | |
| 447 | for (const BVHHandle &h : changed_items) { |
| 448 | // use the expanded aabb for pairing |
| 449 | const BOUNDS &expanded_aabb = tree._pairs[h.id()].expanded_aabb; |
| 450 | BVHABB_CLASS abb; |
| 451 | abb.from(expanded_aabb); |
| 452 | |
| 453 | tree.item_fill_cullparams(h, params); |
| 454 | |
| 455 | // find all the existing paired aabbs that are no longer |
| 456 | // paired, and send callbacks |
| 457 | _find_leavers(h, abb, p_full_check); |
| 458 | |
| 459 | uint32_t changed_item_ref_id = h.id(); |
| 460 | |
| 461 | params.abb = abb; |
| 462 | |
| 463 | params.result_count_overall = 0; // might not be needed |
| 464 | tree.cull_aabb(params, false); |
| 465 | |
| 466 | for (const uint32_t ref_id : tree._cull_hits) { |
| 467 | // don't collide against ourself |
| 468 | if (ref_id == changed_item_ref_id) { |
| 469 | continue; |
| 470 | } |
| 471 | |
| 472 | // checkmasks is already done in the cull routine. |
| 473 | BVHHandle h_collidee; |
| 474 | h_collidee.set_id(ref_id); |
| 475 | |
| 476 | // find NEW enterers, and send callbacks for them only |
| 477 | _collide(h, h_collidee); |
| 478 | } |
| 479 | } |
| 480 | _reset(); |
| 481 | } |
| 482 | |
| 483 | public: |
| 484 | void item_get_AABB(BVHHandle p_handle, BOUNDS &r_aabb) { |
| 485 | DEV_ASSERT(!p_handle.is_invalid()); |
| 486 | BVHABB_CLASS abb; |
| 487 | tree.item_get_ABB(p_handle, abb); |
| 488 | abb.to(r_aabb); |
| 489 | } |
| 490 | |
| 491 | private: |
| 492 | // supplemental funcs |
| 493 | uint32_t item_get_tree_id(BVHHandle p_handle) const { return _get_extra(p_handle).tree_id; } |
| 494 | T *item_get_userdata(BVHHandle p_handle) const { return _get_extra(p_handle).userdata; } |
| 495 | int item_get_subindex(BVHHandle p_handle) const { return _get_extra(p_handle).subindex; } |
| 496 | |
| 497 | void _unpair(BVHHandle p_from, BVHHandle p_to) { |
| 498 | tree._handle_sort(p_from, p_to); |
| 499 | |
| 500 | typename BVHTREE_CLASS::ItemExtra &exa = tree._extra[p_from.id()]; |
| 501 | typename BVHTREE_CLASS::ItemExtra &exb = tree._extra[p_to.id()]; |
| 502 | |
| 503 | // if the userdata is the same, no collisions should occur |
| 504 | if ((exa.userdata == exb.userdata) && exa.userdata) { |
| 505 | return; |
| 506 | } |
| 507 | |
| 508 | typename BVHTREE_CLASS::ItemPairs &pairs_from = tree._pairs[p_from.id()]; |
| 509 | typename BVHTREE_CLASS::ItemPairs &pairs_to = tree._pairs[p_to.id()]; |
| 510 | |
| 511 | void *ud_from = pairs_from.remove_pair_to(p_to); |
| 512 | pairs_to.remove_pair_to(p_from); |
| 513 | |
| 514 | #ifdef BVH_VERBOSE_PAIRING |
| 515 | print_line("_unpair " + itos(p_from.id()) + " from " + itos(p_to.id())); |
| 516 | #endif |
| 517 | |
| 518 | // callback |
| 519 | if (unpair_callback) { |
| 520 | unpair_callback(pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, ud_from); |
| 521 | } |
| 522 | } |
| 523 | |
| 524 | void *_recheck_pair(BVHHandle p_from, BVHHandle p_to, void *p_pair_data) { |
| 525 | tree._handle_sort(p_from, p_to); |
| 526 | |
| 527 | typename BVHTREE_CLASS::ItemExtra &exa = tree._extra[p_from.id()]; |
| 528 | typename BVHTREE_CLASS::ItemExtra &exb = tree._extra[p_to.id()]; |
| 529 | |
| 530 | // if the userdata is the same, no collisions should occur |
| 531 | if ((exa.userdata == exb.userdata) && exa.userdata) { |
| 532 | return p_pair_data; |
| 533 | } |
| 534 | |
| 535 | // callback |
| 536 | if (check_pair_callback) { |
| 537 | return check_pair_callback(check_pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, p_pair_data); |
| 538 | } |
| 539 | |
| 540 | return p_pair_data; |
| 541 | } |
| 542 | |
| 543 | // returns true if unpair |
| 544 | bool _find_leavers_process_pair(typename BVHTREE_CLASS::ItemPairs &p_pairs_from, const BVHABB_CLASS &p_abb_from, BVHHandle p_from, BVHHandle p_to, bool p_full_check) { |
| 545 | BVHABB_CLASS abb_to; |
| 546 | tree.item_get_ABB(p_to, abb_to); |
| 547 | |
| 548 | // do they overlap? |
| 549 | if (p_abb_from.intersects(abb_to)) { |
| 550 | // the full check for pairable / non pairable (i.e. tree_id and tree_masks) and mask changes is extra expense |
| 551 | // this need not be done in most cases (for speed) except in the case where set_tree is called |
| 552 | // where the masks etc of the objects in question may have changed |
| 553 | if (!p_full_check) { |
| 554 | return false; |
| 555 | } |
| 556 | const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_from); |
| 557 | const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_to); |
| 558 | |
| 559 | // Checking tree_ids and tree_collision_masks |
| 560 | if (exa.are_item_trees_compatible(exb)) { |
| 561 | bool pair_allowed = USER_PAIR_TEST_FUNCTION::user_pair_check(exa.userdata, exb.userdata); |
| 562 | |
| 563 | // the masks must still be compatible to pair |
| 564 | // i.e. if there is a hit between the two and they intersect, then they should stay paired |
| 565 | if (pair_allowed) { |
| 566 | return false; |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | _unpair(p_from, p_to); |
| 572 | return true; |
| 573 | } |
| 574 | |
| 575 | // find all the existing paired aabbs that are no longer |
| 576 | // paired, and send callbacks |
| 577 | void _find_leavers(BVHHandle p_handle, const BVHABB_CLASS &expanded_abb_from, bool p_full_check) { |
| 578 | typename BVHTREE_CLASS::ItemPairs &p_from = tree._pairs[p_handle.id()]; |
| 579 | |
| 580 | BVHABB_CLASS abb_from = expanded_abb_from; |
| 581 | |
| 582 | // remove from pairing list for every partner |
| 583 | for (unsigned int n = 0; n < p_from.extended_pairs.size(); n++) { |
| 584 | BVHHandle h_to = p_from.extended_pairs[n].handle; |
| 585 | if (_find_leavers_process_pair(p_from, abb_from, p_handle, h_to, p_full_check)) { |
| 586 | // we need to keep the counter n up to date if we deleted a pair |
| 587 | // as the number of items in p_from.extended_pairs will have decreased by 1 |
| 588 | // and we don't want to miss an item |
| 589 | n--; |
| 590 | } |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | // find NEW enterers, and send callbacks for them only |
| 595 | // handle a and b |
| 596 | void _collide(BVHHandle p_ha, BVHHandle p_hb) { |
| 597 | // only have to do this oneway, lower ID then higher ID |
| 598 | tree._handle_sort(p_ha, p_hb); |
| 599 | |
| 600 | const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_ha); |
| 601 | const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_hb); |
| 602 | |
| 603 | // user collision callback |
| 604 | if (!USER_PAIR_TEST_FUNCTION::user_pair_check(exa.userdata, exb.userdata)) { |
| 605 | return; |
| 606 | } |
| 607 | |
| 608 | // if the userdata is the same, no collisions should occur |
| 609 | if ((exa.userdata == exb.userdata) && exa.userdata) { |
| 610 | return; |
| 611 | } |
| 612 | |
| 613 | typename BVHTREE_CLASS::ItemPairs &p_from = tree._pairs[p_ha.id()]; |
| 614 | typename BVHTREE_CLASS::ItemPairs &p_to = tree._pairs[p_hb.id()]; |
| 615 | |
| 616 | // does this pair exist already? |
| 617 | // or only check the one with lower number of pairs for greater speed |
| 618 | if (p_from.num_pairs <= p_to.num_pairs) { |
| 619 | if (p_from.contains_pair_to(p_hb)) { |
| 620 | return; |
| 621 | } |
| 622 | } else { |
| 623 | if (p_to.contains_pair_to(p_ha)) { |
| 624 | return; |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | // callback |
| 629 | void *callback_userdata = nullptr; |
| 630 | |
| 631 | #ifdef BVH_VERBOSE_PAIRING |
| 632 | print_line("_pair " + itos(p_ha.id()) + " to " + itos(p_hb.id())); |
| 633 | #endif |
| 634 | |
| 635 | if (pair_callback) { |
| 636 | callback_userdata = pair_callback(pair_callback_userdata, p_ha, exa.userdata, exa.subindex, p_hb, exb.userdata, exb.subindex); |
| 637 | } |
| 638 | |
| 639 | // new pair! .. only really need to store the userdata on the lower handle, but both have storage so... |
| 640 | p_from.add_pair_to(p_hb, callback_userdata); |
| 641 | p_to.add_pair_to(p_ha, callback_userdata); |
| 642 | } |
| 643 | |
| 644 | // if we remove an item, we need to immediately remove the pairs, to prevent reading the pair after deletion |
| 645 | void _remove_pairs_containing(BVHHandle p_handle) { |
| 646 | typename BVHTREE_CLASS::ItemPairs &p_from = tree._pairs[p_handle.id()]; |
| 647 | |
| 648 | // remove from pairing list for every partner. |
| 649 | // can't easily use a for loop here, because removing changes the size of the list |
| 650 | while (p_from.extended_pairs.size()) { |
| 651 | BVHHandle h_to = p_from.extended_pairs[0].handle; |
| 652 | _unpair(p_handle, h_to); |
| 653 | } |
| 654 | } |
| 655 | |
| 656 | // Send pair callbacks again for all existing pairs for the given handle. |
| 657 | void _recheck_pairs(BVHHandle p_handle) { |
| 658 | typename BVHTREE_CLASS::ItemPairs &from = tree._pairs[p_handle.id()]; |
| 659 | |
| 660 | // checking pair for every partner. |
| 661 | for (unsigned int n = 0; n < from.extended_pairs.size(); n++) { |
| 662 | typename BVHTREE_CLASS::ItemPairs::Link &pair = from.extended_pairs[n]; |
| 663 | BVHHandle h_to = pair.handle; |
| 664 | void *new_pair_data = _recheck_pair(p_handle, h_to, pair.userdata); |
| 665 | |
| 666 | if (new_pair_data != pair.userdata) { |
| 667 | pair.userdata = new_pair_data; |
| 668 | |
| 669 | // Update pair data for the second item. |
| 670 | typename BVHTREE_CLASS::ItemPairs &to = tree._pairs[h_to.id()]; |
| 671 | for (unsigned int to_index = 0; to_index < to.extended_pairs.size(); to_index++) { |
| 672 | typename BVHTREE_CLASS::ItemPairs::Link &to_pair = to.extended_pairs[to_index]; |
| 673 | if (to_pair.handle == p_handle) { |
| 674 | to_pair.userdata = new_pair_data; |
| 675 | break; |
| 676 | } |
| 677 | } |
| 678 | } |
| 679 | } |
| 680 | } |
| 681 | |
| 682 | private: |
| 683 | const typename BVHTREE_CLASS::ItemExtra &_get_extra(BVHHandle p_handle) const { |
| 684 | return tree._extra[p_handle.id()]; |
| 685 | } |
| 686 | const typename BVHTREE_CLASS::ItemRef &_get_ref(BVHHandle p_handle) const { |
| 687 | return tree._refs[p_handle.id()]; |
| 688 | } |
| 689 | |
| 690 | void _reset() { |
| 691 | changed_items.clear(); |
| 692 | _tick++; |
| 693 | } |
| 694 | |
| 695 | void _add_changed_item(BVHHandle p_handle, const BOUNDS &aabb, bool p_check_aabb = true) { |
| 696 | // Note that non pairable items can pair with pairable, |
| 697 | // so all types must be added to the list |
| 698 | |
| 699 | #ifdef BVH_EXPAND_LEAF_AABBS |
| 700 | // if using expanded AABB in the leaf, the redundancy check will already have been made |
| 701 | BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb; |
| 702 | item_get_AABB(p_handle, expanded_aabb); |
| 703 | #else |
| 704 | // aabb check with expanded aabb. This greatly decreases processing |
| 705 | // at the cost of slightly less accurate pairing checks |
| 706 | // Note this pairing AABB is separate from the AABB in the actual tree |
| 707 | BOUNDS &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb; |
| 708 | |
| 709 | // passing p_check_aabb false disables the optimization which prevents collision checks if |
| 710 | // the aabb hasn't changed. This is needed where set_pairable has been called, but the position |
| 711 | // has not changed. |
| 712 | if (p_check_aabb && tree.expanded_aabb_encloses_not_shrink(expanded_aabb, aabb)) { |
| 713 | return; |
| 714 | } |
| 715 | |
| 716 | // ALWAYS update the new expanded aabb, even if already changed once |
| 717 | // this tick, because it is vital that the AABB is kept up to date |
| 718 | expanded_aabb = aabb; |
| 719 | expanded_aabb.grow_by(tree._pairing_expansion); |
| 720 | #endif |
| 721 | |
| 722 | // this code is to ensure that changed items only appear once on the updated list |
| 723 | // collision checking them multiple times is not needed, and repeats the same thing |
| 724 | uint32_t &last_updated_tick = tree._extra[p_handle.id()].last_updated_tick; |
| 725 | |
| 726 | if (last_updated_tick == _tick) { |
| 727 | return; // already on changed list |
| 728 | } |
| 729 | |
| 730 | // mark as on list |
| 731 | last_updated_tick = _tick; |
| 732 | |
| 733 | // add to the list |
| 734 | changed_items.push_back(p_handle); |
| 735 | } |
| 736 | |
| 737 | void _remove_changed_item(BVHHandle p_handle) { |
| 738 | // Care has to be taken here for items that are deleted. The ref ID |
| 739 | // could be reused on the same tick for new items. This is probably |
| 740 | // rare but should be taken into consideration |
| 741 | |
| 742 | // callbacks |
| 743 | _remove_pairs_containing(p_handle); |
| 744 | |
| 745 | // remove from changed items (not very efficient yet) |
| 746 | for (int n = 0; n < (int)changed_items.size(); n++) { |
| 747 | if (changed_items[n] == p_handle) { |
| 748 | changed_items.remove_at_unordered(n); |
| 749 | |
| 750 | // because we are using an unordered remove, |
| 751 | // the last changed item will now be at spot 'n', |
| 752 | // and we need to redo it, so we prevent moving on to |
| 753 | // the next n at the next for iteration. |
| 754 | n--; |
| 755 | } |
| 756 | } |
| 757 | |
| 758 | // reset the last updated tick (may not be necessary but just in case) |
| 759 | tree._extra[p_handle.id()].last_updated_tick = 0; |
| 760 | } |
| 761 | |
| 762 | PairCallback pair_callback = nullptr; |
| 763 | UnpairCallback unpair_callback = nullptr; |
| 764 | CheckPairCallback check_pair_callback = nullptr; |
| 765 | void *pair_callback_userdata = nullptr; |
| 766 | void *unpair_callback_userdata = nullptr; |
| 767 | void *check_pair_callback_userdata = nullptr; |
| 768 | |
| 769 | BVHTREE_CLASS tree; |
| 770 | |
| 771 | // for collision pairing, |
| 772 | // maintain a list of all items moved etc on each frame / tick |
| 773 | LocalVector<BVHHandle, uint32_t, true> changed_items; |
| 774 | uint32_t _tick = 1; // Start from 1 so items with 0 indicate never updated. |
| 775 | |
| 776 | class BVHLockedFunction { |
| 777 | public: |
| 778 | BVHLockedFunction(Mutex *p_mutex, bool p_thread_safe) { |
| 779 | // will be compiled out if not set in template |
| 780 | if (p_thread_safe) { |
| 781 | _mutex = p_mutex; |
| 782 | _mutex->lock(); |
| 783 | |
| 784 | } else { |
| 785 | _mutex = nullptr; |
| 786 | } |
| 787 | } |
| 788 | ~BVHLockedFunction() { |
| 789 | // will be compiled out if not set in template |
| 790 | if (_mutex) { |
| 791 | _mutex->unlock(); |
| 792 | } |
| 793 | } |
| 794 | |
| 795 | private: |
| 796 | Mutex *_mutex = nullptr; |
| 797 | }; |
| 798 | |
| 799 | Mutex _mutex; |
| 800 | |
| 801 | // local toggle for turning on and off thread safety in project settings |
| 802 | bool _thread_safe = BVH_THREAD_SAFE; |
| 803 | |
| 804 | public: |
| 805 | BVH_Manager() {} |
| 806 | }; |
| 807 | |
| 808 | #undef BVHTREE_CLASS |
| 809 | |
| 810 | #endif // BVH_H |
| 811 | |