use std::fmt::Debug; use bevy_ecs::system::IntoSystem; use nalgebra::Vector3; use ndarray::ArrayView3; const LEAF_BIT: u32 = 1 << 31; const DATA_OFFSET: usize = 8; #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] pub struct OctNode(u32); impl OctNode { pub const fn new_node(addr: u32) -> Self { Self(addr) } pub const fn new_leaf(data: u32) -> Self { Self(data | LEAF_BIT) } pub const fn is_leaf(&self) -> bool { self.0 >= LEAF_BIT } pub fn is_node(&self) -> bool { self.0 < LEAF_BIT } pub fn node_data(&self) -> u32 { self.0 } pub fn leaf_data(&self) -> u32 { self.0 & !LEAF_BIT } } #[derive(Debug, Clone)] pub struct OctTree { data: Vec, levels: u32, side_length: usize, } const CORNERS: [Vector3; 8] = [ Vector3::new(0, 0, 0), Vector3::new(0, 0, 1), Vector3::new(0, 1, 0), Vector3::new(0, 1, 1), Vector3::new(1, 0, 0), Vector3::new(1, 0, 1), Vector3::new(1, 1, 0), Vector3::new(1, 1, 1), ]; impl OctTree { pub fn from_leaf(val: u32, levels: u32) -> Self { Self { data: vec![OctNode::new_leaf(val)], side_length: 2usize.pow(levels), levels, } } pub fn from_fn_rec(f: &mut impl FnMut(Vector3) -> u32, levels: u32) -> OctTree { Self::from_fn_offset(f, levels, Vector3::from_element(0)) } pub fn from_fn_offset( f: &mut impl FnMut(Vector3) -> u32, levels: u32, offset: Vector3, ) -> Self { let mut data = Vec::new(); data.push(OctNode::new_node(0)); Self::from_fn_offset_inner(f, &mut data, levels, offset); if data.len() == 2 { data.remove(0); } Self { data, side_length: 2usize.pow(levels), levels, } } fn from_fn_offset_inner( f: &mut impl FnMut(Vector3) -> u32, accumulator: &mut Vec, level: u32, offset: Vector3, ) { if level == 0 { accumulator.push(OctNode::new_leaf(f(offset))); return; } else if level == 1 { let leaves: [OctNode; 8] = core::array::from_fn(|i| OctNode::new_leaf(f(offset + CORNERS[i]))); if leaves[1..].iter().all(|l| *l == leaves[0]) { accumulator.push(leaves[0]); } else { accumulator.extend_from_slice(&leaves); } return; } let i = accumulator.len(); accumulator.resize(i + 8, OctNode::new_node(0)); let mut data_start = 0; for (j, corner_offset) in CORNERS.iter().enumerate() { let sub_start = accumulator.len(); Self::from_fn_offset_inner( f, accumulator, level - 1, offset + corner_offset * 2usize.pow(level - 1), ); let len = accumulator.len() - sub_start; if len == 1 { accumulator[i + j] = accumulator[sub_start]; accumulator.pop(); } else { accumulator[i + j] = OctNode::new_node(data_start as u32); data_start += len; } } if data_start == 0 { let first = accumulator[i]; if accumulator[i + 1..i + 8].iter().all(|l| *l == first) { accumulator.truncate(i); accumulator.push(first); } } } pub fn from_fn_iter( f: &mut impl FnMut(Vector3) -> u32, levels: u32, ) -> Self { let mut data = vec![OctNode::new_node(0)]; let mut level: usize = 1; let mut children = Vec::new(); let mut child = vec![0; levels as usize + 1]; let pows: Vec<_> = (0..levels).map(|l| 2usize.pow(l)).collect(); while level < levels as usize { if child[level] == 8 { let i = children.len() - 8; let first = children[i]; if children[i + 1..].iter().all(|l| *l == first) { children.truncate(i); children.push(first); } else { data.extend_from_slice(&children[i..]); children.truncate(i); children.push(OctNode::new_node(data.len() as u32 - 8)); } child[level] = 0; level += 1; child[level] += 1; } else if level == 1 { let offset: Vector3 = (level..8).map(|l| CORNERS[child[l]] * pows[l]).sum(); let leaves: [OctNode; 8] = core::array::from_fn(|i| OctNode::new_leaf(f(offset + CORNERS[i]))); if leaves[1..].iter().all(|l| *l == leaves[0]) { children.push(leaves[0]); } else { children.push(OctNode::new_node(data.len() as u32)); data.extend_from_slice(&leaves); } child[level] += 1; } else { level -= 1; } } data[0] = children[0]; Self { data, side_length: 2usize.pow(levels), levels, } } pub fn from_arr(arr: ArrayView3, levels: u32) -> Self { Self::from_fn_rec(&mut |p| arr[(p.x, p.y, p.z)], levels) } pub fn get(&self, mut pos: Vector3) -> u32 { let mut data_start = 1; let mut i = 0; let mut half_len = self.side_length / 2; while self.data[i].is_node() { let node_pos = data_start + self.data[i].node_data() as usize; let corner = pos / half_len; pos -= corner * half_len; half_len /= 2; let j = corner.x * 4 + corner.y * 2 + corner.z; i = node_pos + j; data_start = node_pos + DATA_OFFSET; } self.data[i].leaf_data() } pub fn raw(&self) -> &[OctNode] { &self.data } pub fn mesh(&self) {} } pub struct OctTreeIter<'a> { queue: Vec, levels: Vec, pos: usize, cur: u32, run: usize, data: &'a [OctNode], } impl<'a> Iterator for OctTreeIter<'a> { type Item = u32; fn next(&mut self) -> Option { if self.run != 0 { self.run -= 1; return Some(self.cur); } let node = self.queue.pop()?; let level = self.levels.pop()?; if node.is_leaf() { self.run = 8usize.pow(level); self.cur = node.leaf_data(); } else { let pos = 0; let add = &self.data[pos..pos + 8]; self.data = &self.data[pos + DATA_OFFSET..]; self.queue.extend(add.iter().rev()); self.levels.resize(self.levels.len() + 8, level - 1); } self.next() } } impl<'a> IntoIterator for &'a OctTree { type Item = u32; type IntoIter = OctTreeIter<'a>; fn into_iter(self) -> Self::IntoIter { OctTreeIter { data: &self.data[1..], pos: 0, cur: 0, levels: vec![self.levels], run: 0, queue: vec![self.data[0]], } } }