101 lines
3.3 KiB
Rust
101 lines
3.3 KiB
Rust
use anyhow::{Result, ensure};
|
|
use shacraft_core::Pos;
|
|
pub fn capture(min: Pos, max: Pos, mut cells: Vec<(Pos, [u8; 3])>) -> Result<Vec<u8>> {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|