use crate::greedy::face_needs_mesh;
use crate::Voxel;
use super::MergeVoxel;
pub trait MergeStrategy {
type Voxel;
unsafe fn find_quad(
min_index: u32,
max_width: u32,
max_height: u32,
face_strides: &FaceStrides,
voxels: &[Self::Voxel],
visited: &[bool],
) -> (u32, u32)
where
Self::Voxel: Voxel;
}
pub struct FaceStrides {
pub n_stride: u32,
pub u_stride: u32,
pub v_stride: u32,
pub visibility_offset: u32,
}
pub struct VoxelMerger<T> {
marker: std::marker::PhantomData<T>,
}
impl<T> MergeStrategy for VoxelMerger<T>
where
T: MergeVoxel,
{
type Voxel = T;
unsafe fn find_quad(
min_index: u32,
max_width: u32,
max_height: u32,
face_strides: &FaceStrides,
voxels: &[T],
visited: &[bool],
) -> (u32, u32) {
let quad_value = voxels.get_unchecked(min_index as usize).merge_value();
let mut row_start_stride = min_index;
let quad_width = Self::get_row_width(
voxels,
visited,
&quad_value,
face_strides.visibility_offset,
row_start_stride,
face_strides.u_stride,
max_width,
);
row_start_stride += face_strides.v_stride;
let mut quad_height = 1;
while quad_height < max_height {
let row_width = Self::get_row_width(
voxels,
visited,
&quad_value,
face_strides.visibility_offset,
row_start_stride,
face_strides.u_stride,
quad_width,
);
if row_width < quad_width {
break;
}
quad_height += 1;
row_start_stride = row_start_stride.wrapping_add(face_strides.v_stride);
}
(quad_width, quad_height)
}
}
impl<T> VoxelMerger<T> {
unsafe fn get_row_width(
voxels: &[T],
visited: &[bool],
quad_merge_voxel_value: &T::MergeValue,
visibility_offset: u32,
start_stride: u32,
delta_stride: u32,
max_width: u32,
) -> u32
where
T: MergeVoxel,
{
let mut quad_width = 0;
let mut row_stride = start_stride;
while quad_width < max_width {
let voxel = voxels.get_unchecked(row_stride as usize);
if !face_needs_mesh(voxel, row_stride, visibility_offset, voxels, visited) {
break;
}
if !voxel.merge_value().eq(quad_merge_voxel_value) {
break;
}
quad_width += 1;
row_stride += delta_stride;
}
quad_width
}
}