1use crate::{Bvh, BvhNode, BvhVolume};
4
5use std::collections::VecDeque;
6
7use bevy_math::bounding::IntersectsVolume;
8
9#[derive(Default)]
11pub struct Stack(VecDeque<u32>);
12
13impl std::ops::Deref for Stack {
14 type Target = VecDeque<u32>;
15
16 fn deref(&self) -> &Self::Target {
17 &self.0
18 }
19}
20
21impl std::ops::DerefMut for Stack {
22 fn deref_mut(&mut self) -> &mut Self::Target {
23 &mut self.0
24 }
25}
26
27impl<Volume: BvhVolume, T: Copy> Bvh<Volume, T> {
28 pub fn create_stack(&self) -> Stack {
30 Stack(VecDeque::with_capacity(
32 (self.items.len() as f32).log2().ceil() as usize + 10,
33 ))
34 }
35
36 pub fn traverse<'a, Test: IntersectsVolume<Volume>>(
38 &'a self,
39 stack: &'a mut Stack,
40 tester: Test,
41 ) -> Traverser<'a, Volume, T, Test> {
42 stack.clear();
43 stack.reserve_exact((self.items.len() as f32).log2().ceil() as usize + 10);
44 stack.push_back(0);
45
46 Traverser {
47 bvh: self,
48 tester,
49 stack,
50 current_node: None,
51 offset: 0,
52 }
53 }
54}
55
56pub struct Traverser<'a, Volume: BvhVolume, T: Copy, Test: IntersectsVolume<Volume>> {
58 bvh: &'a Bvh<Volume, T>,
59 pub tester: Test,
61 stack: &'a mut Stack,
62 current_node: Option<u32>,
63 offset: u32,
64}
65
66impl<'a, Volume: BvhVolume, T: Copy, Test: IntersectsVolume<Volume>> Iterator
67 for Traverser<'a, Volume, T, Test>
68{
69 type Item = &'a T;
70
71 fn next(&mut self) -> Option<Self::Item> {
72 if self.bvh.items.is_empty() {
73 return None;
74 }
75
76 if let Some(current_node) = self.current_node {
77 let node = &self.bvh.nodes[current_node as usize];
78 match self.next_item(node) {
79 None => {}
80 v => return v,
81 };
82 }
83
84 while let Some(index) = self.stack.pop_front() {
85 let node = &self.bvh.nodes[index as usize];
86
87 if !self.tester.intersects(&node.volume) {
88 continue;
89 }
90
91 if node.count > 0 {
92 self.current_node = Some(index);
93 self.offset = 0;
94
95 match self.next_item(node) {
96 None => {}
97 v => return v,
98 };
99 } else {
100 self.stack.push_back(node.start_index);
101 self.stack.push_back(node.start_index + 1);
102 }
103 }
104
105 None
106 }
107}
108
109impl<'a, Volume: BvhVolume, T: Copy, Test: IntersectsVolume<Volume>>
110 Traverser<'a, Volume, T, Test>
111{
112 #[inline(always)]
113 fn next_item(&mut self, node: &'_ BvhNode<Volume>) -> Option<&'a T> {
114 while self.current_node.is_some() {
115 let item = &self.bvh.items[(node.start_index + self.offset) as usize];
116 self.offset += 1;
117 if self.offset == node.count {
118 self.current_node = None;
119 }
120 if self.tester.intersects(&item.volume) {
121 return Some(&item.t);
122 }
123 }
124 None
125 }
126}