use anyhow::{Result, ensure}; use shacraft_core::Pos; pub fn capture(min: Pos, max: Pos, mut cells: Vec<(Pos, [u8; 3])>) -> Result> { ensure!((0..3).all(|i| max[i] >= min[i]), "invalid capture bounds"); let size = 512usize; let mut image = vec![0u8; size * size * 3]; for pixel in image.chunks_exact_mut(3) { pixel.copy_from_slice(&[24, 36, 48]); } let span = (max[0] - min[0] + max[2] - min[2] + 2) as f32; let vertical = ((max[1] - min[1] + 1) as f32 + span * 0.25).max(1.); let scale = (460. / span.max(1.)).min(440. / vertical).clamp(0.1, 24.); cells.sort_by_key(|(p, _)| (p[0] + p[2], p[1])); for (p, c) in cells { let x = (p[0] - min[0]) as f32; let y = (p[1] - min[1]) as f32; let z = (p[2] - min[2]) as f32; let cx = 256. + (x - z - (max[0] - min[0] - max[2] + min[2]) as f32 * 0.5) * scale; let cy = 470. - (y + 1.) * scale - (span * 0.5 - x - z) * scale * 0.5; let top = [ [cx, cy - scale * 0.5], [cx + scale, cy], [cx, cy + scale * 0.5], [cx - scale, cy], ]; polygon(&mut image, size, top, c); polygon( &mut image, size, [ [cx - scale, cy], [cx, cy + scale * 0.5], [cx, cy + scale * 1.5], [cx - scale, cy + scale], ], c.map(|v| (v as f32 * 0.64) as u8), ); polygon( &mut image, size, [ [cx, cy + scale * 0.5], [cx + scale, cy], [cx + scale, cy + scale], [cx, cy + scale * 1.5], ], c.map(|v| (v as f32 * 0.82) as u8), ); } let mut bytes = Vec::new(); { let mut encoder = png::Encoder::new(&mut bytes, size as u32, size as u32); encoder.set_color(png::ColorType::Rgb); encoder.set_depth(png::BitDepth::Eight); encoder.write_header()?.write_image_data(&image)?; } Ok(bytes) } fn polygon(img: &mut [u8], size: usize, p: [[f32; 2]; 4], color: [u8; 3]) { let minx = p .iter() .map(|p| p[0]) .fold(f32::INFINITY, f32::min) .floor() .max(0.) as usize; let maxx = p .iter() .map(|p| p[0]) .fold(f32::NEG_INFINITY, f32::max) .ceil() .clamp(0., size as f32 - 1.) as usize; let miny = p .iter() .map(|p| p[1]) .fold(f32::INFINITY, f32::min) .floor() .max(0.) as usize; let maxy = p .iter() .map(|p| p[1]) .fold(f32::NEG_INFINITY, f32::max) .ceil() .clamp(0., size as f32 - 1.) as usize; for y in miny..=maxy { for x in minx..=maxx { let mut signs = [false; 4]; for i in 0..4 { let a = p[i]; let b = p[(i + 1) % 4]; signs[i] = (b[0] - a[0]) * (y as f32 + 0.5 - a[1]) - (b[1] - a[1]) * (x as f32 + 0.5 - a[0]) >= 0.; } if signs.iter().all(|s| *s) || signs.iter().all(|s| !*s) { let i = (y * size + x) * 3; img[i..i + 3].copy_from_slice(&color); } } } }