use axiolid_core::Aabb;
use axiolid_mesh::{AttributeChannel, TriMesh};
pub(crate) fn fuse(meshes: &[&TriMesh]) -> TriMesh {
let vertices = meshes.iter().map(|m| m.positions.len()).sum();
let triangles = meshes.iter().map(|m| m.indices.len()).sum();
let mut positions = Vec::with_capacity(vertices);
let mut indices = Vec::with_capacity(triangles);
for mesh in meshes {
let offset = positions.len() as u32;
positions.extend_from_slice(&mesh.positions);
indices.extend(mesh.indices.iter().map(|&i| i + offset));
}
TriMesh::new(positions, indices)
}
pub(crate) fn fuse_with_channels(meshes: &[&TriMesh], template: &[AttributeChannel]) -> TriMesh {
let mut out = fuse(meshes);
for want in template {
let mut values = Vec::new();
let mut corners = Vec::with_capacity(out.indices.len());
for m in meshes {
let found = m
.attributes
.iter()
.find(|c| c.name == want.name && c.width == want.width && c.blend == want.blend);
for corner in 0..m.indices.len() {
match found.and_then(|c| c.at_corner(&m.indices, corner)) {
Some(v) => {
corners.push((values.len() / want.width) as u32);
values.extend_from_slice(v);
}
None => corners.push(AttributeChannel::UNMAPPED),
}
}
}
out.attributes.push(AttributeChannel::corner_indexed(
want.name.clone(),
values,
want.width,
want.blend,
corners,
));
}
out
}
pub(crate) fn disjoint_groups(bounds: &[Aabb]) -> Vec<Vec<usize>> {
let mut groups: Vec<Vec<usize>> = Vec::new();
let mut group_bounds: Vec<Vec<Aabb>> = Vec::new();
'tool: for (index, bound) in bounds.iter().enumerate() {
for (group, members) in group_bounds.iter_mut().enumerate() {
if members.iter().all(|existing| !existing.intersects(bound)) {
groups[group].push(index);
members.push(*bound);
continue 'tool;
}
}
groups.push(vec![index]);
group_bounds.push(vec![*bound]);
}
groups
}