//! https://www.compuphase.com/riemer.htm use super::*; #[test] fn x() { let mut q = Ring::new([0.0, 2.0, 5.0]); dbg!(q.iter().collect::>()); assert_eq!(q.pop_front_push_back(6.0), 0.0); dbg!(q.iter().collect::>()); assert_eq!(q.pop_front_push_back(3.0), 2.0); dbg!(q.iter().collect::>()); assert_eq!(q.pop_front_push_back(4.0), 5.0); dbg!(q.iter().collect::>()); assert_eq!(q.pop_front_push_back(7.0), 6.0); dbg!(q.iter().collect::>()); } pub struct Ring { arr: [T; N], front: u8, } impl Ring { pub fn new(contents: [T; N]) -> Self { Ring { arr: contents, front: 0, } } pub fn pop_front_push_back(&mut self, push_back: T) -> T { unsafe { let e = std::mem::replace(self.arr.get_unchecked_mut(self.front as usize), push_back); self.front += 1; self.front %= N as u8; e } } pub fn iter(&self) -> impl Iterator { self.arr.iter().cycle().skip(self.front as _).take(N as _) } } pub fn riemerasma(image: Image<&[f32], 4>, palette: pal<'_, 4>) -> Image, 4> { let mut image = Image::build(image.width(), image.height()).buf(image.buffer().to_vec().into_boxed_slice()); #[rustfmt::skip] const WEIGH: [f32; 16] = [0.0625, 0.07518906, 0.09045432, 0.10881881, 0.13091174, 0.15749009, 0.18946451, 0.22793055, 0.27420613, 0.32987684, 0.39685008, 0.47742057, 0.57434887, 0.69095606, 0.8312374, 1.0]; let mut errors = Ring::<[f32; 4], 16>::new([[0.; 4]; 16]); let mut level = image.width().max(image.height()).ilog2(); if (1 << level) < image.width().max(image.height()) { level += 1; } // static mut visualization: Image<[u8; 256 * 256], 1> = fimg::make!(1 channels 256 x 256); // static mut stage: u8 = 0; enum Dir { UP, DOWN, LEFT, RIGHT, } use Dir::*; hl( level, UP, &mut (&mut (0, 0), &mut errors, &(), palette, &mut image), ); fn hl( level: u32, dir: Dir, p: &mut ( &mut (i32, i32), &mut Ring<[f32; 4], 16>, &(), pal<4>, &mut Image, 4>, ), ) { macro_rules! mv { ($dir: expr) => {{ unsafe { if p.0 .0 >= 0 && p.0 .0 < p.4.width() as i32 && p.0 .1 >= 0 && p.0 .1 < p.4.height() as i32 { let error = p.1.iter() .zip(WEIGH) .map(|(&a, b)| a.mul(b)) .fold([0.; 4], |acc, x| acc.aadd(x)) .div(WEIGH.len() as f32); let (x, y) = *p.0; let (x, y) = (x as u32, y as u32); // visualization.set_pixel(x, y, [stage]); // stage += 1; let px = p.4.pixel(x, y).aadd(error); let np = p.3.best(px); p.1.pop_front_push_back(px.asub(np)); *p.4.pixel_mut(x, y) = np; } match $dir { LEFT => p.0 .0 -= 1, RIGHT => p.0 .0 += 1, UP => p.0 .1 -= 1, DOWN => p.0 .1 += 1, } } }}; } macro_rules! dir { (^) => { UP }; (>) => { RIGHT }; (<) => { LEFT }; (v) => { DOWN }; } macro_rules! pattern { ($($x:tt)+) => {{ $(mv!(dir!($x));)+ }}; } macro_rules! hilbert { ($a1:tt $b1:tt $a2:tt $b2:tt $a3:tt $b3:tt $b4:tt) => {{ hl(level - 1, dir!($a1), p); mv!(dir!($b1)); hl(level - 1, dir!($a2), p); mv!(dir!($b2)); hl(level - 1, dir!($a3), p); mv!(dir!($b3)); hl(level - 1, dir!($b4), p); }}; } if level == 1 { match dir { LEFT => pattern!(>v<), RIGHT => pattern!(<^>), UP => pattern!(v>^), DOWN => pattern!(^ hilbert!(^> hilbert!(v< >^ > > ^), UP => hilbert!( ^^ >), DOWN => hilbert!(>^ v< v v <), } } } // unsafe { visualization.as_ref().show() }; image }