Add loading of tiles from png transitional_engine
authorunC0Rr
Thu, 02 Feb 2023 08:41:31 +0100
branchtransitional_engine
changeset 15915 8f093b1b18bc
parent 15914 c571d4b8879c
child 15916 e82de0410da5
Add loading of tiles from png
rust/landgen/Cargo.toml
rust/landgen/src/wavefront_collapse/generator.rs
rust/landgen/src/wavefront_collapse/tile_image.rs
rust/landgen/src/wavefront_collapse/wavefront_collapse.rs
rust/vec2d/src/lib.rs
--- a/rust/landgen/Cargo.toml	Wed Feb 01 11:19:45 2023 +0100
+++ b/rust/landgen/Cargo.toml	Thu Feb 02 08:41:31 2023 +0100
@@ -9,3 +9,4 @@
 land2d = { path = "../land2d" }
 vec2d = { path = "../vec2d" }
 itertools = "0.7.8"
+png = "0.17"
--- a/rust/landgen/src/wavefront_collapse/generator.rs	Wed Feb 01 11:19:45 2023 +0100
+++ b/rust/landgen/src/wavefront_collapse/generator.rs	Thu Feb 02 08:41:31 2023 +0100
@@ -1,22 +1,53 @@
+use super::tile_image::TileImage;
 use super::wavefront_collapse::WavefrontCollapse;
-use super::tile_image::TileImage;
 use crate::{LandGenerationParameters, LandGenerator};
+use integral_geometry::Size;
+use png::Decoder;
+use std::fs::File;
+use std::io::BufReader;
 
 pub struct WavefrontCollapseLandGenerator {
     wfc: WavefrontCollapse,
-    tiles: Vec<TileImage>,
 }
 
 impl WavefrontCollapseLandGenerator {
     pub fn new() -> Self {
         Self {
             wfc: WavefrontCollapse::default(),
-            tiles: Vec::new()
         }
     }
 
-    pub fn load_template() {
+    pub fn load_template<T: Copy + PartialEq + Default>(&self, parameters: &LandGenerationParameters<T>) -> Vec<TileImage<T>> {
+        let file = File::open("sample.png").expect("file exists");
+        let decoder = Decoder::new(BufReader::new(file));
+        let mut reader = decoder.read_info().unwrap();
+
+        let info = reader.info();
+        let mut tiles_image = vec2d::Vec2D::new(
+            &Size::new(info.width as usize, info.height as usize),
+            parameters.zero,
+        );
+
+        let mut buf = vec![0; reader.output_buffer_size()];
+        let info = reader.next_frame(&mut buf).unwrap();
+        let bytes = &buf[..info.buffer_size()];
 
+        let mut tiles_image_pixels = tiles_image.as_mut_slice().into_iter();
+
+        for line in bytes.chunks_exact(info.line_size) {
+            for value in line.chunks_exact(info.color_type.samples()) {
+                *tiles_image_pixels
+                    .next()
+                    .expect("vec2d size matching image dimensions") =
+                    if value.into_iter().all(|p| *p == 0) {
+                        parameters.zero
+                    } else {
+                        parameters.basic
+                    };
+            }
+        }
+
+        TileImage::<T>::new(tiles_image).split(3, 3)
     }
 }
 
@@ -26,6 +57,23 @@
         parameters: &LandGenerationParameters<T>,
         random_numbers: &mut I,
     ) -> land2d::Land2D<T> {
+        let tiles = self.load_template(parameters);
+
         todo!()
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::WavefrontCollapseLandGenerator;
+    use crate::{LandGenerator, LandGenerationParameters};
+    use integral_geometry::Size;
+    use vec2d::Vec2D;
+
+    #[test]
+    fn test_generation() {
+        let wfc_gen =WavefrontCollapseLandGenerator::new();
+        let landgen_params = LandGenerationParameters::new(0u8, 255u8, 0, true, true);
+        wfc_gen.generate_land(&landgen_params, &mut std::iter::repeat(1u32));
+    }
+}
--- a/rust/landgen/src/wavefront_collapse/tile_image.rs	Wed Feb 01 11:19:45 2023 +0100
+++ b/rust/landgen/src/wavefront_collapse/tile_image.rs	Thu Feb 02 08:41:31 2023 +0100
@@ -1,18 +1,19 @@
-use land2d::Land2D;
+use vec2d::Vec2D;
 use std::rc::Rc;
