1use glam::Vec2;
2use rpds::Vector;
3use smallvec::{smallvec, SmallVec};
4
5use crate::{
6 util::{face_intersect, face_intersect_dir, Intersect},
7 ClippedFace, Face, Side, TOLERANCE,
8};
9
10use super::{NodeIndex, Nodes};
11
12#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
13#[derive(Debug)]
14pub struct BSPNode {
21 origin: Vec2,
22 normal: Vec2,
23
24 front: Option<NodeIndex>,
25 back: Option<NodeIndex>,
26
27 faces: SmallVec<[Face; 2]>,
28
29 depth: usize,
30}
31
32impl BSPNode {
33 pub fn from_faces(nodes: &mut Nodes, faces: &[Face], depth: usize) -> Option<NodeIndex> {
36 let (current, faces) = faces.split_first()?;
37 let p = current.vertices[0];
39
40 let mut front = Vec::new();
41 let mut back = Vec::new();
42
43 let mut coplanar = smallvec![*current];
44
45 let normal = current.normal;
46
47 for face in faces {
48 let side = face.side_of(current.vertices[0], current.normal);
49 match side {
50 Side::Front => front.push(*face),
51 Side::Back => back.push(*face),
52 Side::Coplanar => {
53 coplanar.push(*face);
54 }
55 Side::Intersecting => {
56 let intersect = face_intersect(face.into_tuple(), p, normal);
58
59 let [a, b] = face.split(intersect.point, normal);
60
61 assert_eq!(a.side_of(p, normal), Side::Front);
62 assert_eq!(b.side_of(p, normal), Side::Back);
63
64 assert!(a.normal.dot(face.normal) > 0.0);
65 assert!(b.normal.dot(face.normal) > 0.0);
66
67 front.push(a);
68 back.push(b)
69 }
70 }
71 }
72
73 let front = Self::from_faces(nodes, &front, depth + 1);
74 let back = Self::from_faces(nodes, &back, depth + 1);
75
76 assert!(current.normal.is_normalized());
77
78 let node = Self {
79 origin: current.midpoint(),
81 faces: coplanar,
82 normal: current.normal,
83 front,
84 back,
85 depth,
86 };
87
88 Some(nodes.insert(node))
89 }
90
91 pub fn get_side(&self, point: Vec2) -> Side {
92 let dot = (point - self.origin).dot(self.normal());
93
94 if dot.abs() < TOLERANCE {
95 Side::Coplanar
96 } else if dot <= 0.0 {
97 Side::Back
98 } else {
99 Side::Front
100 }
101 }
102
103 pub fn front(&self) -> Option<NodeIndex> {
105 self.front
106 }
107
108 pub fn back(&self) -> Option<NodeIndex> {
110 self.back
111 }
112
113 #[inline]
115 pub fn normal(&self) -> Vec2 {
116 self.normal
117 }
118
119 #[inline]
121 pub fn origin(&self) -> Vec2 {
122 self.origin
123 }
124
125 pub fn descendants(index: NodeIndex, nodes: &Nodes) -> Descendants {
126 Descendants {
127 nodes,
128 stack: vec![index],
129 }
130 }
131
132 pub fn depth(&self) -> usize {
134 self.depth
135 }
136
137 fn get_adjacent_side(&self, p: Vec2, other: Vec2) -> Option<Side> {
138 self.faces
139 .iter()
140 .filter_map(|f| {
141 if f.contains_point(p) {
142 Some(if (other - f.vertices[0]).dot(f.normal()) > 0.0 {
143 Side::Front
144 } else {
145 Side::Back
146 })
147 } else {
148 None
149 }
150 })
151 .reduce(|acc, val| acc.min_side(val))
152 }
153
154 pub fn clip(
156 index: NodeIndex,
157 nodes: &Nodes,
158 mut portal: ClippedFace,
159 root_side: Side,
160 ) -> Vec<ClippedFace> {
161 let node = &nodes[index];
162
163 let side = portal.side_of(node.origin, node.normal);
164 let a = (portal.vertices[0] - node.origin).dot(node.normal);
166 let b = (portal.vertices[1] - node.origin).dot(node.normal);
167
168 if a.abs() < TOLERANCE {
170 if let Some(ad) = node.get_adjacent_side(portal.vertices[0], portal.vertices[1]) {
171 portal.adjacent[0] = true;
172 portal.sides[0] = ad;
173 }
174 }
175 if b.abs() < TOLERANCE {
177 if let Some(ad) = node.get_adjacent_side(portal.vertices[1], portal.vertices[0]) {
178 portal.adjacent[1] = true;
179 portal.sides[1] = ad;
180 }
181 }
182
183 Self::clip_new(index, nodes, portal, side, root_side)
184 }
185
186 fn clip_new(
187 index: NodeIndex,
188 nodes: &Nodes,
189 mut portal: ClippedFace,
190 side: Side,
191 root_side: Side,
192 ) -> Vec<ClippedFace> {
193 let node = &nodes[index];
194 match (side, node.front, node.back) {
196 (Side::Coplanar, Some(front), Some(back)) => {
197 Self::clip(front, nodes, portal, Side::Front)
199 .into_iter()
200 .map(|val| Self::clip(back, nodes, val, Side::Back))
201 .flatten()
202 .collect()
203 }
204 (Side::Coplanar, Some(front), _) => Self::clip(front, nodes, portal, Side::Front),
205 (Side::Coplanar, _, Some(back)) => Self::clip(back, nodes, portal, Side::Back),
206 (Side::Front, Some(front), _) => Self::clip(front, nodes, portal, root_side),
207 (Side::Back, _, Some(back)) => Self::clip(back, nodes, portal, root_side),
208 (Side::Intersecting, _, _) => {
209 let [front, back] = portal.split(node.origin, node.normal);
210
211 assert!(front.normal.dot(portal.normal) > 0.0);
212 assert!(back.normal.dot(portal.normal) > 0.0);
213
214 let mut result = Self::clip(index, nodes, front, root_side);
215
216 result.append(&mut Self::clip(index, nodes, back, root_side));
217 result
218 }
219 _ => {
220 if root_side == Side::Back {
221 portal.dst = index;
222 } else {
223 portal.src = index;
224 }
225 vec![portal]
226 }
227 }
228 }
229
230 pub fn generate_portals(
231 index: NodeIndex,
232 nodes: &Nodes,
233 clipping_planes: &Vector<Face>,
234 result: &mut impl Extend<ClippedFace>,
235 ) {
236 let node = &nodes[index];
237 let dir = Vec2::new(node.normal.y, -node.normal.x);
238 let mut min = Intersect::new(Vec2::ZERO, f32::MAX);
239 let mut adjacent = [false, false];
240 let mut max = Intersect::new(Vec2::ZERO, f32::MAX);
241
242 clipping_planes.iter().for_each(|val| {
243 let intersect = face_intersect_dir(node.origin, dir, val.vertices[0], val.normal());
244 if !intersect.distance.is_finite() {
245 return;
246 }
247
248 let ad = val.contains_point(intersect.point);
249
250 if intersect.distance > 0.0 && intersect.distance < max.distance {
251 max = intersect;
252 adjacent[0] = ad;
253 }
254 if intersect.distance < 0.0 && intersect.distance.abs() < min.distance.abs() {
255 min = intersect;
256 adjacent[1] = ad;
257 }
258 });
259
260 let portal = ClippedFace::new(
261 [max.point, min.point],
262 [Side::Front, Side::Front],
263 adjacent,
264 index,
265 index,
266 );
267
268 result.extend(
269 Self::clip(index, nodes, portal, Side::Front)
270 .into_iter()
271 .filter(|val| {
272 val.src != val.dst
273 && val.sides == [Side::Front; 2]
274 && !node.faces.iter().any(|face| face.overlaps(val))
275 }),
276 );
277
278 let clipping_planes = node
281 .faces
282 .iter()
283 .fold(clipping_planes.clone(), |acc, val| acc.push_back(*val));
284
285 if let Some(child) = node.front {
289 Self::generate_portals(child, nodes, &clipping_planes, result);
290 }
291
292 if let Some(child) = node.back {
293 Self::generate_portals(child, nodes, &clipping_planes, result);
294 }
295 }
296
297 pub fn is_leaf(&self) -> bool {
298 self.front.is_none() && self.back.is_none()
299 }
300
301 pub fn faces(&self) -> &[Face] {
303 &self.faces
304 }
305}
306
307pub struct Descendants<'a> {
308 nodes: &'a Nodes,
309
310 stack: Vec<NodeIndex>,
311}
312
313impl<'a> Iterator for Descendants<'a> {
314 type Item = (NodeIndex, &'a BSPNode);
315
316 fn next(&mut self) -> Option<Self::Item> {
317 let index = self.stack.pop()?;
318
319 let node = &self.nodes[index];
320 if let Some(front) = node.front {
321 self.stack.push(front)
322 }
323 if let Some(back) = node.back {
324 self.stack.push(back)
325 }
326
327 Some((index, node))
328 }
329}