implement basic land texturing
authoralfadur
Wed, 07 Nov 2018 22:01:47 +0300
changeset 14165 c24a76f131d6
parent 14164 0aeea29ef890
child 14166 fe5bfe70c3c2
implement basic land texturing
rust/land2d/src/lib.rs
rust/mapgen/Cargo.toml
rust/mapgen/src/lib.rs
rust/mapgen/src/theme.rs
rust/vec2d/src/lib.rs
--- a/rust/land2d/src/lib.rs	Wed Nov 07 19:43:17 2018 +0100
+++ b/rust/land2d/src/lib.rs	Wed Nov 07 22:01:47 2018 +0300
@@ -30,7 +30,7 @@
     }
 
     pub fn raw_pixels(&self) -> &[T] {
-        &self.pixels.raw_data()
+        &self.pixels.as_slice()
     }
 
     #[inline]
--- a/rust/mapgen/Cargo.toml	Wed Nov 07 19:43:17 2018 +0100
+++ b/rust/mapgen/Cargo.toml	Wed Nov 07 22:01:47 2018 +0300
@@ -5,6 +5,7 @@
 edition = "2018"
 
 [dependencies]
+vec2d = { path = "../vec2d" }
 land2d = { path = "../land2d" }
 landgen = { path = "../landgen" }
 lfprng = { path = "../lfprng" }
--- a/rust/mapgen/src/lib.rs	Wed Nov 07 19:43:17 2018 +0100
+++ b/rust/mapgen/src/lib.rs	Wed Nov 07 22:01:47 2018 +0300
@@ -5,7 +5,6 @@
     borrow::Borrow,
     mem::replace
 };
-use serde::{Deserialize};
 use serde_derive::{Deserialize};
 use serde_yaml;
 use integral_geometry::{Point, Size, Rect};
@@ -14,6 +13,7 @@
 };
 use rand::{thread_rng, Rng};
 use land2d::Land2D;
+use vec2d::Vec2D;
 use self::theme::Theme;
 
 #[derive(Deserialize)]
@@ -106,11 +106,52 @@
         self.templates.get(template_type).and_then(|t| thread_rng().choose(t))
     }
 
-    pub fn make_texture(&self, land: &Land2D<u32>, theme: &Theme) {
+    pub fn make_texture(&self, land: &Land2D<u32>, theme: &Theme) -> Vec2D<u32> {
+        let mut texture = Vec2D::new(land.size(), 0);
+        if let Some(land_sprite) = theme.land_texture() {
+            for (row_index, (land_row, tex_row)) in land.rows()
+                .zip(texture.rows_mut())
+                .enumerate()
+            {
+                let sprite_row = land_sprite.get_row(row_index % land_sprite.height());
+                let mut x_offset = 0;
+                while sprite_row.len() < land.width() - x_offset {
+                    let copy_range = x_offset..x_offset + sprite_row.len();
+                    tex_row_copy(
+                        &land_row[copy_range.clone()],
+                        &mut tex_row[copy_range],
+                        sprite_row
+                    );
+
+                    x_offset += land_sprite.width()
+                }
 
+                if x_offset < land.width() {
+                    let final_range = x_offset..land.width() - 1;
+                    tex_row_copy(
+                        &land_row[final_range.clone()],
+                        &mut tex_row[final_range],
+                        &sprite_row[..land.width() - x_offset]
+                    );
+                }
+            }
+        }
+        texture
     }
 }
 
+fn tex_row_copy(land_row: &[u32], tex_row: &mut [u32], sprite_row: &[u32]) {
+    for ((land_v, tex_v), sprite_v) in
+        land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row)
+        {
+            *tex_v = if *land_v == 0 {
+                *sprite_v
+            } else {
+                0
+            }
+        }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{
--- a/rust/mapgen/src/theme.rs	Wed Nov 07 19:43:17 2018 +0100
+++ b/rust/mapgen/src/theme.rs	Wed Nov 07 22:01:47 2018 +0300
@@ -6,25 +6,55 @@
     path::Path
 };
 use png::{
-    BitDepth,
     ColorType,
     Decoder,
     DecodingError
 };
 
-use integral_geometry::{
-    Rect, Size
-};
+use integral_geometry::Size;
+use vec2d::Vec2D;
 
 pub struct ThemeSprite {
-    bounds: Size,
-    pixels: Vec<u32>
+    pixels: Vec2D<u32>
+}
+
+impl ThemeSprite {
+    #[inline]
+    pub fn width(&self) -> usize {
+        self.pixels.size().width
+    }
+
+    #[inline]
+    pub fn height(&self) -> usize {
+        self.pixels.size().height
+    }
+
+    #[inline]
+    pub fn bounds(&self) -> Size {
+        self.pixels.size()
+    }
+
+    #[inline]
+    pub fn rows(&self) -> impl Iterator<Item = &[u32]> {
+        self.pixels.rows()
+    }
+
+    #[inline]
+    pub fn get_row(&self, index: usize) -> &[u32] {
+        &self.pixels[index]
+    }
 }
 
 pub struct Theme {
     land_texture: Option<ThemeSprite>
 }
 
+impl Theme {
+    pub fn land_texture(&self) -> Option<&ThemeSprite> {
+        self.land_texture.as_ref()
+    }
+}
+
 pub enum ThemeLoadError {
     File(io::Error),
     Decoding(DecodingError),
@@ -66,18 +96,17 @@
                 }
                 let size = Size::new(info.width as usize, info.height as usize);
 
-                let mut buffer: Vec<u32> = Vec::with_capacity(size.area());
-                let mut slice_u32 = buffer.as_mut_slice();
-                let mut slice_u8 = unsafe {
+                let mut buffer: Vec2D<u32> = Vec2D::new(size, 0);
+                let slice_u32 = buffer.as_mut_slice();
+                let slice_u8 = unsafe {
                     from_raw_parts_mut::<u8>(
                         slice_u32.as_mut_ptr() as *mut u8,
                         slice_u32.len() / 4
                     )
                 };
-                reader.next_frame(slice_u8);
+                reader.next_frame(slice_u8)?;
 
                 let land_tex = ThemeSprite {
-                    bounds: size,
                     pixels: buffer
                 };
                 theme.land_texture = Some(land_tex)
--- a/rust/vec2d/src/lib.rs	Wed Nov 07 19:43:17 2018 +0100
+++ b/rust/vec2d/src/lib.rs	Wed Nov 07 22:01:47 2018 +0300
@@ -55,8 +55,14 @@
         Self { size, data: vec![value; size.area()] }
     }
 
-    pub fn raw_data(&self) -> &[T] {
-        &self.data
+    #[inline]
+    pub fn as_slice(&self) -> &[T] {
+        self.data.as_slice()
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [T] {
+        self.data.as_mut_slice()
     }
 
     #[inline]
@@ -83,6 +89,24 @@
     pub fn rows(&self) -> impl Iterator<Item = &[T]> {
         self.data.chunks(self.width())
     }
+
+    #[inline]
+    pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [T]> {
+        let width = self.width();
+        self.data.chunks_mut(width)
+    }
+}
+
+impl<T: Copy> AsRef<[T]> for Vec2D<T> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
+impl<T: Copy> AsMut<[T]> for Vec2D<T> {
+    fn as_mut(&mut self) -> &mut [T] {
+        self.as_mut_slice()
+    }
 }
 
 #[cfg(test)]