| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  bvh_abb.h                                                             */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the        */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including    */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
					
						
							|  |  |  | /* the following conditions:                                              */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be         */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.        */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef BVH_ABB_H
 | 
					
						
							|  |  |  | #define BVH_ABB_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // special optimized version of axis aligned bounding box
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | template <class BOUNDS = AABB, class POINT = Vector3> | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | struct BVH_ABB { | 
					
						
							|  |  |  | 	struct ConvexHull { | 
					
						
							|  |  |  | 		// convex hulls (optional)
 | 
					
						
							|  |  |  | 		const Plane *planes; | 
					
						
							|  |  |  | 		int num_planes; | 
					
						
							|  |  |  | 		const Vector3 *points; | 
					
						
							|  |  |  | 		int num_points; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct Segment { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		POINT from; | 
					
						
							|  |  |  | 		POINT to; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	enum IntersectResult { | 
					
						
							|  |  |  | 		IR_MISS = 0, | 
					
						
							|  |  |  | 		IR_PARTIAL, | 
					
						
							|  |  |  | 		IR_FULL, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// we store mins with a negative value in order to test them with SIMD
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	POINT min; | 
					
						
							|  |  |  | 	POINT neg_max; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); } | 
					
						
							|  |  |  | 	bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	void set(const POINT &_min, const POINT &_max) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		min = _min; | 
					
						
							|  |  |  | 		neg_max = -_max; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// to and from standard AABB
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	void from(const BOUNDS &p_aabb) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		min = p_aabb.position; | 
					
						
							|  |  |  | 		neg_max = -(p_aabb.position + p_aabb.size); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	void to(BOUNDS &r_aabb) const { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		r_aabb.position = min; | 
					
						
							|  |  |  | 		r_aabb.size = calculate_size(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void merge(const BVH_ABB &p_o) { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			neg_max[axis] = MIN(neg_max[axis], p_o.neg_max[axis]); | 
					
						
							|  |  |  | 			min[axis] = MIN(min[axis], p_o.min[axis]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	POINT calculate_size() const { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		return -neg_max - min; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-21 12:25:29 +01:00
										 |  |  | 	POINT calculate_center() const { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		return POINT((calculate_size() * 0.5) + min); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	real_t get_proximity_to(const BVH_ABB &p_b) const { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		const POINT d = (min - neg_max) - (p_b.min - p_b.neg_max); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		real_t proximity = 0.0; | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			proximity += Math::abs(d[axis]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return proximity; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int select_by_proximity(const BVH_ABB &p_a, const BVH_ABB &p_b) const { | 
					
						
							|  |  |  | 		return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	uint32_t find_cutting_planes(const typename BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		uint32_t count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int n = 0; n < p_hull.num_planes; n++) { | 
					
						
							|  |  |  | 			const Plane &p = p_hull.planes[n]; | 
					
						
							|  |  |  | 			if (intersects_plane(p)) { | 
					
						
							|  |  |  | 				p_plane_ids[count++] = n; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return count; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool intersects_plane(const Plane &p_p) const { | 
					
						
							|  |  |  | 		Vector3 size = calculate_size(); | 
					
						
							|  |  |  | 		Vector3 half_extents = size * 0.5; | 
					
						
							|  |  |  | 		Vector3 ofs = min + half_extents; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// forward side of plane?
 | 
					
						
							|  |  |  | 		Vector3 point_offset( | 
					
						
							|  |  |  | 				(p_p.normal.x < 0) ? -half_extents.x : half_extents.x, | 
					
						
							|  |  |  | 				(p_p.normal.y < 0) ? -half_extents.y : half_extents.y, | 
					
						
							|  |  |  | 				(p_p.normal.z < 0) ? -half_extents.z : half_extents.z); | 
					
						
							|  |  |  | 		Vector3 point = point_offset + ofs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!p_p.is_point_over(point)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		point = -point_offset + ofs; | 
					
						
							|  |  |  | 		if (p_p.is_point_over(point)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool intersects_convex_optimized(const ConvexHull &p_hull, const uint32_t *p_plane_ids, uint32_t p_num_planes) const { | 
					
						
							|  |  |  | 		Vector3 size = calculate_size(); | 
					
						
							|  |  |  | 		Vector3 half_extents = size * 0.5; | 
					
						
							|  |  |  | 		Vector3 ofs = min + half_extents; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (unsigned int i = 0; i < p_num_planes; i++) { | 
					
						
							|  |  |  | 			const Plane &p = p_hull.planes[p_plane_ids[i]]; | 
					
						
							|  |  |  | 			Vector3 point( | 
					
						
							|  |  |  | 					(p.normal.x > 0) ? -half_extents.x : half_extents.x, | 
					
						
							|  |  |  | 					(p.normal.y > 0) ? -half_extents.y : half_extents.y, | 
					
						
							|  |  |  | 					(p.normal.z > 0) ? -half_extents.z : half_extents.z); | 
					
						
							|  |  |  | 			point += ofs; | 
					
						
							|  |  |  | 			if (p.is_point_over(point)) { | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool intersects_convex_partial(const ConvexHull &p_hull) const { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		BOUNDS bb; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		to(bb); | 
					
						
							|  |  |  | 		return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IntersectResult intersects_convex(const ConvexHull &p_hull) const { | 
					
						
							|  |  |  | 		if (intersects_convex_partial(p_hull)) { | 
					
						
							|  |  |  | 			// fully within? very important for tree checks
 | 
					
						
							|  |  |  | 			if (is_within_convex(p_hull)) { | 
					
						
							|  |  |  | 				return IR_FULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return IR_PARTIAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return IR_MISS; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool is_within_convex(const ConvexHull &p_hull) const { | 
					
						
							|  |  |  | 		// use half extents routine
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		BOUNDS bb; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		to(bb); | 
					
						
							|  |  |  | 		return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool is_point_within_hull(const ConvexHull &p_hull, const Vector3 &p_pt) const { | 
					
						
							|  |  |  | 		for (int n = 0; n < p_hull.num_planes; n++) { | 
					
						
							|  |  |  | 			if (p_hull.planes[n].distance_to(p_pt) > 0.0f) { | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool intersects_segment(const Segment &p_s) const { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		BOUNDS bb; | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		to(bb); | 
					
						
							|  |  |  | 		return bb.intersects_segment(p_s.from, p_s.to); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	bool intersects_point(const POINT &p_pt) const { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		if (_any_lessthan(-p_pt, neg_max)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (_any_lessthan(p_pt, min)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// Very hot in profiling, make sure optimized
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	bool intersects(const BVH_ABB &p_o) const { | 
					
						
							|  |  |  | 		if (_any_morethan(p_o.min, -neg_max)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (_any_morethan(min, -p_o.neg_max)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	// for pre-swizzled tester (this object)
 | 
					
						
							|  |  |  | 	bool intersects_swizzled(const BVH_ABB &p_o) const { | 
					
						
							|  |  |  | 		if (_any_lessthan(min, p_o.min)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (_any_lessthan(neg_max, p_o.neg_max)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 	bool is_other_within(const BVH_ABB &p_o) const { | 
					
						
							|  |  |  | 		if (_any_lessthan(p_o.neg_max, neg_max)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (_any_lessthan(p_o.min, min)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	void grow(const POINT &p_change) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		neg_max -= p_change; | 
					
						
							|  |  |  | 		min -= p_change; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void expand(real_t p_change) { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		POINT change; | 
					
						
							| 
									
										
										
										
											2022-09-19 12:19:54 -05:00
										 |  |  | 		for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) { | 
					
						
							|  |  |  | 			change[axis] = p_change; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		grow(change); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Actually surface area metric.
 | 
					
						
							|  |  |  | 	float get_area() const { | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 		POINT d = calculate_size(); | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void set_to_max_opposite_extents() { | 
					
						
							| 
									
										
										
										
											2022-09-19 12:19:54 -05:00
										 |  |  | 		for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) { | 
					
						
							|  |  |  | 			neg_max[axis] = FLT_MAX; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 		min = neg_max; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	bool _any_morethan(const POINT &p_a, const POINT &p_b) const { | 
					
						
							|  |  |  | 		for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			if (p_a[axis] > p_b[axis]) { | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 16:46:10 +00:00
										 |  |  | 	bool _any_lessthan(const POINT &p_a, const POINT &p_b) const { | 
					
						
							|  |  |  | 		for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) { | 
					
						
							| 
									
										
										
										
											2021-05-10 14:43:13 -07:00
										 |  |  | 			if (p_a[axis] < p_b[axis]) { | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif // BVH_ABB_H
 |