mod insert;
mod query;
mod rebuild;
mod validate;
use crate::core::NULL_INDEX;
use crate::math_functions::{Aabb, Vec2, VEC2_ZERO};
pub const DEFAULT_CATEGORY_BITS: u64 = 1;
pub const DEFAULT_MASK_BITS: u64 = u64::MAX;
pub(crate) const TREE_STACK_SIZE: usize = 1024;
pub(crate) const ALLOCATED_NODE: u16 = 0x0001;
pub(crate) const ENLARGED_NODE: u16 = 0x0002;
pub(crate) const LEAF_NODE: u16 = 0x0004;
#[derive(Debug, Clone, Copy)]
pub struct TreeNode {
pub aabb: Aabb,
pub category_bits: u64,
pub child1: i32,
pub child2: i32,
pub user_data: u64,
pub parent: i32,
pub next: i32,
pub height: u16,
pub flags: u16,
}
impl TreeNode {
pub(crate) fn default_node() -> TreeNode {
TreeNode {
aabb: Aabb {
lower_bound: VEC2_ZERO,
upper_bound: VEC2_ZERO,
},
category_bits: DEFAULT_CATEGORY_BITS,
child1: NULL_INDEX,
child2: NULL_INDEX,
user_data: u64::MAX,
parent: NULL_INDEX,
next: NULL_INDEX,
height: 0,
flags: ALLOCATED_NODE,
}
}
fn zeroed() -> TreeNode {
TreeNode {
aabb: Aabb {
lower_bound: VEC2_ZERO,
upper_bound: VEC2_ZERO,
},
category_bits: 0,
child1: 0,
child2: 0,
user_data: 0,
parent: 0,
next: 0,
height: 0,
flags: 0,
}
}
pub(crate) fn is_leaf(&self) -> bool {
self.flags & LEAF_NODE != 0
}
pub(crate) fn is_allocated(&self) -> bool {
self.flags & ALLOCATED_NODE != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct TreeStats {
pub node_visits: i32,
pub leaf_visits: i32,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct BoxCastInput {
pub box_: Aabb,
pub translation: Vec2,
pub max_fraction: f32,
}
#[derive(Debug, Clone, Default)]
pub struct DynamicTree {
pub(crate) nodes: Vec<TreeNode>,
pub(crate) root: i32,
pub(crate) node_count: i32,
pub(crate) free_list: i32,
pub(crate) proxy_count: i32,
pub(crate) leaf_indices: Vec<i32>,
pub(crate) leaf_centers: Vec<Vec2>,
pub(crate) rebuild_capacity: i32,
}
impl DynamicTree {
pub fn new(proxy_capacity: i32) -> DynamicTree {
let capacity = crate::math_functions::max_int(proxy_capacity, 16);
let node_capacity = (2 * capacity - 1) as usize;
let mut nodes = vec![TreeNode::zeroed(); node_capacity];
for (i, node) in nodes.iter_mut().enumerate().take(node_capacity - 1) {
node.next = i as i32 + 1;
}
nodes[node_capacity - 1].next = NULL_INDEX;
DynamicTree {
nodes,
root: NULL_INDEX,
node_count: 0,
free_list: 0,
proxy_count: 0,
leaf_indices: Vec::new(),
leaf_centers: Vec::new(),
rebuild_capacity: 0,
}
}
pub fn destroy(&mut self) {
*self = DynamicTree {
nodes: Vec::new(),
root: 0,
node_count: 0,
free_list: 0,
proxy_count: 0,
leaf_indices: Vec::new(),
leaf_centers: Vec::new(),
rebuild_capacity: 0,
};
}
pub(crate) fn node_capacity(&self) -> i32 {
self.nodes.len() as i32
}
pub fn node_count(&self) -> i32 {
self.node_count
}
pub(crate) fn allocate_node(&mut self) -> i32 {
if self.free_list == NULL_INDEX {
debug_assert!(self.node_count == self.node_capacity());
let old_capacity = self.nodes.len();
let new_capacity = old_capacity + (old_capacity >> 1);
self.nodes.resize(new_capacity, TreeNode::zeroed());
for i in self.node_count as usize..new_capacity - 1 {
self.nodes[i].next = i as i32 + 1;
}
self.nodes[new_capacity - 1].next = NULL_INDEX;
self.free_list = self.node_count;
}
let node_index = self.free_list;
self.free_list = self.nodes[node_index as usize].next;
self.nodes[node_index as usize] = TreeNode::default_node();
self.node_count += 1;
node_index
}
pub(crate) fn free_node(&mut self, node_id: i32) {
debug_assert!(0 <= node_id && node_id < self.node_capacity());
debug_assert!(0 < self.node_count);
self.nodes[node_id as usize].next = self.free_list;
self.nodes[node_id as usize].flags = 0;
self.free_list = node_id;
self.node_count -= 1;
}
pub fn proxy_count(&self) -> i32 {
self.proxy_count
}
pub fn category_bits(&self, proxy_id: i32) -> u64 {
debug_assert!(0 <= proxy_id && proxy_id < self.node_capacity());
self.nodes[proxy_id as usize].category_bits
}
pub fn height(&self) -> i32 {
if self.root == NULL_INDEX {
return 0;
}
self.nodes[self.root as usize].height as i32
}
pub fn area_ratio(&self) -> f32 {
use crate::aabb::perimeter;
if self.root == NULL_INDEX {
return 0.0;
}
let root = &self.nodes[self.root as usize];
let root_area = perimeter(root.aabb);
let mut total_area = 0.0;
for (i, node) in self.nodes.iter().enumerate() {
if !node.is_allocated() || node.is_leaf() || i as i32 == self.root {
continue;
}
total_area += perimeter(node.aabb);
}
total_area / root_area
}
pub fn root_bounds(&self) -> Aabb {
if self.root != NULL_INDEX {
return self.nodes[self.root as usize].aabb;
}
Aabb {
lower_bound: VEC2_ZERO,
upper_bound: VEC2_ZERO,
}
}
pub fn byte_count(&self) -> i32 {
let size = core::mem::size_of::<DynamicTree>()
+ core::mem::size_of::<TreeNode>() * self.nodes.len()
+ self.rebuild_capacity as usize
* (core::mem::size_of::<i32>()
+ core::mem::size_of::<Aabb>()
+ core::mem::size_of::<Vec2>()
+ core::mem::size_of::<i32>());
size as i32
}
pub fn user_data(&self, proxy_id: i32) -> u64 {
debug_assert!(0 <= proxy_id && proxy_id < self.node_capacity());
self.nodes[proxy_id as usize].user_data
}
pub fn aabb(&self, proxy_id: i32) -> Aabb {
debug_assert!(0 <= proxy_id && proxy_id < self.node_capacity());
self.nodes[proxy_id as usize].aabb
}
}