bsp_pathfinding/tree/
portals.rs

1use core::slice;
2use std::ops::Deref;
3
4use glam::Vec2;
5use slotmap::{secondary::Iter, SecondaryMap};
6use smallvec::SmallVec;
7
8use crate::{util::face_intersect, BSPTree, Face, NodeIndex, Portal, PortalRef, Side};
9
10#[derive(Copy, Debug, Clone, PartialEq)]
11#[doc(hidden)]
12pub struct ClippedFace {
13    face: Face,
14    // Used to determine if a face is completely inside
15    pub(crate) sides: [Side; 2],
16    pub(crate) adjacent: [bool; 2],
17
18    pub src: NodeIndex,
19    pub dst: NodeIndex,
20}
21
22impl ClippedFace {
23    pub fn new(
24        vertices: [Vec2; 2],
25        sides: [Side; 2],
26        adjacent: [bool; 2],
27        src: NodeIndex,
28        dst: NodeIndex,
29    ) -> Self {
30        Self {
31            face: Face::new(vertices),
32            sides,
33            adjacent,
34            src,
35            dst,
36        }
37    }
38
39    pub(crate) fn split(&self, p: Vec2, normal: Vec2) -> [Self; 2] {
40        let intersection = face_intersect(self.into_tuple(), p, normal);
41
42        // a is in front
43        [
44            Self::new(
45                [self.vertices[0], intersection.point],
46                [Side::Front, Side::Front],
47                [self.adjacent[0], false],
48                self.src,
49                self.dst,
50            ),
51            Self::new(
52                [intersection.point, self.vertices[1]],
53                [Side::Front, Side::Front],
54                [false, self.adjacent[1]],
55                self.src,
56                self.dst,
57            ),
58        ]
59    }
60
61    /// Get the portal's src.
62    pub fn src(&self) -> NodeIndex {
63        self.src
64    }
65
66    /// Get the portal's dst.
67    pub fn dst(&self) -> NodeIndex {
68        self.dst
69    }
70
71    /// Get the portal's sides.
72    pub fn sides(&self) -> [Side; 2] {
73        self.sides
74    }
75
76    /// Get the clipped face's face.
77    pub fn face(&self) -> Face {
78        self.face
79    }
80}
81
82impl Deref for ClippedFace {
83    type Target = Face;
84
85    fn deref(&self) -> &Self::Target {
86        &self.face
87    }
88}
89
90type NodePortals = SmallVec<[PortalRef; 4]>;
91
92/// Declares portals which are surfaces connecting two partitioning planes,
93/// [crate::BSPNode].
94#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
95pub struct Portals {
96    inner: SecondaryMap<NodeIndex, NodePortals>,
97    faces: Vec<Face>,
98}
99
100impl Portals {
101    pub fn new() -> Self {
102        Self {
103            inner: SecondaryMap::new(),
104            faces: Vec::new(),
105        }
106    }
107
108    pub fn generate(&mut self, tree: &BSPTree) {
109        self.extend(tree.generate_portals())
110    }
111
112    /// Adds a new portal for both src and dst
113    pub fn push(&mut self, portal: ClippedFace) {
114        let face = self.faces.len();
115        self.faces.push(portal.face);
116
117        assert_ne!(portal.src, portal.dst);
118
119        self.inner
120            .entry(portal.src)
121            .expect("Node was removed")
122            .or_default()
123            .push(PortalRef {
124                dst: portal.dst,
125                src: portal.src,
126                adjacent: portal.adjacent,
127                normal: -portal.normal(),
128                face,
129            });
130        self.inner
131            .entry(portal.dst)
132            .expect("Node was removed")
133            .or_default()
134            .push(PortalRef {
135                dst: portal.src,
136                src: portal.dst,
137                adjacent: portal.adjacent,
138                normal: portal.normal(),
139                face,
140            });
141    }
142
143    pub fn get(&self, index: NodeIndex) -> PortalIter {
144        PortalIter {
145            faces: &self.faces,
146            iter: self
147                .inner
148                .get(index)
149                .map(|val| val.as_ref())
150                .unwrap_or_default()
151                .iter(),
152        }
153    }
154
155    pub fn iter(&self) -> PortalsIter {
156        PortalsIter {
157            faces: &self.faces,
158            inner: self.inner.iter(),
159        }
160    }
161
162    pub fn from_ref(&self, portal: PortalRef) -> Portal {
163        Portal {
164            face: &self.faces[portal.face],
165            portal_ref: portal,
166        }
167    }
168}
169
170#[doc(hidden)]
171pub struct PortalIter<'a> {
172    faces: &'a [Face],
173    iter: slice::Iter<'a, PortalRef>,
174}
175
176impl<'a> Iterator for PortalIter<'a> {
177    type Item = Portal<'a>;
178
179    fn next(&mut self) -> Option<Self::Item> {
180        let portal = self.iter.next()?;
181
182        Some(Portal {
183            face: &self.faces[portal.face],
184            portal_ref: *portal,
185        })
186    }
187}
188
189impl<'a> IntoIterator for &'a Portals {
190    type Item = PortalIter<'a>;
191
192    type IntoIter = PortalsIter<'a>;
193
194    fn into_iter(self) -> Self::IntoIter {
195        self.iter()
196    }
197}
198
199#[doc(hidden)]
200pub struct PortalsIter<'a> {
201    faces: &'a [Face],
202    inner: Iter<'a, NodeIndex, NodePortals>,
203}
204
205impl<'a> Iterator for PortalsIter<'a> {
206    type Item = PortalIter<'a>;
207
208    fn next(&mut self) -> Option<Self::Item> {
209        let (_, portals) = self.inner.next()?;
210        Some(PortalIter {
211            faces: self.faces,
212            iter: portals.iter(),
213        })
214    }
215}
216
217impl Default for Portals {
218    fn default() -> Self {
219        Self::new()
220    }
221}
222
223impl Extend<ClippedFace> for Portals {
224    fn extend<T: IntoIterator<Item = ClippedFace>>(&mut self, iter: T) {
225        let iter = iter.into_iter();
226        let cap = self.inner.len() + iter.size_hint().0;
227
228        self.inner.set_capacity(cap);
229        iter.for_each(|val| self.push(val))
230    }
231}