use crate::{
pixel::{blend_64w, dia, diff, is_equal, left2, up2},
Block,
};
struct Kernel {
a1: u32, b1: u32, c1: u32, a0: u32, a: u32, b: u32, c: u32, c4: u32, d0: u32, d: u32, e: u32, f: u32, f4: u32, g0: u32, g: u32, h: u32, i: u32, i4: u32, g5: u32, h5: u32, i5: u32, }
struct KernelSection {
e: u32,
i: u32,
h: u32,
f: u32,
g: u32,
c: u32,
d: u32,
b: u32,
f4: u32,
i4: u32,
h5: u32,
i5: u32,
}
impl Kernel {
fn new(colors: &[u32], width: u32, height: u32, x: u32, y: u32) -> Self {
let width = width as i32;
let height = height as i32;
let x = x as i32;
let y = y as i32;
let pixel_at = |x: i32, y: i32| {
if x < 0 || x >= width || y < 0 || y >= height {
0
} else {
colors[(width * y + x) as usize]
}
};
Kernel {
a1: pixel_at(x - 1, y - 2),
b1: pixel_at(x, y - 2),
c1: pixel_at(x + 1, y - 2),
a0: pixel_at(x - 2, y - 1),
a: pixel_at(x - 1, y - 1),
b: pixel_at(x, y - 1),
c: pixel_at(x + 1, y - 1),
c4: pixel_at(x + 2, y - 1),
d0: pixel_at(x - 2, y),
d: pixel_at(x - 1, y),
e: pixel_at(x, y),
f: pixel_at(x + 1, y),
f4: pixel_at(x + 2, y),
g0: pixel_at(x - 2, y + 1),
g: pixel_at(x - 1, y + 1),
h: pixel_at(x, y + 1),
i: pixel_at(x + 1, y + 1),
i4: pixel_at(x + 2, y + 1),
g5: pixel_at(x - 1, y + 2),
h5: pixel_at(x, y + 2),
i5: pixel_at(x + 1, y + 2),
}
}
fn down_right(&self) -> KernelSection {
KernelSection {
e: self.e,
i: self.i,
h: self.h,
f: self.f,
g: self.g,
c: self.c,
d: self.d,
b: self.b,
f4: self.f4,
i4: self.i4,
h5: self.h5,
i5: self.i5,
}
}
fn up_right(&self) -> KernelSection {
KernelSection {
e: self.e,
i: self.c,
h: self.f,
f: self.b,
g: self.i,
c: self.a,
d: self.h,
b: self.d,
f4: self.b1,
i4: self.c1,
h5: self.f4,
i5: self.c4,
}
}
fn up_left(&self) -> KernelSection {
KernelSection {
e: self.e,
i: self.a,
h: self.b,
f: self.d,
g: self.c,
c: self.g,
d: self.f,
b: self.h,
f4: self.d0,
i4: self.a0,
h5: self.b1,
i5: self.a1,
}
}
fn down_left(&self) -> KernelSection {
KernelSection {
e: self.e,
i: self.g,
h: self.d,
f: self.h,
g: self.a,
c: self.i,
d: self.b,
b: self.f,
f4: self.h5,
i4: self.g5,
h5: self.d0,
i5: self.g0,
}
}
}
pub fn x2(block: Block) -> Block {
const SCALE: u32 = 2;
let mut buffer =
vec![0; (block.width as usize) * SCALE as usize * (block.height as usize) * SCALE as usize];
let dst_w = (block.width * SCALE) as usize;
let rgba = block.into_rgba();
for y in 0..block.height {
for x in 0..block.width {
let kernel = Kernel::new(&rgba, block.width, block.height, x, y);
let mut e0 = kernel.e;
let mut e1 = kernel.e;
let mut e2 = kernel.e;
let mut e3 = kernel.e;
sample_x2(kernel.down_right(), &mut e1, &mut e2, &mut e3);
sample_x2(kernel.up_right(), &mut e0, &mut e3, &mut e1);
sample_x2(kernel.up_left(), &mut e2, &mut e1, &mut e0);
sample_x2(kernel.down_left(), &mut e3, &mut e0, &mut e2);
let dst_x = (x * SCALE) as usize;
let dst_y = (y * SCALE) as usize;
buffer[dst_x + dst_y * dst_w] = e0;
buffer[dst_x + 1 + dst_y * dst_w] = e1;
buffer[dst_x + (dst_y + 1) * dst_w] = e2;
buffer[dst_x + 1 + (dst_y + 1) * dst_w] = e3;
}
}
Block::from_rgba(buffer, block.width * SCALE, block.height * SCALE)
}
fn sample_x2(s: KernelSection, n1: &mut u32, n2: &mut u32, n3: &mut u32) {
let ex = s.e == s.h || s.e == s.f;
if ex {
return;
}
let e =
diff(s.e, s.c) + diff(s.e, s.g) + diff(s.i, s.h5) + diff(s.i, s.f4) + diff(s.h, s.f) * 4.0;
let i =
diff(s.h, s.d) + diff(s.h, s.i5) + diff(s.f, s.i4) + diff(s.f, s.b) + diff(s.e, s.i) * 4.0;
let px = if diff(s.e, s.f) <= diff(s.e, s.h) {
s.f
} else {
s.h
};
let edge_cases = !is_equal(s.f, s.b) && !is_equal(s.h, s.d)
|| is_equal(s.e, s.i) && (!is_equal(s.f, s.i4) && !is_equal(s.h, s.i5))
|| is_equal(s.e, s.g)
|| is_equal(s.e, s.c);
if e < i && edge_cases {
let ke = diff(s.f, s.g);
let ki = diff(s.h, s.c);
let ex2 = s.e != s.c && s.b != s.c;
let ex3 = s.e != s.g && s.d != s.g;
if (ke * 2.0) <= ki && ex3 || ke >= (ki * 2.0) && ex2 {
if (ke * 2.0) <= ki && ex3 {
let left_out = left2(*n3, *n2, px);
*n3 = left_out[0];
*n2 = left_out[1];
}
if ke >= (ki * 2.0) && ex2 {
let up_out = up2(*n3, *n1, px);
*n3 = up_out[0];
*n1 = up_out[1];
}
} else {
*n3 = dia(*n3, px); }
} else if e <= i {
*n3 = blend_64w(*n3, px);
}
}