use super::PosNormMesh;
use building_blocks_core::prelude::*;
use building_blocks_storage::{access::GetUncheckedRelease, prelude::*};
pub trait Height {
fn height(&self) -> f32;
}
impl Height for f32 {
fn height(&self) -> f32 {
*self
}
}
pub fn padded_height_map_chunk_extent(chunk_extent: &Extent2i) -> Extent2i {
chunk_extent.padded(1).add_to_shape(PointN([1; 2]))
}
#[derive(Default)]
pub struct HeightMapMeshBuffer {
pub mesh: PosNormMesh,
stride_to_index: Vec<u32>,
}
impl HeightMapMeshBuffer {
pub fn reset(&mut self, array_size: usize) {
self.mesh.clear();
self.stride_to_index.resize(array_size, 0);
}
}
pub fn triangulate_height_map<V, H>(
height_map: &V,
extent: &Extent2i,
output: &mut HeightMapMeshBuffer,
) where
V: Array<[i32; 2]>
+ GetUncheckedRelease<Stride, H>
+ ForEach<[i32; 2], (Point2i, Stride), Data = H>,
H: Height,
{
output.reset(height_map.extent().num_points());
let interior_extent = extent.padded(-1);
let deltas: Vec<_> = Local::localize_points(&Point2i::basis());
let mut delta_strides = [Stride(0); 2];
height_map.strides_from_local_points(&deltas, &mut delta_strides);
height_map.for_each(
&interior_extent,
|(p, stride): (Point2i, Stride), height| {
let pz = p.y();
let y = height.height();
output.stride_to_index[stride.0] = output.mesh.positions.len() as u32;
output.mesh.positions.push([p.x() as f32, y, pz as f32]);
let l_stride = stride - delta_strides[0];
let r_stride = stride + delta_strides[0];
let b_stride = stride - delta_strides[1];
let t_stride = stride + delta_strides[1];
let l_y = height_map.get_unchecked_release(l_stride).height();
let r_y = height_map.get_unchecked_release(r_stride).height();
let b_y = height_map.get_unchecked_release(b_stride).height();
let t_y = height_map.get_unchecked_release(t_stride).height();
let dy_dx = (r_y - l_y) / 2.0;
let dy_dz = (t_y - b_y) / 2.0;
output.mesh.normals.push([-dy_dx, 1.0, -dy_dz]);
},
);
let quads_extent = interior_extent.add_to_shape(PointN([-1; 2]));
height_map.for_each_point_and_stride(&quads_extent, |_p, bl_stride| {
let br_stride = bl_stride + delta_strides[0];
let tl_stride = bl_stride + delta_strides[1];
let tr_stride = bl_stride + delta_strides[0] + delta_strides[1];
let bl_index = output.stride_to_index[bl_stride.0];
let br_index = output.stride_to_index[br_stride.0];
let tl_index = output.stride_to_index[tl_stride.0];
let tr_index = output.stride_to_index[tr_stride.0];
output
.mesh
.indices
.extend_from_slice(&[bl_index, tl_index, tr_index, bl_index, tr_index, br_index]);
});
}