chessboard_generator/
chessboard_generator.rs1use crate::layers::LayerWood;
2use color_eyre::Result;
3use image::DynamicImage;
4use image::ImageBuffer;
5use image::ImageFormat;
6use image::Pixel;
7use image::Rgba;
8use image::RgbaImage;
9use std::path::Path;
10use thiserror::Error;
11
12#[derive(Error, Debug)]
13pub enum ChessboardGeneratorError {
14 #[error("overlay has wrong size, expected {size}x{size} got {width}x{height}")]
15 WrongOverlaySize { size: u32, width: u32, height: u32 },
16}
17
18type RgbaImage32F = ImageBuffer<Rgba<f32>, Vec<f32>>;
19#[derive(Debug)]
20pub struct ChessboardGenerator {
21 size: u32,
22 colors: [Rgba<f32>; 2],
23 buffer: Option<RgbaImage>,
24 overlays: Vec<RgbaImage32F>,
25 layers: Vec<Box<LayerWood>>,
26}
27
28impl Default for ChessboardGenerator {
29 fn default() -> Self {
30 Self {
31 size: 128,
32 colors: [
33 Rgba::from([1.0, 1.0, 1.0, 1.0]),
34 Rgba::from([0.0, 0.0, 0.0, 1.0]),
35 ],
36 buffer: None,
37 overlays: Vec::default(),
38 layers: Vec::default(),
39 }
40 }
41}
42impl ChessboardGenerator {
43 pub fn new(colors: &[[u8; 4]; 2]) -> Self {
44 Self {
45 colors: colors.map(|c| Rgba::from(c.map(|c| (c as f32) / 255.0))),
46 ..Default::default()
47 }
48 }
49 pub fn set_size(&mut self, size: u32) {
50 self.size = size;
51 }
52 pub fn add_layer(&mut self, layer: Box<LayerWood>) {
53 self.layers.push(layer);
54 }
55 pub fn add_overlay_image(&mut self, img: DynamicImage) -> Result<()> {
56 if img.width() != self.size || img.height() != self.size {
58 Err(ChessboardGeneratorError::WrongOverlaySize {
59 size: self.size,
60 width: img.width(),
61 height: img.height(),
62 }
63 .into())
64 } else {
65 self.overlays.push(img.into_rgba32f());
66 Ok(())
67 }
68 }
69 pub fn render(&mut self) {
70 let mut buffer = RgbaImage32F::new(self.size, self.size);
71 let size = self.size as f32;
72 let ppc = size / 8.0;
73 let colors = self.colors;
74 for (x, y, pixel) in buffer.enumerate_pixels_mut() {
75 let fx = x as f32;
76 let fy = y as f32;
77 let col = (fx / ppc).floor();
78 let row = (fy / ppc).floor();
79 let p = (row + col).rem_euclid(2.0) as usize;
80 let mut c = self.colors[p];
81 let nx = fx / size;
85 let ny = fy / size;
86 for layer in self.layers.iter() {
87 c = layer.apply(nx, ny, p, &colors, c);
88 }
89 *pixel = c;
90 }
91
92 for overlay in self.overlays.iter() {
93 for (x, y, pixel) in buffer.enumerate_pixels_mut() {
94 let o = overlay.get_pixel(x, y);
95 pixel.blend(&o);
96 }
97 }
98 let buffer = DynamicImage::ImageRgba32F(buffer).into_rgba8();
99 self.buffer = Some(buffer);
100 }
101 pub fn save_as_png(&self, path: &Path) {
102 if let Some(buffer) = &self.buffer {
103 let _todo = buffer
104 .save_with_format(path, ImageFormat::Png)
105 .expect("Can save PNG");
106 } else {
107 }
109 }
110}