use std::num::NonZeroUsize;
use crate::util::Pixel;
pub(super) fn reduce_triangle<T: Pixel>(
dest: &mut [T],
src: &[T],
dest_pitch: NonZeroUsize,
src_pitch: NonZeroUsize,
dest_width: NonZeroUsize,
dest_height: NonZeroUsize,
) {
debug_assert!(src.len() >= src_pitch.get() * dest_height.get() * 2);
debug_assert!(dest.len() >= dest_pitch.get() * dest_height.get());
unsafe {
reduce_triangle_vertical(
dest,
src,
dest_pitch,
src_pitch,
dest_width.saturating_mul(NonZeroUsize::new_unchecked(2)),
dest_height,
);
reduce_triangle_horizontal_inplace(dest, dest_pitch, dest_width, dest_height);
}
}
unsafe fn reduce_triangle_vertical<T: Pixel>(
dest: &mut [T],
src: &[T],
dest_pitch: NonZeroUsize,
src_pitch: NonZeroUsize,
dest_width: NonZeroUsize,
dest_height: NonZeroUsize,
) {
let dest = dest.as_mut_ptr();
let src = src.as_ptr();
let width_usize = dest_width.get();
let height_usize = dest_height.get();
let src_pitch_usize = src_pitch.get();
let dest_pitch_usize = dest_pitch.get();
for x in 0..width_usize {
let a: u32 = (*src.add(x)).as_();
let b: u32 = (*src.add(x + src_pitch_usize)).as_();
*dest.add(x) = T::from_u32_or_max_value((a + b + 1) / 2);
}
for y in 1..height_usize {
let dest_offset = y * dest_pitch_usize;
let src_offset = y * 2 * src_pitch_usize;
for x in 0..width_usize {
let a: u32 = (*src.add(src_offset + x - src_pitch_usize)).as_(); let b: u32 = (*src.add(src_offset + x)).as_(); let c: u32 = (*src.add(src_offset + x + src_pitch_usize)).as_(); *dest.add(dest_offset + x) = T::from_u32_or_max_value((a + b * 2 + c + 2) / 4);
}
}
}
unsafe fn reduce_triangle_horizontal_inplace<T: Pixel>(
dest: &mut [T],
dest_pitch: NonZeroUsize,
width: NonZeroUsize,
height: NonZeroUsize,
) {
let mut dest = dest.as_mut_ptr();
for _y in 0..height.get() {
let x = 0;
let mut a: u32;
let mut b: u32 = (*dest.add(x * 2)).as_();
let mut c: u32 = (*dest.add(x * 2 + 1)).as_();
let src0 = (b + c + 1) / 2;
for x in 1..width.get() {
a = (*dest.add(x * 2 - 1)).as_();
b = (*dest.add(x * 2)).as_();
c = (*dest.add(x * 2 + 1)).as_();
*dest.add(x) = T::from_u32_or_max_value((a + b * 2 + c + 2) / 4);
}
*dest = T::from_u32_or_max_value(src0);
dest = dest.add(dest_pitch.get());
}
}