/// Write a single palette index. Out-of-bounds coordinates are silently ignored. #[allow(dead_code)] pub fn set_pixel(dst: &mut [u8], dst_w: usize, x: i32, y: i32, color: u8) { let dst_h = (dst.len() / dst_w) as i32; if x < 0 || x >= dst_w as i32 || y < 0 || y >= dst_h { return; } dst[dst_w * y as usize + x as usize] = color; } /// Copy a rectangle out of `src` into a new Vec (for building sprites/glyphs). #[allow(dead_code)] pub fn extract(src: &[u8], src_w: usize, x: usize, y: usize, w: usize, h: usize) -> Vec { let mut out = vec![0u8; w * h]; for row in 0..h { let s = src_w * (y + row) + x; let d = w * row; out[d..d + w].copy_from_slice(&src[s..s + w]); } out } /// Blit `src` (width `src_w`, height derived from src.len()) into `dst` at (dx, dy). /// Clips against all four edges of `dst`; the destination position may be negative. #[allow(dead_code)] pub fn blit(dst: &mut [u8], dst_w: usize, dx: i32, dy: i32, src: &[u8], src_w: usize) { let dst_w_i = dst_w as i32; let dst_h = (dst.len() / dst_w) as i32; let src_h = (src.len() / src_w) as i32; for row in 0..src_h { let y = dy + row; if y < 0 || y >= dst_h { continue; } // Clip the horizontal span once per row, then copy it in one shot. let x0 = dx.max(0); let x1 = (dx + src_w as i32).min(dst_w_i); if x0 >= x1 { continue; } let d = dst_w * y as usize + x0 as usize; let s = (row * src_w as i32 + (x0 - dx)) as usize; let len = (x1 - x0) as usize; dst[d..d + len].copy_from_slice(&src[s..s + len]); } } /// Blit an 8×8 tile with transparency: index 0 is skipped. /// Clips against all four edges of `dst`; the destination position may be negative. pub fn blit_tile(dst: &mut [u8], dst_w: usize, dx: i32, dy: i32, tile: &[u8; 64]) { let dst_w_i = dst_w as i32; let dst_h = (dst.len() / dst_w) as i32; for row in 0..8i32 { let y = dy + row; if y < 0 || y >= dst_h { continue; } for col in 0..8i32 { let x = dx + col; if x < 0 || x >= dst_w_i { continue; } let px = tile[(row * 8 + col) as usize]; if px != 0 { dst[dst_w * y as usize + x as usize] = px; } } } }