| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | BVHHandle item_add(T *p_userdata, bool p_active, const BOUNDS &p_aabb, int32_t p_subindex, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_invisible = false) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | #ifdef BVH_VERBOSE_TREE
 | 
					
						
							|  |  |  | 	VERBOSE_PRINT("\nitem_add BEFORE"); | 
					
						
							| 
									
										
										
										
											2022-07-25 17:37:28 +02:00
										 |  |  | 	_debug_recursive_print_tree(p_tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	VERBOSE_PRINT("\n"); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BVHABB_CLASS abb; | 
					
						
							|  |  |  | 	abb.from(p_aabb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// NOTE that we do not expand the AABB for the first create even if
 | 
					
						
							|  |  |  | 	// leaf expansion is switched on. This is for two reasons:
 | 
					
						
							|  |  |  | 	// (1) We don't know if this object will move in future, in which case a non-expanded
 | 
					
						
							|  |  |  | 	// bound would be better...
 | 
					
						
							|  |  |  | 	// (2) We don't yet know how many objects will be paired, which is used to modify
 | 
					
						
							|  |  |  | 	// the expansion margin.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	// handle to be filled with the new item ref
 | 
					
						
							|  |  |  | 	BVHHandle handle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ref id easier to pass around than handle
 | 
					
						
							|  |  |  | 	uint32_t ref_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// this should never fail
 | 
					
						
							|  |  |  | 	ItemRef *ref = _refs.request(ref_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// the extra data should be parallel list to the references
 | 
					
						
							|  |  |  | 	uint32_t extra_id; | 
					
						
							|  |  |  | 	ItemExtra *extra = _extra.request(extra_id); | 
					
						
							|  |  |  | 	BVH_ASSERT(extra_id == ref_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// pairs info
 | 
					
						
							|  |  |  | 	if (USE_PAIRS) { | 
					
						
							|  |  |  | 		uint32_t pairs_id; | 
					
						
							|  |  |  | 		ItemPairs *pairs = _pairs.request(pairs_id); | 
					
						
							|  |  |  | 		pairs->clear(); | 
					
						
							|  |  |  | 		BVH_ASSERT(pairs_id == ref_id); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	extra->subindex = p_subindex; | 
					
						
							|  |  |  | 	extra->userdata = p_userdata; | 
					
						
							|  |  |  | 	extra->last_updated_tick = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// add an active reference to the list for slow incremental optimize
 | 
					
						
							|  |  |  | 	// this list must be kept in sync with the references as they are added or removed.
 | 
					
						
							|  |  |  | 	extra->active_ref_id = _active_refs.size(); | 
					
						
							|  |  |  | 	_active_refs.push_back(ref_id); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	extra->tree_id = p_tree_id; | 
					
						
							|  |  |  | 	extra->tree_collision_mask = p_tree_collision_mask; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// assign to handle to return
 | 
					
						
							|  |  |  | 	handle.set_id(ref_id); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	create_root_node(p_tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// we must choose where to add to tree
 | 
					
						
							|  |  |  | 	if (p_active) { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		ref->tnode_id = _logic_choose_item_add_node(_root_node_id[p_tree_id], abb); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		bool refit = _node_add_item(ref->tnode_id, ref_id, abb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (refit) { | 
					
						
							|  |  |  | 			// only need to refit from the parent
 | 
					
						
							|  |  |  | 			const TNode &add_node = _nodes[ref->tnode_id]; | 
					
						
							|  |  |  | 			if (add_node.parent_id != BVHCommon::INVALID) { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 				refit_upward_and_balance(add_node.parent_id, p_tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ref->set_inactive(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef BVH_VERBOSE
 | 
					
						
							|  |  |  | 	// memory use
 | 
					
						
							|  |  |  | 	int mem = _refs.estimate_memory_use(); | 
					
						
							|  |  |  | 	mem += _nodes.estimate_memory_use(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String sz = _debug_aabb_to_string(abb); | 
					
						
							| 
									
										
										
										
											2022-07-25 17:37:28 +02:00
										 |  |  | 	VERBOSE_PRINT("\titem_add [" + itos(ref_id) + "] " + itos(_refs.used_size()) + " refs,\t" + itos(_nodes.used_size()) + " nodes " + sz); | 
					
						
							|  |  |  | 	VERBOSE_PRINT("mem use : " + itos(mem) + ", num nodes reserved : " + itos(_nodes.reserved_size())); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return handle; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void _debug_print_refs() { | 
					
						
							|  |  |  | #ifdef BVH_VERBOSE_TREE
 | 
					
						
							|  |  |  | 	print_line("refs....."); | 
					
						
							|  |  |  | 	for (int n = 0; n < _refs.size(); n++) { | 
					
						
							|  |  |  | 		const ItemRef &ref = _refs[n]; | 
					
						
							|  |  |  | 		print_line("tnode_id " + itos(ref.tnode_id) + ", item_id " + itos(ref.item_id)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // returns false if noop
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | bool item_move(BVHHandle p_handle, const BOUNDS &p_aabb) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// get the reference
 | 
					
						
							|  |  |  | 	ItemRef &ref = _refs[ref_id]; | 
					
						
							|  |  |  | 	if (!ref.is_active()) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BVHABB_CLASS abb; | 
					
						
							|  |  |  | 	abb.from(p_aabb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | #ifdef BVH_EXPAND_LEAF_AABBS
 | 
					
						
							|  |  |  | 	if (USE_PAIRS) { | 
					
						
							|  |  |  | 		// scale the pairing expansion by the number of pairs.
 | 
					
						
							|  |  |  | 		abb.expand(_pairs[ref_id].scale_expansion_margin(_pairing_expansion)); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		abb.expand(_pairing_expansion); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID); | 
					
						
							|  |  |  | 	TNode &tnode = _nodes[ref.tnode_id]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// does it fit within the current leaf aabb?
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	if (tnode.aabb.is_other_within(abb)) { | 
					
						
							|  |  |  | 		// do nothing .. fast path .. not moved enough to need refit
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// however we WILL update the exact aabb in the leaf, as this will be needed
 | 
					
						
							|  |  |  | 		// for accurate collision detection
 | 
					
						
							|  |  |  | 		TLeaf &leaf = _node_get_leaf(tnode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		BVHABB_CLASS &leaf_abb = leaf.get_aabb(ref.item_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// no change?
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | #ifdef BVH_EXPAND_LEAF_AABBS
 | 
					
						
							|  |  |  | 		BOUNDS leaf_aabb; | 
					
						
							|  |  |  | 		leaf_abb.to(leaf_aabb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// This test should pass in a lot of cases, and by returning false we can avoid
 | 
					
						
							|  |  |  | 		// collision pairing checks later, which greatly reduces processing.
 | 
					
						
							|  |  |  | 		if (expanded_aabb_encloses_not_shrink(leaf_aabb, p_aabb)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		if (leaf_abb == abb) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef BVH_VERBOSE_MOVES
 | 
					
						
							|  |  |  | 		print_line("item_move " + itos(p_handle.id()) + "(within tnode aabb) : " + _debug_aabb_to_string(abb)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		leaf_abb = abb; | 
					
						
							|  |  |  | 		_integrity_check_all(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | #ifdef BVH_VERBOSE_MOVES
 | 
					
						
							|  |  |  | 	print_line("item_move " + itos(p_handle.id()) + "(outside tnode aabb) : " + _debug_aabb_to_string(abb)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	uint32_t tree_id = _handle_get_tree_id(p_handle); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// remove and reinsert
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	node_remove_item(ref_id, tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// we must choose where to add to tree
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// add to the tree
 | 
					
						
							|  |  |  | 	bool needs_refit = _node_add_item(ref.tnode_id, ref_id, abb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// only need to refit from the PARENT
 | 
					
						
							|  |  |  | 	if (needs_refit) { | 
					
						
							|  |  |  | 		// only need to refit from the parent
 | 
					
						
							|  |  |  | 		const TNode &add_node = _nodes[ref.tnode_id]; | 
					
						
							|  |  |  | 		if (add_node.parent_id != BVHCommon::INVALID) { | 
					
						
							|  |  |  | 			// not sure we need to rebalance all the time, this can be done less often
 | 
					
						
							|  |  |  | 			refit_upward(add_node.parent_id); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		//refit_upward_and_balance(add_node.parent_id);
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void item_remove(BVHHandle p_handle) { | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	uint32_t tree_id = _handle_get_tree_id(p_handle); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	VERBOSE_PRINT("item_remove [" + itos(ref_id) + "] "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	////////////////////////////////////////
 | 
					
						
							|  |  |  | 	// remove the active reference from the list for slow incremental optimize
 | 
					
						
							|  |  |  | 	// this list must be kept in sync with the references as they are added or removed.
 | 
					
						
							|  |  |  | 	uint32_t active_ref_id = _extra[ref_id].active_ref_id; | 
					
						
							|  |  |  | 	uint32_t ref_id_moved_back = _active_refs[_active_refs.size() - 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// swap back and decrement for fast unordered remove
 | 
					
						
							|  |  |  | 	_active_refs[active_ref_id] = ref_id_moved_back; | 
					
						
							|  |  |  | 	_active_refs.resize(_active_refs.size() - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// keep the moved active reference up to date
 | 
					
						
							|  |  |  | 	_extra[ref_id_moved_back].active_ref_id = active_ref_id; | 
					
						
							|  |  |  | 	////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// remove the item from the node (only if active)
 | 
					
						
							|  |  |  | 	if (_refs[ref_id].is_active()) { | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 		node_remove_item(ref_id, tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// remove the item reference
 | 
					
						
							|  |  |  | 	_refs.free(ref_id); | 
					
						
							|  |  |  | 	_extra.free(ref_id); | 
					
						
							|  |  |  | 	if (USE_PAIRS) { | 
					
						
							|  |  |  | 		_pairs.free(ref_id); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// don't think refit_all is necessary?
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	//refit_all(_tree_id);
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef BVH_VERBOSE_TREE
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	_debug_recursive_print_tree(tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // returns success
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | bool item_activate(BVHHandle p_handle, const BOUNDS &p_aabb) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 	ItemRef &ref = _refs[ref_id]; | 
					
						
							|  |  |  | 	if (ref.is_active()) { | 
					
						
							|  |  |  | 		// noop
 | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// add to tree
 | 
					
						
							|  |  |  | 	BVHABB_CLASS abb; | 
					
						
							|  |  |  | 	abb.from(p_aabb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	uint32_t tree_id = _handle_get_tree_id(p_handle); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// we must choose where to add to tree
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	_node_add_item(ref.tnode_id, ref_id, abb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	refit_upward_and_balance(ref.tnode_id, tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // returns success
 | 
					
						
							|  |  |  | bool item_deactivate(BVHHandle p_handle) { | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 	ItemRef &ref = _refs[ref_id]; | 
					
						
							|  |  |  | 	if (!ref.is_active()) { | 
					
						
							|  |  |  | 		// noop
 | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	uint32_t tree_id = _handle_get_tree_id(p_handle); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	// remove from tree
 | 
					
						
							|  |  |  | 	BVHABB_CLASS abb; | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 	node_remove_item(ref_id, tree_id, &abb); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// mark as inactive
 | 
					
						
							|  |  |  | 	ref.set_inactive(); | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool item_get_active(BVHHandle p_handle) const { | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 	const ItemRef &ref = _refs[ref_id]; | 
					
						
							|  |  |  | 	return ref.is_active(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // during collision testing, we want to set the mask and whether pairable for the item testing from
 | 
					
						
							|  |  |  | void item_fill_cullparams(BVHHandle p_handle, CullParams &r_params) const { | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 	const ItemExtra &extra = _extra[ref_id]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// which trees does this item want to collide detect against?
 | 
					
						
							|  |  |  | 	r_params.tree_collision_mask = extra.tree_collision_mask; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// The testing user defined object is passed to the user defined cull check function
 | 
					
						
							|  |  |  | 	// for masks etc. This is usually a dummy object of type T with masks set.
 | 
					
						
							|  |  |  | 	// However, if not using the cull_check callback (i.e. returning true), you can pass
 | 
					
						
							|  |  |  | 	// a nullptr instead of dummy object, as it will not be used.
 | 
					
						
							|  |  |  | 	r_params.tester = extra.userdata; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool item_is_pairable(const BVHHandle &p_handle) { | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 	const ItemExtra &extra = _extra[ref_id]; | 
					
						
							|  |  |  | 	return extra.pairable != 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void item_get_ABB(const BVHHandle &p_handle, BVHABB_CLASS &r_abb) { | 
					
						
							|  |  |  | 	// change tree?
 | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 	const ItemRef &ref = _refs[ref_id]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	TNode &tnode = _nodes[ref.tnode_id]; | 
					
						
							|  |  |  | 	TLeaf &leaf = _node_get_leaf(tnode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r_abb = leaf.get_aabb(ref.item_id); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | bool item_set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	// change tree?
 | 
					
						
							|  |  |  | 	uint32_t ref_id = p_handle.id(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ItemExtra &ex = _extra[ref_id]; | 
					
						
							|  |  |  | 	ItemRef &ref = _refs[ref_id]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool active = ref.is_active(); | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	bool tree_changed = ex.tree_id != p_tree_id; | 
					
						
							|  |  |  | 	bool mask_changed = ex.tree_collision_mask != p_tree_collision_mask; | 
					
						
							|  |  |  | 	bool state_changed = tree_changed | mask_changed; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// Keep an eye on this for bugs of not noticing changes to objects,
 | 
					
						
							|  |  |  | 	// especially when changing client user masks that will not be detected as a change
 | 
					
						
							|  |  |  | 	// in the BVH. You may need to force a collision check in this case with recheck_pairs().
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	if (active && (tree_changed | mask_changed)) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		// record abb
 | 
					
						
							|  |  |  | 		TNode &tnode = _nodes[ref.tnode_id]; | 
					
						
							|  |  |  | 		TLeaf &leaf = _node_get_leaf(tnode); | 
					
						
							|  |  |  | 		BVHABB_CLASS abb = leaf.get_aabb(ref.item_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// make sure current tree is correct prior to changing
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 		uint32_t tree_id = _handle_get_tree_id(p_handle); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// remove from old tree
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 		node_remove_item(ref_id, tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// we must set the pairable AFTER getting the current tree
 | 
					
						
							|  |  |  | 		// because the pairable status determines which tree
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		ex.tree_id = p_tree_id; | 
					
						
							|  |  |  | 		ex.tree_collision_mask = p_tree_collision_mask; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// add to new tree
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 		tree_id = _handle_get_tree_id(p_handle); | 
					
						
							|  |  |  | 		create_root_node(tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// we must choose where to add to tree
 | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 		ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		bool needs_refit = _node_add_item(ref.tnode_id, ref_id, abb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// only need to refit from the PARENT
 | 
					
						
							|  |  |  | 		if (needs_refit) { | 
					
						
							|  |  |  | 			// only need to refit from the parent
 | 
					
						
							|  |  |  | 			const TNode &add_node = _nodes[ref.tnode_id]; | 
					
						
							|  |  |  | 			if (add_node.parent_id != BVHCommon::INVALID) { | 
					
						
							| 
									
										
										
										
											2021-05-29 18:03:43 +01:00
										 |  |  | 				refit_upward_and_balance(add_node.parent_id, tree_id); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// always keep this up to date
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		ex.tree_id = p_tree_id; | 
					
						
							|  |  |  | 		ex.tree_collision_mask = p_tree_collision_mask; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return state_changed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void incremental_optimize() { | 
					
						
							|  |  |  | 	// first update all aabbs as one off step..
 | 
					
						
							|  |  |  | 	// this is cheaper than doing it on each move as each leaf may get touched multiple times
 | 
					
						
							|  |  |  | 	// in a frame.
 | 
					
						
							|  |  |  | 	for (int n = 0; n < NUM_TREES; n++) { | 
					
						
							|  |  |  | 		if (_root_node_id[n] != BVHCommon::INVALID) { | 
					
						
							|  |  |  | 			refit_branch(_root_node_id[n]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// now do small section reinserting to get things moving
 | 
					
						
							|  |  |  | 	// gradually, and keep items in the right leaf
 | 
					
						
							|  |  |  | 	if (_current_active_ref >= _active_refs.size()) { | 
					
						
							|  |  |  | 		_current_active_ref = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// special case
 | 
					
						
							|  |  |  | 	if (!_active_refs.size()) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint32_t ref_id = _active_refs[_current_active_ref++]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_logic_item_remove_and_reinsert(ref_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef BVH_VERBOSE
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	// memory use
 | 
					
						
							|  |  |  | 	int mem_refs = _refs.estimate_memory_use(); | 
					
						
							|  |  |  | 	int mem_nodes = _nodes.estimate_memory_use(); | 
					
						
							|  |  |  | 	int mem_leaves = _leaves.estimate_memory_use(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String sz; | 
					
						
							|  |  |  | 	sz += "mem_refs : " + itos(mem_refs) + " "; | 
					
						
							|  |  |  | 	sz += "mem_nodes : " + itos(mem_nodes) + " "; | 
					
						
							|  |  |  | 	sz += "mem_leaves : " + itos(mem_leaves) + " "; | 
					
						
							|  |  |  | 	sz += ", num nodes : " + itos(_nodes.size()); | 
					
						
							|  |  |  | 	print_line(sz); | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void update() { | 
					
						
							|  |  |  | 	incremental_optimize(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// keep the expansion values up to date with the world bound
 | 
					
						
							|  |  |  | //#define BVH_ALLOW_AUTO_EXPANSION
 | 
					
						
							|  |  |  | #ifdef BVH_ALLOW_AUTO_EXPANSION
 | 
					
						
							|  |  |  | 	if (_auto_node_expansion || _auto_pairing_expansion) { | 
					
						
							|  |  |  | 		BVHABB_CLASS world_bound; | 
					
						
							|  |  |  | 		world_bound.set_to_max_opposite_extents(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bool bound_valid = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int n = 0; n < NUM_TREES; n++) { | 
					
						
							|  |  |  | 			uint32_t node_id = _root_node_id[n]; | 
					
						
							|  |  |  | 			if (node_id != BVHCommon::INVALID) { | 
					
						
							|  |  |  | 				world_bound.merge(_nodes[node_id].aabb); | 
					
						
							|  |  |  | 				bound_valid = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// if there are no nodes, do nothing, but if there are...
 | 
					
						
							|  |  |  | 		if (bound_valid) { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 			BOUNDS bb; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			world_bound.to(bb); | 
					
						
							|  |  |  | 			real_t size = bb.get_longest_axis_size(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// automatic AI decision for best parameters.
 | 
					
						
							|  |  |  | 			// These can be overridden in project settings.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// these magic numbers are determined by experiment
 | 
					
						
							|  |  |  | 			if (_auto_node_expansion) { | 
					
						
							|  |  |  | 				_node_expansion = size * 0.025; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (_auto_pairing_expansion) { | 
					
						
							|  |  |  | 				_pairing_expansion = size * 0.009; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void params_set_pairing_expansion(real_t p_value) { | 
					
						
							|  |  |  | 	if (p_value < 0.0) { | 
					
						
							|  |  |  | #ifdef BVH_ALLOW_AUTO_EXPANSION
 | 
					
						
							|  |  |  | 		_auto_pairing_expansion = true; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #ifdef BVH_ALLOW_AUTO_EXPANSION
 | 
					
						
							|  |  |  | 	_auto_pairing_expansion = false; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_pairing_expansion = p_value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// calculate shrinking threshold
 | 
					
						
							|  |  |  | 	const real_t fudge_factor = 1.1; | 
					
						
							|  |  |  | 	_aabb_shrinkage_threshold = _pairing_expansion * POINT::AXIS_COUNT * 2.0 * fudge_factor; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This routine is not just an enclose check, it also checks for special case of shrinkage
 | 
					
						
							|  |  |  | bool expanded_aabb_encloses_not_shrink(const BOUNDS &p_expanded_aabb, const BOUNDS &p_aabb) const { | 
					
						
							|  |  |  | 	if (!p_expanded_aabb.encloses(p_aabb)) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check for special case of shrinkage. If the aabb has shrunk
 | 
					
						
							|  |  |  | 	// significantly we want to create a new expanded bound, because
 | 
					
						
							|  |  |  | 	// the previous expanded bound will have diverged significantly.
 | 
					
						
							|  |  |  | 	const POINT &exp_size = p_expanded_aabb.size; | 
					
						
							|  |  |  | 	const POINT &new_size = p_aabb.size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	real_t exp_l = 0.0; | 
					
						
							|  |  |  | 	real_t new_l = 0.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < POINT::AXIS_COUNT; ++i) { | 
					
						
							|  |  |  | 		exp_l += exp_size[i]; | 
					
						
							|  |  |  | 		new_l += new_size[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// is difference above some metric
 | 
					
						
							|  |  |  | 	real_t diff = exp_l - new_l; | 
					
						
							|  |  |  | 	if (diff < _aabb_shrinkage_threshold) { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } |