use crate::ecs::bounding_volume::components::{BoundingVolume, OrientedBoundingBox};
use crate::ecs::cloth::components::Cloth;
use crate::ecs::mesh::components::{Mesh, Vertex};
use crate::ecs::prefab::resources::mesh_cache_insert;
use crate::ecs::world::{CLOTH, RENDER_MESH, World};
use nalgebra_glm::{Quat, Vec3};
pub fn sync_cloth_meshes_system(world: &mut World) {
let mut changed: Vec<(freecs::Entity, Cloth, String)> = Vec::new();
let mut seen: Vec<freecs::Entity> = Vec::new();
world
.core
.query()
.with(CLOTH | RENDER_MESH)
.iter(|entity, table, index| {
seen.push(entity);
let cloth = &table.cloth[index];
let snapshot = world.resources.cloth_sync.snapshots.get(&entity);
if snapshot != Some(cloth) {
changed.push((entity, cloth.clone(), table.render_mesh[index].name.clone()));
}
});
world
.resources
.cloth_sync
.snapshots
.retain(|entity, _| seen.contains(entity));
for (entity, cloth, mesh_name) in changed {
let mesh = build_cloth_mesh(&cloth);
mesh_cache_insert(&mut world.resources.assets.mesh_cache, mesh_name, mesh);
world
.core
.set_bounding_volume(entity, cloth_bounding_volume(&cloth));
world.resources.cloth_sync.snapshots.insert(entity, cloth);
}
}
pub fn build_cloth_mesh(cloth: &Cloth) -> Mesh {
let columns = cloth.columns.max(2);
let rows = cloth.rows.max(2);
let spacing_x = cloth.width / (columns - 1) as f32;
let spacing_y = cloth.height / (rows - 1) as f32;
let mut vertices = Vec::with_capacity((columns * rows) as usize);
for row in 0..rows {
for column in 0..columns {
vertices.push(Vertex {
position: [
-cloth.width / 2.0 + column as f32 * spacing_x,
-(row as f32 * spacing_y),
0.0,
],
normal: [0.0, 0.0, 1.0],
tex_coords: [
column as f32 / (columns - 1) as f32 * cloth.texture_tiling.x,
row as f32 / (rows - 1) as f32 * cloth.texture_tiling.y,
],
tex_coords_1: [0.0, 0.0],
tangent: [1.0, 0.0, 0.0, 1.0],
color: [1.0, 1.0, 1.0, 1.0],
});
}
}
let mut indices = Vec::with_capacity(((columns - 1) * (rows - 1) * 6) as usize);
for row in 0..rows - 1 {
for column in 0..columns - 1 {
let top_left = row * columns + column;
let top_right = top_left + 1;
let bottom_left = top_left + columns;
let bottom_right = bottom_left + 1;
indices.extend_from_slice(&[
top_left,
bottom_left,
top_right,
top_right,
bottom_left,
bottom_right,
]);
}
}
Mesh {
vertices,
indices,
bounding_volume: Some(cloth_bounding_volume(cloth)),
skin_data: None,
morph_targets: None,
}
}
pub fn cloth_bounding_volume(cloth: &Cloth) -> BoundingVolume {
let half_extents = Vec3::new(
cloth.width / 2.0 + cloth.height * 0.5,
cloth.height / 2.0 + cloth.height * 0.1,
cloth.height * 0.6,
);
BoundingVolume {
obb: OrientedBoundingBox {
center: Vec3::new(0.0, -cloth.height / 2.0, 0.0),
half_extents,
orientation: Quat::identity(),
},
sphere_radius: nalgebra_glm::length(&half_extents),
}
}