pub mod blocks;
pub mod locate;
pub mod model;
pub mod run;
pub mod stats;
pub const CELL: usize = 2;
pub const BLOCK: usize = 16;
pub const TIER_OPAQUE: u8 = 0;
pub const TIER_FRINGE: u8 = 1;
pub const TIER_VEIL: u8 = 2;
pub const TIER_CLEAN: u8 = 3;
#[inline]
pub fn tolerance(noise: f64) -> i32 {
((noise * 2.4).round() as i32).max(2)
}
#[inline]
pub fn luma(r: u8, g: u8, b: u8) -> u32 {
(r as u32 * 77 + g as u32 * 150 + b as u32 * 29) >> 8
}
pub struct Frame<'a> {
pub rgba: &'a [u8],
pub width: usize,
pub height: usize,
}
pub struct Footprint<'a> {
pub x: i64,
pub y: i64,
pub width: usize,
pub height: usize,
pub mask: &'a [u8],
}
impl Footprint<'_> {
#[inline]
pub fn contains(&self, sx: i64, sy: i64) -> bool {
let (lx, ly) = (sx - self.x, sy - self.y);
lx >= 0
&& ly >= 0
&& (lx as usize) < self.width
&& (ly as usize) < self.height
&& self.mask[ly as usize * self.width + lx as usize] != 0
}
pub fn occlude(
label_mask: &[u8],
x: i64,
y: i64,
width: usize,
height: usize,
occlusions: &[(i64, i64, i64, i64)],
) -> Vec<u8> {
let mut m = label_mask.to_vec();
for &(ox, oy, ow, oh) in occlusions {
let (x0, y0) = ((ox - x).max(0) as usize, (oy - y).max(0) as usize);
let (x1, y1) = (
((ox + ow - x).max(0) as usize).min(width),
((oy + oh - y).max(0) as usize).min(height),
);
for ly in y0..y1.max(y0) {
if x1 > x0 {
m[ly * width + x0..ly * width + x1].fill(0);
}
}
}
m
}
}
pub struct CanvasView<'a> {
pub x: i64,
pub y: i64,
pub width: usize,
pub height: usize,
pub rgba: &'a [u8],
pub coverage: &'a [u8],
}
impl CanvasView<'_> {
#[inline]
pub fn covered(&self, wx: i64, wy: i64) -> Option<usize> {
let (lx, ly) = (wx - self.x, wy - self.y);
if lx < 0 || ly < 0 || lx >= self.width as i64 || ly >= self.height as i64 {
return None;
}
let i = ly as usize * self.width + lx as usize;
(self.coverage[i >> 3] & (1 << (i & 7)) != 0).then_some(i)
}
}