#![allow(clippy::unnecessary_cast)]
use crate::collision::CastOutput;
use crate::math_functions::{
abs, lerp, min_float, round_down_float, round_up_float, sub, Aabb, Pos, Vec2, VEC2_ZERO,
};
pub fn perimeter(a: Aabb) -> f32 {
let wx = a.upper_bound.x - a.lower_bound.x;
let wy = a.upper_bound.y - a.lower_bound.y;
2.0 * (wx + wy)
}
pub fn enlarge_aabb(a: &mut Aabb, b: Aabb) -> bool {
let mut changed = false;
if b.lower_bound.x < a.lower_bound.x {
a.lower_bound.x = b.lower_bound.x;
changed = true;
}
if b.lower_bound.y < a.lower_bound.y {
a.lower_bound.y = b.lower_bound.y;
changed = true;
}
if a.upper_bound.x < b.upper_bound.x {
a.upper_bound.x = b.upper_bound.x;
changed = true;
}
if a.upper_bound.y < b.upper_bound.y {
a.upper_bound.y = b.upper_bound.y;
changed = true;
}
changed
}
pub fn offset_aabb(box_: Aabb, origin: Pos) -> Aabb {
Aabb {
lower_bound: Vec2 {
x: round_down_float(origin.x as f64 + box_.lower_bound.x as f64),
y: round_down_float(origin.y as f64 + box_.lower_bound.y as f64),
},
upper_bound: Vec2 {
x: round_up_float(origin.x as f64 + box_.upper_bound.x as f64),
y: round_up_float(origin.y as f64 + box_.upper_bound.y as f64),
},
}
}
pub fn aabb_ray_cast(a: Aabb, p1: Vec2, p2: Vec2) -> CastOutput {
let mut output = CastOutput::default();
let mut t_min = -f32::MAX;
let mut t_max = f32::MAX;
let p = p1;
let d = sub(p2, p1);
let abs_d = abs(d);
let mut normal = VEC2_ZERO;
if abs_d.x < f32::EPSILON {
if p.x < a.lower_bound.x || a.upper_bound.x < p.x {
return output;
}
} else {
let inv_d = 1.0 / d.x;
let mut t1 = (a.lower_bound.x - p.x) * inv_d;
let mut t2 = (a.upper_bound.x - p.x) * inv_d;
let mut s = -1.0;
if t1 > t2 {
core::mem::swap(&mut t1, &mut t2);
s = 1.0;
}
if t1 > t_min {
normal.y = 0.0;
normal.x = s;
t_min = t1;
}
t_max = min_float(t_max, t2);
if t_min > t_max {
return output;
}
}
if abs_d.y < f32::EPSILON {
if p.y < a.lower_bound.y || a.upper_bound.y < p.y {
return output;
}
} else {
let inv_d = 1.0 / d.y;
let mut t1 = (a.lower_bound.y - p.y) * inv_d;
let mut t2 = (a.upper_bound.y - p.y) * inv_d;
let mut s = -1.0;
if t1 > t2 {
core::mem::swap(&mut t1, &mut t2);
s = 1.0;
}
if t1 > t_min {
normal.x = 0.0;
normal.y = s;
t_min = t1;
}
t_max = min_float(t_max, t2);
if t_min > t_max {
return output;
}
}
if t_min < 0.0 {
return output;
}
if 1.0 < t_min {
return output;
}
output.fraction = t_min;
output.normal = normal;
output.point = lerp(p1, p2, t_min);
output.hit = true;
output
}