#[derive(Clone, Debug, Default)]
pub struct LayoutGraph {
pub nodes: Vec<freecs::Entity>,
pub node_index: std::collections::HashMap<freecs::Entity, u32>,
pub parents: Vec<i32>,
pub depths: Vec<u32>,
pub child_offsets: Vec<u32>,
pub child_counts: Vec<u32>,
pub flat_children: Vec<u32>,
pub max_depth: u32,
pub valid: bool,
}
impl LayoutGraph {
pub fn clear(&mut self) {
self.nodes.clear();
self.node_index.clear();
self.parents.clear();
self.depths.clear();
self.child_offsets.clear();
self.child_counts.clear();
self.flat_children.clear();
self.max_depth = 0;
self.valid = false;
}
pub fn rebuild(
&mut self,
roots: &[freecs::Entity],
children_of: impl Fn(freecs::Entity) -> Option<Vec<freecs::Entity>>,
) {
self.clear();
let mut stack: Vec<(freecs::Entity, i32, u32)> = Vec::new();
for &root in roots.iter().rev() {
stack.push((root, -1, 0));
}
while let Some((entity, parent, depth)) = stack.pop() {
let node_idx = self.nodes.len() as u32;
self.nodes.push(entity);
self.node_index.insert(entity, node_idx);
self.parents.push(parent);
self.depths.push(depth);
self.max_depth = self.max_depth.max(depth);
let children = children_of(entity).unwrap_or_default();
for &child in children.iter().rev() {
stack.push((child, node_idx as i32, depth + 1));
}
}
self.child_offsets.resize(self.nodes.len(), 0);
self.child_counts.resize(self.nodes.len(), 0);
let mut counts: Vec<u32> = vec![0; self.nodes.len()];
for &parent in &self.parents {
if parent >= 0 {
counts[parent as usize] += 1;
}
}
let mut offset = 0u32;
for (index, count) in counts.iter().enumerate() {
self.child_offsets[index] = offset;
self.child_counts[index] = *count;
offset += count;
}
self.flat_children.resize(offset as usize, 0);
let mut writes: Vec<u32> = vec![0; self.nodes.len()];
for (child_idx, &parent) in self.parents.iter().enumerate() {
if parent >= 0 {
let parent_idx = parent as usize;
let slot = self.child_offsets[parent_idx] + writes[parent_idx];
self.flat_children[slot as usize] = child_idx as u32;
writes[parent_idx] += 1;
}
}
self.valid = true;
}
pub fn children_of(&self, node_index: u32) -> &[u32] {
let start = self.child_offsets[node_index as usize] as usize;
let count = self.child_counts[node_index as usize] as usize;
&self.flat_children[start..start + count]
}
pub fn parent_of(&self, node_index: u32) -> Option<u32> {
let parent = self.parents[node_index as usize];
if parent < 0 {
None
} else {
Some(parent as u32)
}
}
pub fn entities_at_depth(&self, depth: u32) -> Vec<u32> {
self.depths
.iter()
.enumerate()
.filter_map(|(idx, d)| if *d == depth { Some(idx as u32) } else { None })
.collect()
}
}