| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | struct ItemRef { | 
					
						
							|  |  |  | 	uint32_t tnode_id; // -1 is invalid
 | 
					
						
							|  |  |  | 	uint32_t item_id; // in the leaf
 | 
					
						
							| 
									
										
										
										
											2021-01-29 17:47:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	bool is_active() const { return tnode_id != BVHCommon::INACTIVE; } | 
					
						
							|  |  |  | 	void set_inactive() { | 
					
						
							|  |  |  | 		tnode_id = BVHCommon::INACTIVE; | 
					
						
							|  |  |  | 		item_id = BVHCommon::INACTIVE; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // extra info kept in separate parallel list to the references,
 | 
					
						
							|  |  |  | // as this is less used as keeps cache better
 | 
					
						
							|  |  |  | struct ItemExtra { | 
					
						
							| 
									
										
										
										
											2021-12-03 11:36:39 +00:00
										 |  |  | 	// Before doing user defined pairing checks (especially in the find_leavers function),
 | 
					
						
							|  |  |  | 	// we may want to check that two items have compatible tree ids and tree masks,
 | 
					
						
							|  |  |  | 	// as if they are incompatible they should not pair / collide.
 | 
					
						
							|  |  |  | 	bool are_item_trees_compatible(const ItemExtra &p_other) const { | 
					
						
							|  |  |  | 		uint32_t other_type = 1 << p_other.tree_id; | 
					
						
							|  |  |  | 		if (tree_collision_mask & other_type) { | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		uint32_t our_type = 1 << tree_id; | 
					
						
							|  |  |  | 		if (p_other.tree_collision_mask & our_type) { | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-03 11:36:39 +00:00
										 |  |  | 	// There can be multiple user defined trees
 | 
					
						
							|  |  |  | 	uint32_t tree_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Defines which trees this item should collision check against.
 | 
					
						
							|  |  |  | 	// 1 << tree_id, and normally items would collide against there own
 | 
					
						
							|  |  |  | 	// tree (but not always).
 | 
					
						
							|  |  |  | 	uint32_t tree_collision_mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint32_t last_updated_tick; | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 	int32_t subindex; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-03 11:36:39 +00:00
										 |  |  | 	T *userdata; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 	// the active reference is a separate list of which references
 | 
					
						
							|  |  |  | 	// are active so that we can slowly iterate through it over many frames for
 | 
					
						
							|  |  |  | 	// slow optimize.
 | 
					
						
							|  |  |  | 	uint32_t active_ref_id; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // tree leaf
 | 
					
						
							|  |  |  | struct TLeaf { | 
					
						
							|  |  |  | 	uint16_t num_items; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	uint16_t dirty; | 
					
						
							|  |  |  | 	// separate data orientated lists for faster SIMD traversal
 | 
					
						
							|  |  |  | 	uint32_t item_ref_ids[MAX_ITEMS]; | 
					
						
							| 
									
										
										
										
											2021-04-27 13:56:23 -07:00
										 |  |  | 	BVHABB_CLASS aabbs[MAX_ITEMS]; | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	// accessors
 | 
					
						
							| 
									
										
										
										
											2021-04-27 13:56:23 -07:00
										 |  |  | 	BVHABB_CLASS &get_aabb(uint32_t p_id) { return aabbs[p_id]; } | 
					
						
							|  |  |  | 	const BVHABB_CLASS &get_aabb(uint32_t p_id) const { return aabbs[p_id]; } | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	uint32_t &get_item_ref_id(uint32_t p_id) { return item_ref_ids[p_id]; } | 
					
						
							|  |  |  | 	const uint32_t &get_item_ref_id(uint32_t p_id) const { return item_ref_ids[p_id]; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool is_dirty() const { return dirty; } | 
					
						
							|  |  |  | 	void set_dirty(bool p) { dirty = p; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void clear() { | 
					
						
							|  |  |  | 		num_items = 0; | 
					
						
							|  |  |  | 		set_dirty(true); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bool is_full() const { return num_items >= MAX_ITEMS; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void remove_item_unordered(uint32_t p_id) { | 
					
						
							|  |  |  | 		BVH_ASSERT(p_id < num_items); | 
					
						
							|  |  |  | 		num_items--; | 
					
						
							|  |  |  | 		aabbs[p_id] = aabbs[num_items]; | 
					
						
							|  |  |  | 		item_ref_ids[p_id] = item_ref_ids[num_items]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint32_t request_item() { | 
					
						
							|  |  |  | 		if (num_items < MAX_ITEMS) { | 
					
						
							|  |  |  | 			uint32_t id = num_items; | 
					
						
							|  |  |  | 			num_items++; | 
					
						
							|  |  |  | 			return id; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // tree node
 | 
					
						
							|  |  |  | struct TNode { | 
					
						
							| 
									
										
										
										
											2021-04-27 13:56:23 -07:00
										 |  |  | 	BVHABB_CLASS aabb; | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 	// either number of children if positive
 | 
					
						
							|  |  |  | 	// or leaf id if negative (leaf id 0 is disallowed)
 | 
					
						
							|  |  |  | 	union { | 
					
						
							|  |  |  | 		int32_t num_children; | 
					
						
							|  |  |  | 		int32_t neg_leaf_id; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	uint32_t parent_id; // or -1
 | 
					
						
							|  |  |  | 	uint16_t children[MAX_CHILDREN]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// height in the tree, where leaves are 0, and all above are 1+
 | 
					
						
							|  |  |  | 	// (or the highest where there is a tie off)
 | 
					
						
							|  |  |  | 	int32_t height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool is_leaf() const { return num_children < 0; } | 
					
						
							|  |  |  | 	void set_leaf_id(int id) { neg_leaf_id = -id; } | 
					
						
							|  |  |  | 	int get_leaf_id() const { return -neg_leaf_id; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void clear() { | 
					
						
							|  |  |  | 		num_children = 0; | 
					
						
							|  |  |  | 		parent_id = BVHCommon::INVALID; | 
					
						
							|  |  |  | 		height = 0; // or -1 for testing
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// for safety set to improbable value
 | 
					
						
							|  |  |  | 		aabb.set_to_max_opposite_extents(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// other members are not blanked for speed .. they may be uninitialized
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool is_full_of_children() const { return num_children >= MAX_CHILDREN; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void remove_child_internal(uint32_t child_num) { | 
					
						
							|  |  |  | 		children[child_num] = children[num_children - 1]; | 
					
						
							|  |  |  | 		num_children--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int find_child(uint32_t p_child_node_id) { | 
					
						
							|  |  |  | 		BVH_ASSERT(!is_leaf()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int n = 0; n < num_children; n++) { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			if (children[n] == p_child_node_id) { | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 				return n; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// not found
 | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // instead of using linked list we maintain
 | 
					
						
							|  |  |  | // item references (for quick lookup)
 | 
					
						
							| 
									
										
										
										
											2021-11-09 12:00:07 +00:00
										 |  |  | PooledList<ItemRef, uint32_t, true> _refs; | 
					
						
							|  |  |  | PooledList<ItemExtra, uint32_t, true> _extra; | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | PooledList<ItemPairs> _pairs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // these 2 are not in sync .. nodes != leaves!
 | 
					
						
							| 
									
										
										
										
											2021-11-09 12:00:07 +00:00
										 |  |  | PooledList<TNode, uint32_t, true> _nodes; | 
					
						
							|  |  |  | PooledList<TLeaf, uint32_t, true> _leaves; | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // we can maintain an un-ordered list of which references are active,
 | 
					
						
							|  |  |  | // in order to do a slow incremental optimize of the tree over each frame.
 | 
					
						
							|  |  |  | // This will work best if dynamic objects and static objects are in a different tree.
 | 
					
						
							|  |  |  | LocalVector<uint32_t, uint32_t, true> _active_refs; | 
					
						
							|  |  |  | uint32_t _current_active_ref = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // instead of translating directly to the userdata output,
 | 
					
						
							|  |  |  | // we keep an intermediate list of hits as reference IDs, which can be used
 | 
					
						
							|  |  |  | // for pairing collision detection
 | 
					
						
							|  |  |  | LocalVector<uint32_t, uint32_t, true> _cull_hits; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-03 11:36:39 +00:00
										 |  |  | // We can now have a user definable number of trees.
 | 
					
						
							|  |  |  | // This allows using e.g. a non-pairable and pairable tree,
 | 
					
						
							|  |  |  | // which can be more efficient for example, if we only need check non pairable against the pairable tree.
 | 
					
						
							|  |  |  | // It also may be more efficient in terms of separating static from dynamic objects, by reducing housekeeping.
 | 
					
						
							|  |  |  | // However this is a trade off, as there is a cost of traversing two trees.
 | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | uint32_t _root_node_id[NUM_TREES]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // these values may need tweaking according to the project
 | 
					
						
							|  |  |  | // the bound of the world, and the average velocities of the objects
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // node expansion is important in the rendering tree
 | 
					
						
							|  |  |  | // larger values give less re-insertion as items move...
 | 
					
						
							|  |  |  | // but on the other hand over estimates the bounding box of nodes.
 | 
					
						
							|  |  |  | // we can either use auto mode, where the expansion is based on the root node size, or specify manually
 | 
					
						
							|  |  |  | real_t _node_expansion = 0.5; | 
					
						
							|  |  |  | bool _auto_node_expansion = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // pairing expansion important for physics pairing
 | 
					
						
							|  |  |  | // larger values gives more 'sticky' pairing, and is less likely to exhibit tunneling
 | 
					
						
							|  |  |  | // we can either use auto mode, where the expansion is based on the root node size, or specify manually
 | 
					
						
							|  |  |  | real_t _pairing_expansion = 0.1; | 
					
						
							| 
									
										
										
										
											2021-11-17 06:33:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef BVH_ALLOW_AUTO_EXPANSION
 | 
					
						
							| 
									
										
										
										
											2020-10-21 13:13:20 +01:00
										 |  |  | bool _auto_pairing_expansion = true; | 
					
						
							| 
									
										
										
										
											2021-11-17 06:33:45 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // when using an expanded bound, we must detect the condition where a new AABB
 | 
					
						
							|  |  |  | // is significantly smaller than the expanded bound, as this is a special case where we
 | 
					
						
							|  |  |  | // should override the optimization and create a new expanded bound.
 | 
					
						
							|  |  |  | // This threshold is derived from the _pairing_expansion, and should be recalculated
 | 
					
						
							|  |  |  | // if _pairing_expansion is changed.
 | 
					
						
							|  |  |  | real_t _aabb_shrinkage_threshold = 0.0; |