1use crate::node::{Node, NodeContent, NodeId};
5use crate::transform::Affine2D;
6
7#[allow(clippy::large_enum_variant)]
9enum Slot {
10 Occupied(Node),
11 Free { next_free: Option<u32> },
12}
13
14pub struct SceneGraph {
16 slots: Vec<Slot>,
17 generation: Vec<u32>,
18 free_head: Option<u32>,
19 root: Option<NodeId>,
20}
21
22impl SceneGraph {
23 pub fn new() -> Self {
25 Self {
26 slots: Vec::new(),
27 generation: Vec::new(),
28 free_head: None,
29 root: None,
30 }
31 }
32
33 pub fn with_root() -> Self {
35 let mut sg = Self::new();
36 let root = sg.insert(Node::container());
37 sg.root = Some(root);
38 sg
39 }
40
41 pub fn root(&self) -> Option<NodeId> {
43 self.root
44 }
45
46 pub fn set_root(&mut self, id: NodeId) {
48 self.root = Some(id);
49 }
50
51 pub fn insert(&mut self, node: Node) -> NodeId {
53 if let Some(idx) = self.free_head {
54 let i = idx as usize;
55 if let Slot::Free { next_free } = self.slots[i] {
56 self.free_head = next_free;
57 }
58 self.generation[i] += 1;
59 self.slots[i] = Slot::Occupied(node);
60 NodeId {
61 index: idx,
62 generation: self.generation[i],
63 }
64 } else {
65 let idx = self.slots.len() as u32;
66 self.slots.push(Slot::Occupied(node));
67 self.generation.push(0);
68 NodeId {
69 index: idx,
70 generation: 0,
71 }
72 }
73 }
74
75 pub fn remove(&mut self, id: NodeId) -> Option<Node> {
77 let i = id.index as usize;
78 if i >= self.slots.len() || self.generation[i] != id.generation {
79 return None;
80 }
81 if let Slot::Occupied(_) = &self.slots[i] {
82 let old = std::mem::replace(
83 &mut self.slots[i],
84 Slot::Free {
85 next_free: self.free_head,
86 },
87 );
88 self.free_head = Some(id.index);
89 match old {
90 Slot::Occupied(node) => Some(node),
91 Slot::Free { .. } => None,
92 }
93 } else {
94 None
95 }
96 }
97
98 pub fn get(&self, id: NodeId) -> Option<&Node> {
100 let i = id.index as usize;
101 if i >= self.slots.len() || self.generation[i] != id.generation {
102 return None;
103 }
104 match &self.slots[i] {
105 Slot::Occupied(node) => Some(node),
106 Slot::Free { .. } => None,
107 }
108 }
109
110 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut Node> {
112 let i = id.index as usize;
113 if i >= self.slots.len() || self.generation[i] != id.generation {
114 return None;
115 }
116 match &mut self.slots[i] {
117 Slot::Occupied(node) => Some(node),
118 Slot::Free { .. } => None,
119 }
120 }
121
122 pub fn add_child(&mut self, parent: NodeId, child: NodeId) {
124 if let Some(c) = self.get_mut(child) {
126 c.parent = Some(parent);
127 }
128 if let Some(p) = self.get_mut(parent) {
130 p.children.push(child);
131 }
132 }
133
134 pub fn insert_child(&mut self, parent: NodeId, node: Node) -> NodeId {
136 let id = self.insert(node);
137 self.add_child(parent, id);
138 id
139 }
140
141 pub fn len(&self) -> usize {
143 self.slots
144 .iter()
145 .filter(|s| matches!(s, Slot::Occupied(_)))
146 .count()
147 }
148
149 pub fn is_empty(&self) -> bool {
151 self.len() == 0
152 }
153
154 pub fn iter(&self) -> impl Iterator<Item = (NodeId, &Node)> {
156 self.slots
157 .iter()
158 .enumerate()
159 .filter_map(|(i, slot)| match slot {
160 Slot::Occupied(node) => Some((
161 NodeId {
162 index: i as u32,
163 generation: self.generation[i],
164 },
165 node,
166 )),
167 Slot::Free { .. } => None,
168 })
169 }
170
171 pub fn world_transform(&self, id: NodeId) -> Affine2D {
173 let mut chain = Vec::new();
174 let mut current = Some(id);
175 while let Some(cid) = current {
176 if let Some(node) = self.get(cid) {
177 chain.push(node.transform);
178 current = node.parent;
179 } else {
180 break;
181 }
182 }
183 let mut result = Affine2D::IDENTITY;
184 for t in chain.into_iter().rev() {
185 result = result.then(t);
186 }
187 result
188 }
189
190 pub fn collect_marks(&self) -> Vec<(NodeId, Affine2D)> {
192 let mut result = Vec::new();
193 if let Some(root) = self.root {
194 self.collect_marks_recursive(root, Affine2D::IDENTITY, &mut result);
195 }
196 result
197 }
198
199 fn collect_marks_recursive(
200 &self,
201 id: NodeId,
202 parent_transform: Affine2D,
203 result: &mut Vec<(NodeId, Affine2D)>,
204 ) {
205 let Some(node) = self.get(id) else { return };
206 let world = parent_transform.then(node.transform);
207
208 match &node.content {
209 NodeContent::Container => {}
210 NodeContent::Mark(_) | NodeContent::Batch(_) => {
211 result.push((id, world));
212 }
213 }
214
215 let mut indices: Vec<usize> = (0..node.children.len()).collect();
217 indices.sort_by_key(|&i| self.get(node.children[i]).map_or(0, |n| n.z_order));
218
219 for i in indices {
220 let child_id = self.get(id).map(|n| n.children[i]);
222 if let Some(cid) = child_id {
223 self.collect_marks_recursive(cid, world, result);
224 }
225 }
226 }
227}
228
229impl Default for SceneGraph {
230 fn default() -> Self {
231 Self::new()
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238 use crate::mark::Mark;
239 use crate::style::StrokeStyle;
240
241 #[test]
242 fn insert_and_get() {
243 let mut sg = SceneGraph::new();
244 let id = sg.insert(Node::container());
245 assert!(sg.get(id).is_some());
246 assert_eq!(sg.len(), 1);
247 }
248
249 #[test]
250 fn remove_and_reuse() {
251 let mut sg = SceneGraph::new();
252 let id1 = sg.insert(Node::container());
253 sg.remove(id1);
254 assert!(sg.get(id1).is_none());
255 assert_eq!(sg.len(), 0);
256
257 let id2 = sg.insert(Node::container());
259 assert_eq!(id2.index, id1.index);
260 assert_ne!(id2.generation, id1.generation);
261 }
262
263 #[test]
264 fn parent_child() {
265 let mut sg = SceneGraph::with_root();
266 let root = sg.root().unwrap();
267 let child = sg.insert_child(root, Node::container());
268
269 let root_node = sg.get(root).unwrap();
270 assert_eq!(root_node.children.len(), 1);
271 assert_eq!(root_node.children[0], child);
272
273 let child_node = sg.get(child).unwrap();
274 assert_eq!(child_node.parent, Some(root));
275 }
276
277 #[test]
278 fn collect_marks_ordering() {
279 let mut sg = SceneGraph::with_root();
280 let root = sg.root().unwrap();
281
282 let mut n1 = Node::with_mark(Mark::Rule(crate::mark::RuleMark {
283 segments: vec![],
284 stroke: StrokeStyle::default(),
285 }));
286 n1.z_order = 2;
287
288 let mut n2 = Node::with_mark(Mark::Rule(crate::mark::RuleMark {
289 segments: vec![],
290 stroke: StrokeStyle::default(),
291 }));
292 n2.z_order = 1;
293
294 sg.insert_child(root, n1);
295 sg.insert_child(root, n2);
296
297 let marks = sg.collect_marks();
298 assert_eq!(marks.len(), 2);
299 let first = sg.get(marks[0].0).unwrap();
301 let second = sg.get(marks[1].0).unwrap();
302 assert!(first.z_order <= second.z_order);
303 }
304}