use crate::pbs::*;
use crate::prelude::*;
use bevy::prelude::*;
use bevy::render::mesh::{Indices, MeshVertexAttribute, VertexAttributeValues};
use bevy::render::render_asset::RenderAssetUsages;
use bevy::render::render_resource::PrimitiveTopology;
#[derive(Debug, Clone, Copy)]
pub enum MeshingAlgorithm {
Naive,
Culling,
}
pub fn mesh_grid<T>(
dims: Dimensions,
outer_layer: &[Face],
grid: &[T],
reg: &impl VoxelRegistry<Voxel = T>,
meshing_algorithm: MeshingAlgorithm,
smooth_lighting_params: Option<SmoothLightingParameters>,
) -> Option<(Mesh, MeshMD<T>)> {
let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
);
let ch_len = grid.len();
let mut vivi = VIVI::new(ch_len);
assert_eq!(
ch_len,
dims.0 * dims.1 * dims.2,
"The product of the value of each of the dimensions must be the length of
the one dimentional grid array."
);
let [cull_top, cull_bottom, cull_right, cull_left, cull_back, cull_forward] = {
let mut r = [true, true, true, true, true, true];
for f in outer_layer {
r[*f as usize] = false;
}
r
};
let width = dims.0;
let length = dims.2;
let height = dims.1;
let t = width * length * height;
let mut rle_bool_voxel = RleVec::new();
let mut indices: Vec<u32> = vec![];
let mut vertices: Vec<(MeshVertexAttribute, VertexAttributeValues)> = vec![];
for att in reg.all_attributes().iter() {
vertices.push((att.clone(), VertexAttributeValues::new(att.format.clone())));
}
let voxel_dims = reg.get_voxel_dimensions();
let center = reg.get_center();
for k in 0..height {
for j in 0..length {
for i in 0..width {
let cord = k * length * width + j * width + i;
let above = cord + length * width;
let below = cord.checked_sub(width * length).unwrap_or(usize::MAX);
let right = cord + 1;
let left = cord.checked_sub(1).unwrap_or(usize::MAX);
let back = cord + width;
let forward = cord.checked_sub(width).unwrap_or(usize::MAX);
let mut neig = [false; 6];
let position_offset = (
i as f32 * voxel_dims[0],
k as f32 * voxel_dims[1],
j as f32 * voxel_dims[2],
);
if in_range(k + 1, 0, height) {
neig[0] = !reg.is_covering(&grid[above], Bottom);
} else {
neig[0] = cull_top;
}
if in_range(k, 1, t) {
neig[1] = !reg.is_covering(&grid[below], Top);
} else {
neig[1] = cull_bottom;
}
if in_range(i + 1, 0, width) {
neig[2] = !reg.is_covering(&grid[right], Left);
} else {
neig[2] = cull_right;
}
if in_range(i, 1, t) {
neig[3] = !reg.is_covering(&grid[left], Right);
} else {
neig[3] = cull_left;
}
if in_range(j + 1, 0, length) {
neig[4] = !reg.is_covering(&grid[back], Forward);
} else {
neig[4] = cull_back;
}
if in_range(j, 1, t) {
neig[5] = !reg.is_covering(&grid[forward], Back);
} else {
neig[5] = cull_forward;
}
match meshing_algorithm {
MeshingAlgorithm::Naive => neig = [true; 6],
MeshingAlgorithm::Culling => {}
}
if neig == [false, false, false, false, false, false] {
continue;
}
if in_range(cord, 0, t) {
if let VoxelMesh::NormalCube(v_mesh) = reg.get_mesh(&grid[cord]) {
add_vertices_normal_cube(
neig,
&mut indices,
&mut vertices,
v_mesh,
&mut vivi,
cord,
center,
position_offset,
);
rle_bool_voxel.push(true, 1);
} else {
rle_bool_voxel.push(false, 1);
}
}
}
}
}
for (att, vals) in vertices {
mesh.insert_attribute(att, vals);
}
mesh.insert_indices(Indices::U32(indices));
let d_mesh = MeshMD {
dims,
smooth_lighting_params,
vivi,
changed_voxels: vec![],
};
if let Some(t) = smooth_lighting_params {
if t.apply_at_gen {
apply_smooth_lighting(reg, &mut mesh, &d_mesh, dims, 0, ch_len, grid);
}
}
Some((mesh, d_mesh))
}
fn add_vertices_normal_cube(
neig: Neighbors,
indices_main: &mut Vec<u32>,
vertices: &mut Vec<(MeshVertexAttribute, VertexAttributeValues)>,
voxel: &Mesh,
vivi: &mut VIVI,
voxel_index: usize,
center: [f32; 3],
position_offset: (f32, f32, f32),
) {
let vertices_count = vertices[0].1.len();
let pos_attribute = voxel
.attribute(Mesh::ATTRIBUTE_POSITION)
.expect("couldn't get voxel mesh data");
let VertexAttributeValues::Float32x3(positions) = pos_attribute else {
panic!("Unexpected vertex format for position attribute, expected Float32x3.");
};
let Indices::U32(indices) = voxel.indices().expect("couldn't get indices data") else {
panic!("Expected U32 indices format");
};
let triangles = indices
.chunks(3)
.map(|chunk| (chunk[0], chunk[1], chunk[2]));
let mut indices_to_save: Vec<u32> = vec![];
let mut vertices_to_save: Vec<(bool, u32, Face)> = vec![(false, 0, Face::Top); positions.len()];
let mut sorted_vertices: Vec<Option<Vec<u32>>> = vec![None; 6];
let mut final_vertices: Vec<u32> = vec![];
for (a, b, c) in triangles {
let v1 = positions[a as usize];
let v2 = positions[b as usize];
let v3 = positions[c as usize];
let mut save = (false, Top);
for i in 0..3 {
if v1[i] == v2[i] && v2[i] == v3[i] && v1[i] == v3[i] {
match (i, center[i] > v1[i]) {
(0, true) if neig[3] => save = (true, Left),
(0, false) if neig[2] => save = (true, Right),
(1, true) if neig[1] => save = (true, Bottom),
(1, false) if neig[0] => save = (true, Top),
(2, true) if neig[5] => save = (true, Forward),
(2, false) if neig[4] => save = (true, Back),
_ => save = (false, Top),
}
break;
}
}
if save.0 {
let quad: usize = save.1.into();
indices_to_save.push(a);
indices_to_save.push(b);
indices_to_save.push(c);
match sorted_vertices[quad] {
None => {
sorted_vertices[quad] = Some(vec![a, b, c]);
vertices_to_save[a as usize].0 = true;
vertices_to_save[b as usize].0 = true;
vertices_to_save[c as usize].0 = true;
vertices_to_save[a as usize].1 = 0;
vertices_to_save[b as usize].1 = 1;
vertices_to_save[c as usize].1 = 2;
vertices_to_save[a as usize].2 = save.1;
vertices_to_save[b as usize].2 = save.1;
vertices_to_save[c as usize].2 = save.1;
}
Some(ref mut v) => {
for &i in [a, b, c].iter() {
if !vertices_to_save[i as usize].0 {
v.push(i);
vertices_to_save[i as usize].2 = save.1;
vertices_to_save[i as usize].1 = v.len() as u32 - 1;
vertices_to_save[i as usize].0 = true;
}
}
}
}
}
}
let mut offset: u32 = 0;
for q in sorted_vertices.iter() {
match q {
None => offset += 4,
Some(ref v) => {
let mut only_first = true;
for &i in v.iter() {
let face = vertices_to_save[i as usize].2;
vertices_to_save[i as usize].1 += face as u32 * 4 - offset;
final_vertices.push(i);
if only_first {
vivi.insert(face, voxel_index, i + vertices_count as u32 - offset);
only_first = false;
}
}
}
}
}
for i in indices_to_save.iter_mut() {
*i = vertices_to_save[*i as usize].1 + vertices_count as u32;
}
for (id, vals) in vertices.iter_mut() {
let mut att = voxel
.attribute(id.id)
.expect(format!("Couldn't retrieve voxel mesh attribute {:?}.", id).as_str())
.get_needed(&final_vertices);
if id.id == Mesh::ATTRIBUTE_POSITION.id {
att = att.offset_all(position_offset);
}
vals.extend(&att);
}
indices_main.extend(indices_to_save);
}