use crate::pipe::Pattern;
pub struct TiledPattern {
pixels: Vec<u8>,
width: i32,
height: i32,
phase_x: i32,
phase_y: i32,
}
impl TiledPattern {
#[must_use]
#[expect(
clippy::cast_sign_loss,
reason = "width/height are asserted positive just above the cast"
)]
pub fn new(pixels: Vec<u8>, width: i32, height: i32, phase_x: i32, phase_y: i32) -> Self {
assert!(
width > 0,
"TiledPattern: width must be positive, got {width}"
);
assert!(
height > 0,
"TiledPattern: height must be positive, got {height}"
);
let expected = width as usize * height as usize * 3;
assert!(
pixels.len() == expected,
"TiledPattern: pixels.len() {} does not match width({width}) * height({height}) * 3 = {expected}",
pixels.len()
);
Self {
pixels,
width,
height,
phase_x,
phase_y,
}
}
}
impl Pattern for TiledPattern {
#[expect(
clippy::cast_sign_loss,
reason = "rem_euclid guarantees non-negative results; safe cast to usize"
)]
fn fill_span(&self, y: i32, x0: i32, x1: i32, out: &mut [u8]) {
let ty = (y - self.phase_y).rem_euclid(self.height) as usize;
let w = self.width as usize;
let row_start = ty * w * 3;
let row = &self.pixels[row_start..row_start + w * 3];
let mut out_pos = 0usize;
for x in x0..=x1 {
let tx = (x - self.phase_x).rem_euclid(self.width) as usize;
out[out_pos] = row[tx * 3];
out[out_pos + 1] = row[tx * 3 + 1];
out[out_pos + 2] = row[tx * 3 + 2];
out_pos += 3;
}
}
}