use crate::core::instant;
use crate::scene::mesh::buffer::{
TriangleBufferRefMut, VertexAttributeDataType, VertexAttributeDescriptor, VertexAttributeUsage,
VertexBufferRefMut, VertexFetchError, VertexReadTrait, VertexWriteTrait,
};
use crate::{
core::{
algebra::Vector2,
math::{self, PlaneClass, TriangleDefinition, Vector2Ext},
rectpack::RectPacker,
visitor::{Visit, VisitResult, Visitor},
},
scene::mesh::surface::SurfaceData,
scene::mesh::Mesh,
};
use rayon::prelude::*;
#[derive(Debug)]
pub struct UvMesh {
triangles: Vec<usize>,
uv_max: Vector2<f32>,
uv_min: Vector2<f32>,
}
impl UvMesh {
fn new(first_triangle: usize) -> Self {
Self {
triangles: vec![first_triangle],
uv_max: Vector2::new(-f32::MAX, -f32::MAX),
uv_min: Vector2::new(f32::MAX, f32::MAX),
}
}
pub fn width(&self) -> f32 {
self.uv_max.x - self.uv_min.x
}
pub fn height(&self) -> f32 {
self.uv_max.y - self.uv_min.y
}
pub fn area(&self) -> f32 {
self.width() * self.height()
}
}
#[derive(Default, Debug)]
pub struct UvBox {
px: Vec<usize>,
nx: Vec<usize>,
py: Vec<usize>,
ny: Vec<usize>,
pz: Vec<usize>,
nz: Vec<usize>,
projections: Vec<[Vector2<f32>; 3]>,
}
fn face_vs_face(
vertex_buffer: &mut VertexBufferRefMut,
geometry_buffer_mut: &mut TriangleBufferRefMut,
face_triangles: &[usize],
other_face_triangles: &[usize],
patch: &mut SurfaceDataPatch,
) {
for other_triangle_index in other_face_triangles.iter() {
let other_triangle = geometry_buffer_mut[*other_triangle_index].clone();
for triangle_index in face_triangles.iter() {
'outer_loop: for vertex_index in geometry_buffer_mut[*triangle_index].indices_mut() {
for &other_vertex_index in other_triangle.indices() {
if *vertex_index == other_vertex_index {
patch.additional_vertices.push(other_vertex_index);
*vertex_index = vertex_buffer.vertex_count();
vertex_buffer.duplicate(other_vertex_index as usize);
continue 'outer_loop;
}
}
}
}
}
}
fn make_seam(
vertex_buffer: &mut VertexBufferRefMut,
geometry_buffer_mut: &mut TriangleBufferRefMut,
face_triangles: &[usize],
other_faces: &[&[usize]],
patch: &mut SurfaceDataPatch,
) {
for &other_face_triangles in other_faces.iter() {
face_vs_face(
vertex_buffer,
geometry_buffer_mut,
face_triangles,
other_face_triangles,
patch,
);
}
}
#[derive(Clone, Debug, Default)]
pub struct SurfaceDataPatch {
pub data_id: u64,
pub triangles: Vec<TriangleDefinition>,
pub second_tex_coords: Vec<Vector2<f32>>,
pub additional_vertices: Vec<u32>,
}
impl Visit for SurfaceDataPatch {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.data_id.visit("DataId", visitor)?;
self.triangles.visit("Triangles", visitor)?;
self.second_tex_coords.visit("SecondTexCoords", visitor)?;
self.additional_vertices
.visit("AdditionalVertices", visitor)?;
visitor.leave_region()
}
}
fn generate_uv_box(data: &SurfaceData) -> UvBox {
let mut uv_box = UvBox::default();
for (i, triangle) in data.geometry_buffer.iter().enumerate() {
let a = data
.vertex_buffer
.get(triangle[0] as usize)
.unwrap()
.read_3_f32(VertexAttributeUsage::Position)
.unwrap();
let b = data
.vertex_buffer
.get(triangle[1] as usize)
.unwrap()
.read_3_f32(VertexAttributeUsage::Position)
.unwrap();
let c = data
.vertex_buffer
.get(triangle[2] as usize)
.unwrap()
.read_3_f32(VertexAttributeUsage::Position)
.unwrap();
let normal = (b - a).cross(&(c - a));
let class = math::classify_plane(normal);
match class {
PlaneClass::XY => {
if normal.z < 0.0 {
uv_box.nz.push(i);
uv_box.projections.push([a.yx(), b.yx(), c.yx()])
} else {
uv_box.pz.push(i);
uv_box.projections.push([a.xy(), b.xy(), c.xy()]);
}
}
PlaneClass::XZ => {
if normal.y < 0.0 {
uv_box.ny.push(i);
uv_box.projections.push([a.xz(), b.xz(), c.xz()])
} else {
uv_box.py.push(i);
uv_box.projections.push([a.zx(), b.zx(), c.zx()])
}
}
PlaneClass::YZ => {
if normal.x < 0.0 {
uv_box.nx.push(i);
uv_box.projections.push([a.zy(), b.zy(), c.zy()])
} else {
uv_box.px.push(i);
uv_box.projections.push([a.yz(), b.yz(), c.yz()])
}
}
}
}
uv_box
}
pub fn generate_uv_meshes(
uv_box: &UvBox,
data_id: u64,
vertex_buffer_mut: &mut VertexBufferRefMut,
geometry_buffer_mut: &mut TriangleBufferRefMut,
) -> (Vec<UvMesh>, SurfaceDataPatch) {
let mut mesh_patch = SurfaceDataPatch {
data_id,
..Default::default()
};
if !vertex_buffer_mut.has_attribute(VertexAttributeUsage::TexCoord1) {
vertex_buffer_mut
.add_attribute(
VertexAttributeDescriptor {
usage: VertexAttributeUsage::TexCoord1,
data_type: VertexAttributeDataType::F32,
size: 2,
divisor: 0,
shader_location: 6, },
Vector2::<f32>::default(),
)
.unwrap();
}
make_seam(
vertex_buffer_mut,
geometry_buffer_mut,
&uv_box.px,
&[&uv_box.nx, &uv_box.py, &uv_box.ny, &uv_box.pz, &uv_box.nz],
&mut mesh_patch,
);
make_seam(
vertex_buffer_mut,
geometry_buffer_mut,
&uv_box.nx,
&[&uv_box.px, &uv_box.py, &uv_box.ny, &uv_box.pz, &uv_box.nz],
&mut mesh_patch,
);
make_seam(
vertex_buffer_mut,
geometry_buffer_mut,
&uv_box.py,
&[&uv_box.px, &uv_box.nx, &uv_box.ny, &uv_box.pz, &uv_box.nz],
&mut mesh_patch,
);
make_seam(
vertex_buffer_mut,
geometry_buffer_mut,
&uv_box.ny,
&[&uv_box.py, &uv_box.nx, &uv_box.px, &uv_box.pz, &uv_box.nz],
&mut mesh_patch,
);
make_seam(
vertex_buffer_mut,
geometry_buffer_mut,
&uv_box.pz,
&[&uv_box.nz, &uv_box.px, &uv_box.nx, &uv_box.py, &uv_box.ny],
&mut mesh_patch,
);
make_seam(
vertex_buffer_mut,
geometry_buffer_mut,
&uv_box.nz,
&[&uv_box.pz, &uv_box.px, &uv_box.nx, &uv_box.py, &uv_box.ny],
&mut mesh_patch,
);
let mut meshes = Vec::new();
let mut removed_triangles = vec![false; geometry_buffer_mut.len()];
for triangle_index in 0..geometry_buffer_mut.len() {
if !removed_triangles[triangle_index] {
let mut mesh = UvMesh::new(triangle_index);
removed_triangles[triangle_index] = true;
let mut last_triangle = 1;
let mut i = 0;
while i < last_triangle {
let triangle = &geometry_buffer_mut[mesh.triangles[i]];
for (other_triangle_index, other_triangle) in geometry_buffer_mut.iter().enumerate()
{
if !removed_triangles[other_triangle_index] {
'vertex_loop: for &vertex_index in triangle.indices() {
for &other_vertex_index in other_triangle.indices() {
if vertex_index == other_vertex_index {
mesh.triangles.push(other_triangle_index);
removed_triangles[other_triangle_index] = true;
last_triangle += 1;
break 'vertex_loop;
}
}
}
}
}
i += 1;
}
for &triangle_index in mesh.triangles.iter() {
let [a, b, c] = uv_box.projections[triangle_index];
mesh.uv_min = a
.per_component_min(&b)
.per_component_min(&c)
.per_component_min(&mesh.uv_min);
mesh.uv_max = a
.per_component_max(&b)
.per_component_max(&c)
.per_component_max(&mesh.uv_max);
}
meshes.push(mesh);
}
}
(meshes, mesh_patch)
}
pub fn generate_uvs(
data: &mut SurfaceData,
spacing: f32,
) -> Result<SurfaceDataPatch, VertexFetchError> {
let uv_box = generate_uv_box(data);
let data_id = data.content_hash();
let mut vertex_buffer_mut = data.vertex_buffer.modify();
let mut geometry_buffer_mut = data.geometry_buffer.modify();
let (mut meshes, mut patch) = generate_uv_meshes(
&uv_box,
data_id,
&mut vertex_buffer_mut,
&mut geometry_buffer_mut,
);
drop(geometry_buffer_mut);
let area = meshes.iter().fold(0.0, |area, mesh| area + mesh.area());
let square_side = area.sqrt() + spacing * meshes.len() as f32;
meshes.sort_unstable_by(|a, b| b.area().partial_cmp(&a.area()).unwrap());
let mut rects = Vec::new();
let twice_spacing = spacing * 2.0;
let mut empiric_scale = 1.1;
let mut scale = 1.0;
let mut packer = RectPacker::new(1.0, 1.0);
'try_loop: for _ in 0..100 {
rects.clear();
scale = 1.0 / (square_side * empiric_scale);
packer.clear();
for mesh in meshes.iter() {
if let Some(rect) = packer.find_free(
mesh.width() * scale + twice_spacing,
mesh.height() * scale + twice_spacing,
) {
rects.push(rect);
} else {
empiric_scale *= 1.33;
continue 'try_loop;
}
}
}
for (i, rect) in rects.into_iter().enumerate() {
let mesh = &meshes[i];
for &triangle_index in mesh.triangles.iter() {
for (&vertex_index, &projection) in data.geometry_buffer[triangle_index]
.indices()
.iter()
.zip(&uv_box.projections[triangle_index])
{
vertex_buffer_mut
.get_mut(vertex_index as usize)
.unwrap()
.write_2_f32(
VertexAttributeUsage::TexCoord1,
(projection - mesh.uv_min).scale(scale)
+ Vector2::new(spacing, spacing)
+ rect.position,
)?;
}
}
}
patch.triangles = data.geometry_buffer.triangles_ref().to_vec();
for view in vertex_buffer_mut.iter() {
patch
.second_tex_coords
.push(view.read_2_f32(VertexAttributeUsage::TexCoord1)?);
}
Ok(patch)
}
pub fn generate_uvs_mesh(
mesh: &Mesh,
spacing: f32,
) -> Result<Vec<SurfaceDataPatch>, VertexFetchError> {
let last = instant::Instant::now();
let data_set = mesh.surfaces().iter().map(|s| s.data()).collect::<Vec<_>>();
let patches = data_set
.into_par_iter()
.map(|data| generate_uvs(&mut data.lock(), spacing))
.collect::<Result<Vec<SurfaceDataPatch>, VertexFetchError>>()?;
println!("Generate UVs: {:?}", instant::Instant::now() - last);
Ok(patches)
}