parry3d/partitioning/bvh/
bvh_traverse_bvtt.rs1use super::{Bvh, BvhNode, BvhWorkspace};
2use smallvec::SmallVec;
3
4const TRAVERSAL_STACK_SIZE: usize = 32;
5
6impl Bvh {
7 pub fn traverse_bvtt_single_tree<const CHANGE_DETECTION: bool>(
20 &self,
21 workspace: &mut BvhWorkspace,
22 f: &mut impl FnMut(u32, u32),
23 ) {
24 if self.nodes.is_empty() || self.nodes[0].right.leaf_count() == 0 {
25 return;
27 }
28
29 workspace.traversal_stack.clear();
30 self.self_intersect_node::<CHANGE_DETECTION>(workspace, 0, f)
31 }
32
33 fn self_intersect_node<const CHANGE_DETECTION: bool>(
39 &self,
40 workspace: &mut BvhWorkspace,
41 id: u32,
42 f: &mut impl FnMut(u32, u32),
43 ) {
44 let node = &self.nodes[id as usize];
45
46 if CHANGE_DETECTION && !node.right.is_changed() && !node.left.is_changed() {
47 return;
48 }
49
50 let left_right_intersect = node.left.intersects(&node.right);
51 let left_child = node.left.children;
52 let right_child = node.right.children;
53 let left_is_leaf = node.left.is_leaf();
54 let right_is_leaf = node.right.is_leaf();
55
56 if (!CHANGE_DETECTION || node.left.is_changed()) && !left_is_leaf {
57 self.self_intersect_node::<CHANGE_DETECTION>(workspace, left_child, f);
58 }
59
60 if (!CHANGE_DETECTION || node.right.is_changed()) && !right_is_leaf {
61 self.self_intersect_node::<CHANGE_DETECTION>(workspace, right_child, f);
62 }
63
64 if left_right_intersect {
65 match (left_is_leaf, right_is_leaf) {
66 (true, true) => f(left_child, right_child),
67 (true, false) => self.traverse_single_subtree::<CHANGE_DETECTION>(
68 workspace,
69 &node.left,
70 right_child,
71 f,
72 ),
73 (false, true) => self.traverse_single_subtree::<CHANGE_DETECTION>(
74 workspace,
75 &node.right,
76 left_child,
77 f,
78 ),
79 (false, false) => self.traverse_two_branches::<CHANGE_DETECTION>(
80 workspace,
81 left_child,
82 right_child,
83 f,
84 ),
85 }
86 }
87 }
88
89 fn traverse_two_branches<const CHANGE_DETECTION: bool>(
90 &self,
91 workspace: &mut BvhWorkspace,
92 a: u32,
93 b: u32,
94 f: &mut impl FnMut(u32, u32),
95 ) {
96 let node1 = &self.nodes[a as usize];
97 let node2 = &self.nodes[b as usize];
98
99 let left1 = &node1.left;
100 let right1 = &node1.right;
101 let left2 = &node2.left;
102 let right2 = &node2.right;
103
104 let left_left = (!CHANGE_DETECTION || left1.is_changed() || left2.is_changed())
105 && left1.intersects(left2);
106 let left_right = (!CHANGE_DETECTION || left1.is_changed() || right2.is_changed())
107 && left1.intersects(right2);
108 let right_left = (!CHANGE_DETECTION || right1.is_changed() || left2.is_changed())
109 && right1.intersects(left2);
110 let right_right = (!CHANGE_DETECTION || right1.is_changed() || right2.is_changed())
111 && right1.intersects(right2);
112
113 macro_rules! dispatch(
114 ($check: ident, $child_a: ident, $child_b: ident) => {
115 if $check {
116 match ($child_a.is_leaf(), $child_b.is_leaf()) {
117 (true, true) => f($child_a.children, $child_b.children),
118 (true, false) => {
119 self.traverse_single_subtree::<CHANGE_DETECTION>(workspace, $child_a, $child_b.children, f)
120 }
121 (false, true) => self.traverse_single_subtree::<CHANGE_DETECTION>(
122 workspace,
123 $child_b,
124 $child_a.children,
125 f,
126 ),
127 (false, false) => self.traverse_two_branches::<CHANGE_DETECTION>(
128 workspace,
129 $child_a.children,
130 $child_b.children,
131 f,
132 ),
133 }
134 }
135 }
136 );
137
138 dispatch!(left_left, left1, left2);
139 dispatch!(left_right, left1, right2);
140 dispatch!(right_left, right1, left2);
141 dispatch!(right_right, right1, right2);
142 }
143
144 fn traverse_single_subtree<const CHANGE_DETECTION: bool>(
146 &self,
147 workspace: &mut BvhWorkspace,
148 node: &BvhNode,
149 subtree: u32,
150 f: &mut impl FnMut(u32, u32),
151 ) {
152 debug_assert!(workspace.traversal_stack.is_empty());
153
154 let mut curr_id = subtree;
158 let node_changed = node.is_changed();
159
160 loop {
161 let curr = &self.nodes[curr_id as usize];
162 let left = &curr.left;
163 let right = &curr.right;
164 let left_check =
165 (!CHANGE_DETECTION || node_changed || left.is_changed()) && node.intersects(left);
166 let right_check =
167 (!CHANGE_DETECTION || node_changed || right.is_changed()) && node.intersects(right);
168 let left_is_leaf = left.is_leaf();
169 let right_is_leaf = right.is_leaf();
170 let mut found_next = false;
171
172 if left_check {
173 if left_is_leaf {
174 f(node.children, left.children)
175 } else {
176 curr_id = left.children;
177 found_next = true;
178 }
179 }
180
181 if right_check {
182 if right_is_leaf {
183 f(node.children, right.children)
184 } else if !found_next {
185 curr_id = right.children;
186 found_next = true;
187 } else {
188 workspace.traversal_stack.push(right.children);
191 }
192 }
193
194 if !found_next {
195 if let Some(next_id) = workspace.traversal_stack.pop() {
197 curr_id = next_id;
198 } else {
199 return;
201 }
202 }
203 }
204 }
205
206 pub fn leaf_pairs<'a, F: Fn(&BvhNode, &BvhNode) -> bool>(
211 &'a self,
212 other: &'a Self,
213 check: F,
214 ) -> LeafPairs<'a, F> {
215 if let (Some(root1), Some(root2)) = (self.nodes.first(), other.nodes.first()) {
216 let mut stack = SmallVec::default();
217
218 if root1.left.leaf_count() > 0 && root2.right.leaf_count() > 0 {
219 stack.push((&root1.left, &root2.right));
220 }
224
225 if root1.right.leaf_count() > 0 {
226 if root2.right.leaf_count() > 0 {
227 stack.push((&root1.right, &root2.right));
228 }
229 stack.push((&root1.right, &root2.left))
230 }
231
232 LeafPairs {
233 tree1: self,
234 tree2: other,
235 next: Some((&root1.left, &root2.left)),
236 stack,
237 check,
238 }
239 } else {
240 LeafPairs {
241 tree1: self,
242 tree2: other,
243 next: None,
244 stack: Default::default(),
245 check,
246 }
247 }
248 }
249}
250
251pub struct LeafPairs<'a, Check: Fn(&BvhNode, &BvhNode) -> bool> {
252 tree1: &'a Bvh,
253 tree2: &'a Bvh,
254 next: Option<(&'a BvhNode, &'a BvhNode)>,
255 stack: SmallVec<[(&'a BvhNode, &'a BvhNode); TRAVERSAL_STACK_SIZE]>,
256 check: Check,
257}
258
259impl<'a, Check: Fn(&BvhNode, &BvhNode) -> bool> Iterator for LeafPairs<'a, Check> {
260 type Item = (u32, u32);
261 fn next(&mut self) -> Option<Self::Item> {
262 loop {
263 if self.next.is_none() {
264 self.next = self.stack.pop();
265 }
266
267 let (node1, node2) = self.next.take()?;
268
269 match (node1.is_leaf(), node2.is_leaf()) {
270 (true, true) => return Some((node1.children, node2.children)),
271 (true, false) => {
272 let child2 = &self.tree2.nodes[node2.children as usize];
273 if (self.check)(node1, &child2.left) {
274 self.next = Some((node1, &child2.left));
275 }
276 if (self.check)(node1, &child2.right) {
277 if self.next.is_none() {
278 self.next = Some((node1, &child2.right));
279 } else {
280 self.stack.push((node1, &child2.right));
281 }
282 }
283 }
284 (false, true) => {
285 let child1 = &self.tree1.nodes[node1.children as usize];
286 if (self.check)(&child1.left, node2) {
287 self.next = Some((&child1.left, node2));
288 }
289 if (self.check)(&child1.right, node2) {
290 if self.next.is_none() {
291 self.next = Some((&child1.right, node2));
292 } else {
293 self.stack.push((&child1.right, node2));
294 }
295 }
296 }
297 (false, false) => {
298 let child1 = &self.tree1.nodes[node1.children as usize];
299 let child2 = &self.tree2.nodes[node2.children as usize];
300 if (self.check)(&child1.left, &child2.left) {
301 self.stack.push((&child1.left, &child2.left));
302 }
303 if (self.check)(&child1.right, &child2.left) {
304 self.stack.push((&child1.right, &child2.left));
305 }
306 if (self.check)(&child1.left, &child2.right) {
307 self.stack.push((&child1.left, &child2.right));
308 }
309 if (self.check)(&child1.right, &child2.right) {
310 self.stack.push((&child1.right, &child2.right));
311 }
312 }
313 }
314 }
315 }
316}