use super::chunk_downsample_for_each;
use crate::{
ArrayForEach, ArrayIndexer, ChunkDownsampler, Get, GetMut, IndexedArray, Local, Stride,
};
use building_blocks_core::prelude::*;
pub struct SdfMeanDownsampler;
impl<N, Src, Dst, T> ChunkDownsampler<N, T, Src, Dst> for SdfMeanDownsampler
where
N: ArrayIndexer<N>,
PointN<N>: IntegerPoint<N>,
ArrayForEach<N>: Clone,
T: From<f32>,
f32: From<T>,
Src: Get<Stride, Item = T> + IndexedArray<N>,
Dst: for<'r> GetMut<'r, Stride, Item = &'r mut T> + IndexedArray<N>,
{
fn downsample(&self, src_chunk: &Src, dst_chunk: &mut Dst, dst_min: Local<N>, lod_delta: u8) {
let chunk_shape = src_chunk.extent().shape;
debug_assert!(lod_delta > 0);
let lod_delta = lod_delta as i32;
let lod_scale_factor = 1 << lod_delta;
let src_shape_per_point = PointN::fill(lod_scale_factor);
let kernel_for_each = ArrayForEach::new_local_unchecked(
chunk_shape,
Local(PointN::ZERO),
ExtentN::from_min_and_shape(PointN::ZERO, src_shape_per_point),
);
let rescale = 1.0 / (lod_scale_factor * src_shape_per_point.volume()) as f32;
let for_each = chunk_downsample_for_each(chunk_shape, dst_min, lod_delta);
N::for_each_lockstep_unchecked(for_each, |_p, (s_dst, s_src)| {
let mut sum = 0.0;
N::for_each(kernel_for_each.clone(), |_p, neighbor_offset| {
sum += f32::from(src_chunk.get(s_src + neighbor_offset));
});
*dst_chunk.get_mut(s_dst) = T::from(rescale * sum);
});
}
}