rust/mapgen/src/lib.rs
changeset 14710 946df0bb3b28
parent 14702 29dbe9ce8b7d
child 15828 44b49f255e31
equal deleted inserted replaced
14709:65c971417780 14710:946df0bb3b28
     1 pub mod theme;
     1 pub mod theme;
     2 
     2 
     3 use std::{
     3 use self::theme::Theme;
     4     collections::hash_map::HashMap,
     4 use integral_geometry::{Point, Rect, Size};
     5     borrow::Borrow,
     5 use land2d::Land2D;
     6     mem::replace
     6 use landgen::outline_template::OutlineTemplate;
     7 };
     7 use rand::{thread_rng, Rng};
     8 use serde_derive::{Deserialize};
     8 use serde_derive::Deserialize;
     9 use serde_yaml;
     9 use serde_yaml;
    10 use integral_geometry::{Point, Size, Rect};
    10 use std::{borrow::Borrow, collections::hash_map::HashMap, mem::replace};
    11 use landgen::{
       
    12     outline_template::OutlineTemplate
       
    13 };
       
    14 use rand::{thread_rng, Rng};
       
    15 use land2d::Land2D;
       
    16 use vec2d::Vec2D;
    11 use vec2d::Vec2D;
    17 use self::theme::Theme;
       
    18 
    12 
    19 #[derive(Deserialize)]
    13 #[derive(Deserialize)]
    20 struct PointDesc {
    14 struct PointDesc {
    21     x: u32,
    15     x: u32,
    22     y: u32
    16     y: u32,
    23 }
    17 }
    24 
    18 
    25 #[derive(Deserialize)]
    19 #[derive(Deserialize)]
    26 struct RectDesc {
    20 struct RectDesc {
    27     x: u32,
    21     x: u32,
    28     y: u32,
    22     y: u32,
    29     w: u32,
    23     w: u32,
    30     h: u32
    24     h: u32,
    31 }
    25 }
    32 
    26 
    33 #[derive(Deserialize)]
    27 #[derive(Deserialize)]
    34 struct TemplateDesc {
    28 struct TemplateDesc {
    35     width: usize,
    29     width: usize,
    39     can_mirror: bool,
    33     can_mirror: bool,
    40     is_negative: bool,
    34     is_negative: bool,
    41     put_girders: bool,
    35     put_girders: bool,
    42     max_hedgehogs: u8,
    36     max_hedgehogs: u8,
    43     outline_points: Vec<Vec<RectDesc>>,
    37     outline_points: Vec<Vec<RectDesc>>,
    44     fill_points: Vec<PointDesc>
    38     fill_points: Vec<PointDesc>,
    45 }
    39 }
    46 
    40 
    47 #[derive(Deserialize)]
    41 #[derive(Deserialize)]
    48 struct TemplateCollectionDesc {
    42 struct TemplateCollectionDesc {
    49     templates: Vec<TemplateDesc>,
    43     templates: Vec<TemplateDesc>,
    50     template_types: HashMap<String, Vec<usize>>
    44     template_types: HashMap<String, Vec<usize>>,
    51 }
    45 }
    52 
    46 
    53 impl From<&TemplateDesc> for OutlineTemplate {
    47 impl From<&TemplateDesc> for OutlineTemplate {
    54     fn from(desc: &TemplateDesc) -> Self {
    48     fn from(desc: &TemplateDesc) -> Self {
    55         OutlineTemplate {
    49         OutlineTemplate {
    56             islands: desc.outline_points.iter()
    50             islands: desc
    57                 .map(|v| v.iter()
    51                 .outline_points
    58                     .map(|r| Rect::from_size(
    52                 .iter()
    59                         Point::new(r.x as i32, r.y as i32),
    53                 .map(|v| {
    60                         Size::new(r.w as usize, r.h as usize)))
    54                     v.iter()
    61                     .collect())
    55                         .map(|r| {
       
    56                             Rect::from_size(
       
    57                                 Point::new(r.x as i32, r.y as i32),
       
    58                                 Size::new(r.w as usize, r.h as usize),
       
    59                             )
       
    60                         })
       
    61                         .collect()
       
    62                 })
    62                 .collect(),
    63                 .collect(),
    63             fill_points: desc.fill_points.iter()
    64             fill_points: desc
       
    65                 .fill_points
       
    66                 .iter()
    64                 .map(|p| Point::new(p.x as i32, p.y as i32))
    67                 .map(|p| Point::new(p.x as i32, p.y as i32))
    65                 .collect(),
    68                 .collect(),
    66             size: Size::new(desc.width, desc.height),
    69             size: Size::new(desc.width, desc.height),
    67             can_flip: desc.can_flip,
    70             can_flip: desc.can_flip,
    68             can_invert: desc.can_invert,
    71             can_invert: desc.can_invert,
    69             can_mirror: desc.can_mirror,
    72             can_mirror: desc.can_mirror,
    70             is_negative: desc.is_negative
    73             is_negative: desc.is_negative,
    71         }
    74         }
    72     }
    75     }
    73 }
    76 }
    74 
    77 
    75 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
    78 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
    81     }
    84     }
    82 }
    85 }
    83 
    86 
    84 #[derive(Debug)]
    87 #[derive(Debug)]
    85 pub struct MapGenerator {
    88 pub struct MapGenerator {
    86     pub(crate) templates: HashMap<TemplateType, Vec<OutlineTemplate>>
    89     pub(crate) templates: HashMap<TemplateType, Vec<OutlineTemplate>>,
    87 }
    90 }
    88 
    91 
    89 impl MapGenerator {
    92 impl MapGenerator {
    90     pub fn new() -> Self {
    93     pub fn new() -> Self {
    91         Self { templates: HashMap::new() }
    94         Self {
       
    95             templates: HashMap::new(),
       
    96         }
    92     }
    97     }
    93 
    98 
    94     pub fn import_yaml_templates(&mut self, text: &str) {
    99     pub fn import_yaml_templates(&mut self, text: &str) {
    95         let mut desc: TemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
   100         let mut desc: TemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
    96         let templates = replace(&mut desc.templates, vec![]);
   101         let templates = replace(&mut desc.templates, vec![]);
    97         self.templates = desc.template_types.into_iter()
   102         self.templates = desc
    98             .map(|(size, indices)|
   103             .template_types
    99                 (TemplateType(size), indices.iter()
   104             .into_iter()
   100                     .map(|i| (&templates[*i]).into())
   105             .map(|(size, indices)| {
   101                     .collect()))
   106                 (
       
   107                     TemplateType(size),
       
   108                     indices.iter().map(|i| (&templates[*i]).into()).collect(),
       
   109                 )
       
   110             })
   102             .collect();
   111             .collect();
   103     }
   112     }
   104 
   113 
   105     pub fn get_template(&self, template_type: &str) -> Option<&OutlineTemplate> {
   114     pub fn get_template(&self, template_type: &str) -> Option<&OutlineTemplate> {
   106         self.templates.get(template_type).and_then(|t| thread_rng().choose(t))
   115         self.templates
   107     }
   116             .get(template_type)
   108 
   117             .and_then(|t| thread_rng().choose(t))
   109     pub fn make_texture(&self, land: &Land2D<u8>, theme: &Theme) -> Vec2D<u32> {
   118     }
       
   119 
       
   120     pub fn make_texture<LandT>(&self, land: &Land2D<LandT>, theme: &Theme) -> Vec2D<u32>
       
   121     where
       
   122         LandT: Copy + Default + PartialEq,
       
   123     {
   110         let mut texture = Vec2D::new(land.size(), 0);
   124         let mut texture = Vec2D::new(land.size(), 0);
   111 
   125 
   112         if let Some(land_sprite) = theme.land_texture() {
   126         if let Some(land_sprite) = theme.land_texture() {
   113             for (row_index, (land_row, tex_row)) in land.rows()
   127             for (row_index, (land_row, tex_row)) in land.rows().zip(texture.rows_mut()).enumerate()
   114                 .zip(texture.rows_mut())
       
   115                 .enumerate()
       
   116             {
   128             {
   117                 let sprite_row = land_sprite.get_row(row_index % land_sprite.height());
   129                 let sprite_row = land_sprite.get_row(row_index % land_sprite.height());
   118                 let mut x_offset = 0;
   130                 let mut x_offset = 0;
   119                 while sprite_row.len() < land.width() - x_offset {
   131                 while sprite_row.len() < land.width() - x_offset {
   120                     let copy_range = x_offset..x_offset + sprite_row.len();
   132                     let copy_range = x_offset..x_offset + sprite_row.len();
   121                     tex_row_copy(
   133                     tex_row_copy(
   122                         &land_row[copy_range.clone()],
   134                         &land_row[copy_range.clone()],
   123                         &mut tex_row[copy_range],
   135                         &mut tex_row[copy_range],
   124                         sprite_row
   136                         sprite_row,
   125                     );
   137                     );
   126 
   138 
   127                     x_offset += land_sprite.width()
   139                     x_offset += land_sprite.width()
   128                 }
   140                 }
   129 
   141 
   130                 if x_offset < land.width() {
   142                 if x_offset < land.width() {
   131                     let final_range = x_offset..land.width();
   143                     let final_range = x_offset..land.width();
   132                     tex_row_copy(
   144                     tex_row_copy(
   133                         &land_row[final_range.clone()],
   145                         &land_row[final_range.clone()],
   134                         &mut tex_row[final_range],
   146                         &mut tex_row[final_range],
   135                         &sprite_row[..land.width() - x_offset]
   147                         &sprite_row[..land.width() - x_offset],
   136                     );
   148                     );
   137                 }
   149                 }
   138             }
   150             }
   139         }
   151         }
   140 
   152 
   147 
   159 
   148             land_border_pass(
   160             land_border_pass(
   149                 land.rows().rev().zip(texture.rows_mut().rev()),
   161                 land.rows().rev().zip(texture.rows_mut().rev()),
   150                 &mut offsets,
   162                 &mut offsets,
   151                 border_width,
   163                 border_width,
   152                 |x, y| border_sprite.get_pixel(
   164                 |x, y| {
   153                     x % border_sprite.width(),
   165                     border_sprite
   154                     border_sprite.height() - 1 - y,
   166                         .get_pixel(x % border_sprite.width(), border_sprite.height() - 1 - y)
   155                 )
   167                 },
   156             );
   168             );
   157 
   169 
   158             offsets.iter_mut().for_each(|v| *v = 255);
   170             offsets.iter_mut().for_each(|v| *v = 255);
   159 
   171 
   160             land_border_pass(
   172             land_border_pass(
   161                 land.rows().zip(texture.rows_mut()),
   173                 land.rows().zip(texture.rows_mut()),
   162                 &mut offsets,
   174                 &mut offsets,
   163                 border_width,
   175                 border_width,
   164                 |x, y| border_sprite.get_pixel(
   176                 |x, y| border_sprite.get_pixel(x % border_sprite.width(), y),
   165                     x % border_sprite.width(),
       
   166                     y,
       
   167                 )
       
   168             );
       
   169         }
       
   170 
       
   171         texture
       
   172     }
       
   173 
       
   174     // TODO: no way to pass both u8 & u32?
       
   175     pub fn make_texture32(&self, land: &Land2D<u32>, theme: &Theme) -> Vec2D<u32> {
       
   176         let mut texture = Vec2D::new(land.size(), 0);
       
   177 
       
   178         if let Some(land_sprite) = theme.land_texture() {
       
   179             for (row_index, (land_row, tex_row)) in land.rows()
       
   180                 .zip(texture.rows_mut())
       
   181                 .enumerate()
       
   182             {
       
   183                 let sprite_row = land_sprite.get_row(row_index % land_sprite.height());
       
   184                 let mut x_offset = 0;
       
   185                 while sprite_row.len() < land.width() - x_offset {
       
   186                     let copy_range = x_offset..x_offset + sprite_row.len();
       
   187                     tex_row_copy32(
       
   188                         &land_row[copy_range.clone()],
       
   189                         &mut tex_row[copy_range],
       
   190                         sprite_row
       
   191                     );
       
   192 
       
   193                     x_offset += land_sprite.width()
       
   194                 }
       
   195 
       
   196                 if x_offset < land.width() {
       
   197                     let final_range = x_offset..land.width();
       
   198                     tex_row_copy32(
       
   199                         &land_row[final_range.clone()],
       
   200                         &mut tex_row[final_range],
       
   201                         &sprite_row[..land.width() - x_offset]
       
   202                     );
       
   203                 }
       
   204             }
       
   205         }
       
   206 
       
   207         if let Some(border_sprite) = theme.border_texture() {
       
   208             assert!(border_sprite.height() <= 512);
       
   209             let border_width = (border_sprite.height() / 2) as u8;
       
   210             let border_sprite = border_sprite.to_tiled();
       
   211 
       
   212             let mut offsets = vec![255u8; land.width()];
       
   213 
       
   214             land_border_pass32(
       
   215                 land.rows().rev().zip(texture.rows_mut().rev()),
       
   216                 &mut offsets,
       
   217                 border_width,
       
   218                 |x, y| border_sprite.get_pixel(
       
   219                     x % border_sprite.width(),
       
   220                     border_sprite.height() - 1 - y,
       
   221                 )
       
   222             );
       
   223 
       
   224             offsets.iter_mut().for_each(|v| *v = 255);
       
   225 
       
   226             land_border_pass32(
       
   227                 land.rows().zip(texture.rows_mut()),
       
   228                 &mut offsets,
       
   229                 border_width,
       
   230                 |x, y| border_sprite.get_pixel(
       
   231                     x % border_sprite.width(),
       
   232                     y,
       
   233                 )
       
   234             );
   177             );
   235         }
   178         }
   236 
   179 
   237         texture
   180         texture
   238     }
   181     }
   277     let green = lerp(target.green(), source.green(), source.alpha());
   220     let green = lerp(target.green(), source.green(), source.alpha());
   278     let blue = lerp(target.blue(), source.blue(), source.alpha());
   221     let blue = lerp(target.blue(), source.blue(), source.alpha());
   279     (red as u32) << 0 | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24
   222     (red as u32) << 0 | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24
   280 }
   223 }
   281 
   224 
   282 fn land_border_pass<'a, T, F>(rows: T, offsets: &mut [u8], border_width: u8, pixel_getter: F)
   225 fn land_border_pass<'a, LandT, T, F>(rows: T, offsets: &mut [u8], border_width: u8, pixel_getter: F)
   283     where T: Iterator<Item = (&'a [u8], &'a mut [u32])>,
   226 where
   284           F: (Fn(usize, usize) -> u32)
   227     LandT: Default + PartialEq + 'a,
       
   228     T: Iterator<Item = (&'a [LandT], &'a mut [u32])>,
       
   229     F: (Fn(usize, usize) -> u32),
   285 {
   230 {
   286     for (land_row, tex_row) in rows {
   231     for (land_row, tex_row) in rows {
   287         for (x, ((land_v, tex_v), offset_v)) in land_row.iter()
   232         for (x, ((land_v, tex_v), offset_v)) in land_row
       
   233             .iter()
   288             .zip(tex_row.iter_mut())
   234             .zip(tex_row.iter_mut())
   289             .zip(offsets.iter_mut())
   235             .zip(offsets.iter_mut())
   290             .enumerate()
   236             .enumerate()
   291         {
   237         {
   292             *offset_v = if *land_v == 0 {
   238             *offset_v = if *land_v == LandT::default() {
   293                 if *offset_v < border_width {
   239                 if *offset_v < border_width {
   294                     *tex_v = blend(
   240                     *tex_v = blend(pixel_getter(x, *offset_v as usize), *tex_v)
   295                         pixel_getter(x, *offset_v as usize),
       
   296                         *tex_v,
       
   297                     )
       
   298                 }
   241                 }
   299                 offset_v.saturating_add(1)
   242                 offset_v.saturating_add(1)
   300             } else {
   243             } else {
   301                 0
   244                 0
   302             }
   245             }
   303         }
   246         }
   304     }
   247     }
   305 }
   248 }
   306 
   249 
   307 fn land_border_pass32<'a, T, F>(rows: T, offsets: &mut [u8], border_width: u8, pixel_getter: F)
   250 fn tex_row_copy<LandT>(land_row: &[LandT], tex_row: &mut [u32], sprite_row: &[u32])
   308     where T: Iterator<Item = (&'a [u32], &'a mut [u32])>,
   251 where
   309           F: (Fn(usize, usize) -> u32)
   252     LandT: Default + PartialEq,
   310 {
   253 {
   311     for (land_row, tex_row) in rows {
   254     for ((land_v, tex_v), sprite_v) in land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row) {
   312         for (x, ((land_v, tex_v), offset_v)) in land_row.iter()
   255         *tex_v = if *land_v == LandT::default() {
   313             .zip(tex_row.iter_mut())
       
   314             .zip(offsets.iter_mut())
       
   315             .enumerate()
       
   316         {
       
   317             *offset_v = if *land_v == 0 {
       
   318                 if *offset_v < border_width {
       
   319                     *tex_v = blend(
       
   320                         pixel_getter(x, *offset_v as usize),
       
   321                         *tex_v,
       
   322                     )
       
   323                 }
       
   324                 offset_v.saturating_add(1)
       
   325             } else {
       
   326                 0
       
   327             }
       
   328         }
       
   329     }
       
   330 }
       
   331 
       
   332 fn tex_row_copy(land_row: &[u8], tex_row: &mut [u32], sprite_row: &[u32]) {
       
   333     for ((land_v, tex_v), sprite_v) in
       
   334         land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row)
       
   335     {
       
   336         *tex_v = if *land_v == 0 {
       
   337             *sprite_v
   256             *sprite_v
   338         } else {
   257         } else {
   339             0
   258             0
   340         }
   259         }
   341     }
   260     }
   342 }
   261 }
   343 
   262 
   344 fn tex_row_copy32(land_row: &[u32], tex_row: &mut [u32], sprite_row: &[u32]) {
       
   345     for ((land_v, tex_v), sprite_v) in
       
   346         land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row)
       
   347     {
       
   348         *tex_v = if *land_v == 0 {
       
   349             *sprite_v
       
   350         } else {
       
   351             0
       
   352         }
       
   353     }
       
   354 }
       
   355 
       
   356 #[cfg(test)]
   263 #[cfg(test)]
   357 mod tests {
   264 mod tests {
   358     use crate::{
   265     use crate::{MapGenerator, TemplateType};
   359         MapGenerator,
       
   360         TemplateType
       
   361     };
       
   362 
   266 
   363     #[test]
   267     #[test]
   364     fn simple_load() {
   268     fn simple_load() {
   365         let text = r#"
   269         let text = r#"
   366 # comment
   270 # comment
   393 "#;
   297 "#;
   394 
   298 
   395         let mut generator = MapGenerator::new();
   299         let mut generator = MapGenerator::new();
   396         generator.import_yaml_templates(&text);
   300         generator.import_yaml_templates(&text);
   397 
   301 
   398         assert!(generator.templates.contains_key(&TemplateType("test".to_string())));
   302         assert!(generator
       
   303             .templates
       
   304             .contains_key(&TemplateType("test".to_string())));
   399 
   305 
   400         let template = generator.get_template("test").unwrap();
   306         let template = generator.get_template("test").unwrap();
   401 
   307 
   402         assert_eq!(template.islands[0].len(), 7);
   308         assert_eq!(template.islands[0].len(), 7);
   403     }
   309     }