use de_types::projection::ToFlat;
use glam::{IVec2, Vec2};
use parry3d::bounding_volume::Aabb;
use crate::TILE_SIZE;
pub(super) struct TileRange {
a: IVec2,
b: IVec2,
x: i32,
y: i32,
exhausted: bool,
}
impl TileRange {
pub(super) fn from_aabb(aabb: &Aabb) -> Self {
let aabb = aabb.to_flat();
let min_flat: Vec2 = aabb.mins.into();
let max_flat: Vec2 = aabb.maxs.into();
let start = (min_flat / TILE_SIZE).floor().as_ivec2();
let stop = (max_flat / TILE_SIZE).floor().as_ivec2();
Self::new(start, stop)
}
pub(super) fn new(a: IVec2, b: IVec2) -> Self {
Self {
a,
b,
x: a.x,
y: a.y,
exhausted: a.cmpgt(b).any(),
}
}
pub(super) fn excludes(&self, point: IVec2) -> bool {
self.a.cmpgt(point).any() || self.b.cmplt(point).any()
}
pub(super) fn intersection(&self, other: &TileRange) -> TileRange {
Self::new(self.a.max(other.a), self.b.min(other.b))
}
}
impl PartialEq for TileRange {
fn eq(&self, other: &Self) -> bool {
self.a == other.a && self.b == other.b
}
}
impl Eq for TileRange {}
impl Iterator for TileRange {
type Item = IVec2;
fn next(&mut self) -> Option<IVec2> {
if self.exhausted {
return None;
}
let next = Some(IVec2::new(self.x, self.y));
if self.x == self.b.x {
if self.y == self.b.y {
self.exhausted = true;
} else {
self.x = self.a.x;
self.y += 1;
}
} else {
self.x += 1;
}
next
}
}