+use integral_geometry::Size;
 
-pub struct TileImage {
-    image: Rc<Land2D<u8>>,
+pub struct TileImage<T> {
+    image: Rc<Vec2D<T>>,
     flip: bool,
     mirror: bool,
 }
 
-impl TileImage {
-    pub fn new(flip: bool, mirror: bool) -> Self {
+impl<T: Copy> TileImage<T> {
+    pub fn new(image: Vec2D<T>) -> Self {
         Self {
-            image: todo!(),
-            flip,
-            mirror,
+            image: Rc::new(image),
+            flip: false,
+            mirror: false,
         }
     }
 
@@ -20,7 +21,7 @@
         Self {
             image: self.image.clone(),
             flip: self.flip,
-            mirror: !self.mirror
+            mirror: !self.mirror,
         }
     }
 
@@ -28,7 +29,50 @@
         Self {
             image: self.image.clone(),
             flip: !self.flip,
-            mirror: self.mirror
+            mirror: self.mirror,
         }
     }
+
+    pub fn split(&self, rows: usize, columns: usize) -> Vec<TileImage<T>> {
+        let mut result = Vec::new();
+        let self_image = self.image.as_ref();
+        let (result_width, result_height) = (self_image.width() / columns, self.image.height() / rows);
+
+        for row in 0..rows {
+            for column in 0..columns {
+                let mut tile_pixels = Vec::new();
+
+                for out_row in 0..result_height {
+                    tile_pixels.push(self_image[row * result_height + out_row][column*result_width..(column+1)*result_width].iter());
+                }
+
+                let tile_image = Vec2D::from_iter(tile_pixels.into_iter().flatten().map(|p| *p), &Size::new(result_width, result_height));
+
+                result.push(TileImage::new(tile_image.expect("correct calculation of tile dimensions")));
+            }
+        }
+
+        result
+    }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::TileImage;
+    use integral_geometry::Size;
+    use vec2d::Vec2D;
+
+    #[test]
+    fn test_split() {
+        let size = Size::new(6, 4);
+        let sample_data = Vec2D::from_iter((0..24).into_iter(), &size);
+
+        assert!(sample_data.is_some());
+
+        let sample_data = sample_data.unwrap();
+        let big_tile = TileImage::new(sample_data);
+        let subtiles = big_tile.split(2, 2);
+
+        assert_eq!(subtiles.len(), 4);
+    }
+}
--- a/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs	Wed Feb 01 11:19:45 2023 +0100
+++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs	Thu Feb 02 08:41:31 2023 +0100
@@ -1,6 +1,6 @@
 use integral_geometry::Size;
+use std::collections::HashMap;
 use vec2d::Vec2D;
-use std::collections::HashMap;
 
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum Tile {
@@ -60,7 +60,7 @@
         map_size: &Size,
         seed_fn: F,
         random_numbers: &mut I,
-        ) -> Vec2D<Tile> {
+    ) -> Vec2D<Tile> {
         let mut land = Vec2D::new(&map_size, Tile::Empty);
 
         seed_fn(&mut land);
@@ -116,8 +116,12 @@
         [
             land.get(y, x + 1).map(|p| *p).unwrap_or_default(),
             land.get(y + 1, x).map(|p| *p).unwrap_or_default(),
-            land.get(y, x.wrapping_sub(1)).map(|p| *p).unwrap_or_default(),
-            land.get(y.wrapping_sub(1), x).map(|p| *p).unwrap_or_default(),
+            land.get(y, x.wrapping_sub(1))
+                .map(|p| *p)
+                .unwrap_or_default(),
+            land.get(y.wrapping_sub(1), x)
+                .map(|p| *p)
+                .unwrap_or_default(),
         ]
     }
 }
--- a/rust/vec2d/src/lib.rs	Wed Feb 01 11:19:45 2023 +0100
+++ b/rust/vec2d/src/lib.rs	Thu Feb 02 08:41:31 2023 +0100
@@ -143,6 +143,17 @@
     }
 }
 
+impl<T: Clone> Vec2D<T> {
+    pub fn from_iter<I: IntoIterator<Item = T>>(iter: I, size: &Size) -> Option<Vec2D<T>> {
+        let data: Vec<T> = iter.into_iter().collect();
+        if size.width * size.height == data.len() {
+            Some(Vec2D { data, size: *size })
+        } else {
+            None
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;