use crate::geometry::Aabb;
use crate::scene::{Quat, Transform, Vec3};
pub(super) fn union_optional(current: Option<Aabb>, next: Aabb) -> Aabb {
match current {
Some(current) => union_aabb(current, next),
None => next,
}
}
pub(super) fn transform_aabb(bounds: Aabb, transform: Transform) -> Aabb {
let corners = [
Vec3::new(bounds.min.x, bounds.min.y, bounds.min.z),
Vec3::new(bounds.max.x, bounds.min.y, bounds.min.z),
Vec3::new(bounds.min.x, bounds.max.y, bounds.min.z),
Vec3::new(bounds.max.x, bounds.max.y, bounds.min.z),
Vec3::new(bounds.min.x, bounds.min.y, bounds.max.z),
Vec3::new(bounds.max.x, bounds.min.y, bounds.max.z),
Vec3::new(bounds.min.x, bounds.max.y, bounds.max.z),
Vec3::new(bounds.max.x, bounds.max.y, bounds.max.z),
];
let mut transformed = transform_point(corners[0], transform);
let mut result = Aabb::new(transformed, transformed);
for corner in &corners[1..] {
transformed = transform_point(*corner, transform);
result = union_aabb(result, Aabb::new(transformed, transformed));
}
result
}
fn union_aabb(left: Aabb, right: Aabb) -> Aabb {
Aabb::new(
Vec3::new(
left.min.x.min(right.min.x),
left.min.y.min(right.min.y),
left.min.z.min(right.min.z),
),
Vec3::new(
left.max.x.max(right.max.x),
left.max.y.max(right.max.y),
left.max.z.max(right.max.z),
),
)
}
fn transform_point(point: Vec3, transform: Transform) -> Vec3 {
let scaled = Vec3::new(
point.x * transform.scale.x,
point.y * transform.scale.y,
point.z * transform.scale.z,
);
add_vec3(
rotate_vec3(transform.rotation, scaled),
transform.translation,
)
}
fn rotate_vec3(rotation: Quat, vector: Vec3) -> Vec3 {
let length_squared = rotation.x * rotation.x
+ rotation.y * rotation.y
+ rotation.z * rotation.z
+ rotation.w * rotation.w;
if length_squared <= f32::EPSILON || !length_squared.is_finite() {
return vector;
}
let inverse_length = length_squared.sqrt().recip();
let qx = rotation.x * inverse_length;
let qy = rotation.y * inverse_length;
let qz = rotation.z * inverse_length;
let qw = rotation.w * inverse_length;
let tx = 2.0 * (qy * vector.z - qz * vector.y);
let ty = 2.0 * (qz * vector.x - qx * vector.z);
let tz = 2.0 * (qx * vector.y - qy * vector.x);
Vec3::new(
vector.x + qw * tx + (qy * tz - qz * ty),
vector.y + qw * ty + (qz * tx - qx * tz),
vector.z + qw * tz + (qx * ty - qy * tx),
)
}
fn add_vec3(left: Vec3, right: Vec3) -> Vec3 {
Vec3::new(left.x + right.x, left.y + right.y, left.z + right.z)
}