use glam::Vec3A;
use crate::{aabb::Aabb, triangle::Triangle};
pub fn split_aabbs_preset(
aabbs: &mut Vec<Aabb>,
indices: &mut Vec<u32>,
triangles: &[Triangle],
avg_half_area: f32,
largest_half_area: f32,
) {
split_aabbs_precise(
aabbs,
indices,
triangles,
avg_half_area * 3.0,
(avg_half_area * 4.0).max(avg_half_area * 0.9 + largest_half_area * 0.1),
1.8,
1.6,
12,
12,
);
}
#[allow(clippy::too_many_arguments)]
pub fn split_aabbs_precise(
aabbs: &mut Vec<Aabb>,
indices: &mut Vec<u32>,
triangles: &[Triangle],
area_thresh_low: f32,
area_thresh_high: f32,
split_factor_low: f32,
split_factor_high: f32,
max_iterations: u32,
split_tests: u32,
) {
crate::scope!("split_aabbs_precise");
let mut candidates = Vec::new();
for (i, aabb) in aabbs.iter().enumerate() {
if aabb.half_area() > area_thresh_low {
candidates.push(i)
}
}
let mut old_candidates_len = candidates.len();
for _ in 0..max_iterations {
for i in 0..candidates.len() {
let aabb = &mut aabbs[candidates[i]];
let index = indices[candidates[i]];
let axis: usize = aabb.largest_axis();
let tri = triangles[index as usize];
let mut best_cost = f32::MAX;
let mut left = *aabb;
let mut right = *aabb;
for i in 1..split_tests {
let n = i as f32 / split_tests as f32;
let pos = aabb.min[axis] * n + aabb.max[axis] * (1.0 - n);
let mut tmp_left = *aabb;
let mut tmp_right = *aabb;
tmp_left.max[axis] = pos;
tmp_right.min[axis] = pos;
let verts = [tri.v0, tri.v1, tri.v2, tri.v0];
let (t_left, t_right) = split_triangle(axis as u32, pos, verts);
tmp_left = t_left.intersection(&tmp_left);
tmp_right = t_right.intersection(&tmp_right);
let area = tmp_left.half_area() + tmp_right.half_area();
if area < best_cost {
best_cost = area;
left = tmp_left;
right = tmp_right;
}
}
let old_cost = aabb.half_area();
if (area_thresh_high > old_cost && best_cost * split_factor_high < old_cost)
|| best_cost * split_factor_low < old_cost
{
*aabb = left;
candidates.push(aabbs.len());
aabbs.push(right);
indices.push(index);
}
}
if old_candidates_len == candidates.len() {
break;
} else {
candidates.retain(|c| aabbs[*c].half_area() > area_thresh_low);
old_candidates_len = candidates.len();
}
}
}
pub fn split_triangle(dim: u32, pos: f32, v: [Vec3A; 4]) -> (Aabb, Aabb) {
let mut left = Aabb::INVALID;
let mut right = Aabb::INVALID;
for i in 0..3 {
let v0 = v[i];
let v1 = v[i + 1];
let v0d = v0[dim as usize];
let v1d = v1[dim as usize];
if v0d <= pos {
left.extend(v0);
}
if v0d >= pos {
right.extend(v0);
}
if (v0d < pos && pos < v1d) || (v1d < pos && pos < v0d) {
debug_assert!((v1d - v0d) != 0.0);
let inv_length = 1.0 / (v1d - v0d);
let c = Vec3A::mul_add(Vec3A::splat((pos - v0d) * inv_length), v1 - v0, v0);
left.extend(c);
right.extend(c);
}
}
(left, right)
}