rust/landgen/src/wavefront_collapse/generator.rs
branchtransitional_engine
changeset 15955 b0e8cc72bfef
parent 15954 9502611bffc1
child 15956 c273908218f3
equal deleted inserted replaced
15954:9502611bffc1 15955:b0e8cc72bfef
    34     pub can_rotate180: Option<bool>,
    34     pub can_rotate180: Option<bool>,
    35     pub can_rotate270: Option<bool>,
    35     pub can_rotate270: Option<bool>,
    36 }
    36 }
    37 
    37 
    38 #[derive(Clone)]
    38 #[derive(Clone)]
       
    39 pub struct NonStrictEdgesDescription {
       
    40     pub top: Option<EdgeDescription>,
       
    41     pub right: Option<EdgeDescription>,
       
    42     pub bottom: Option<EdgeDescription>,
       
    43     pub left: Option<EdgeDescription>,
       
    44 }
       
    45 
       
    46 #[derive(Clone)]
    39 pub struct TemplateDescription {
    47 pub struct TemplateDescription {
    40     pub size: Size,
    48     pub size: Size,
    41     pub tiles: Vec<TileDescription>,
    49     pub tiles: Vec<TileDescription>,
       
    50     pub edges: NonStrictEdgesDescription,
    42     pub wrap: bool,
    51     pub wrap: bool,
    43 }
    52 }
    44 
    53 
    45 pub struct WavefrontCollapseLandGenerator {
    54 pub struct WavefrontCollapseLandGenerator {
    46     pub template: TemplateDescription,
    55     pub template: TemplateDescription,
   105                     }
   114                     }
   106                 }
   115                 }
   107             }
   116             }
   108         }
   117         }
   109 
   118 
   110         let edges: Vec<Edge<String>> = [
   119         let [top_edge, right_edge, bottom_edge, left_edge]: [Edge<String>; 4] = [
   111             &tile_description.edges.top,
   120             (&tile_description.edges.top).into(),
   112             &tile_description.edges.right,
   121             (&tile_description.edges.right).into(),
   113             &tile_description.edges.bottom,
   122             (&tile_description.edges.bottom).into(),
   114             &tile_description.edges.left,
   123             (&tile_description.edges.left).into(),
   115         ]
   124         ];
   116         .iter()
       
   117         .map(|descr| {
       
   118             let edge = Edge::new(descr.name.clone(), descr.symmetrical.unwrap_or_default());
       
   119 
       
   120             if descr.reversed.unwrap_or_default() {
       
   121                 edge.reversed()
       
   122             } else {
       
   123                 edge
       
   124             }
       
   125         })
       
   126         .collect();
       
   127 
       
   128         let [top_edge, right_edge, bottom_edge, left_edge] = edges.as_slice() else {
       
   129             unreachable!()
       
   130         };
       
   131 
   125 
   132         let tile = TileImage::<T, String>::new(
   126         let tile = TileImage::<T, String>::new(
   133             tiles_image,
   127             tiles_image,
   134             top_edge.clone(),
   128             top_edge,
   135             right_edge.clone(),
   129             right_edge,
   136             bottom_edge.clone(),
   130             bottom_edge,
   137             left_edge.clone(),
   131             left_edge,
   138         );
   132         );
   139 
   133 
   140         result.push(tile.clone());
   134         result.push(tile.clone());
   141 
   135 
   142         if tile_description.can_flip.unwrap_or_default() {
   136         if tile_description.can_flip.unwrap_or_default() {
   175                 result.append(&mut tiles);
   169                 result.append(&mut tiles);
   176             }
   170             }
   177         }
   171         }
   178 
   172 
   179         result
   173         result
       
   174     }
       
   175 
       
   176     pub fn build_rules<T: Copy + PartialEq + Default>(
       
   177         &self,
       
   178         tiles: &[TileImage<T, String>],
       
   179     ) -> Vec<CollapseRule> {
       
   180         let [grid_top_edge, grid_right_edge, grid_bottom_edge, grid_left_edge]: [Option<
       
   181             Edge<String>,
       
   182         >; 4] = [
       
   183             self.template.edges.top.as_ref(),
       
   184             self.template.edges.right.as_ref(),
       
   185             self.template.edges.bottom.as_ref(),
       
   186             self.template.edges.left.as_ref(),
       
   187         ]
       
   188         .map(|opt| opt.map(|d| d.into()));
       
   189 
       
   190         let mut rules = Vec::<CollapseRule>::new();
       
   191 
       
   192         let default_connection = HashSet::from_iter(vec![Tile::Empty].into_iter());
       
   193         for (i, tile) in tiles.iter().enumerate() {
       
   194             let mut right = default_connection.clone();
       
   195             let mut bottom = default_connection.clone();
       
   196             let mut left = default_connection.clone();
       
   197             let mut top = default_connection.clone();
       
   198 
       
   199             // compatibility with grid edges
       
   200             if grid_top_edge
       
   201                 .as_ref()
       
   202                 .map(|e| e.is_compatible(tile.top_edge()))
       
   203                 .unwrap_or(true)
       
   204             {
       
   205                 top.insert(Tile::Outside);
       
   206             }
       
   207             if grid_right_edge
       
   208                 .as_ref()
       
   209                 .map(|e| e.is_compatible(tile.right_edge()))
       
   210                 .unwrap_or(true)
       
   211             {
       
   212                 right.insert(Tile::Outside);
       
   213             }
       
   214             if grid_bottom_edge
       
   215                 .as_ref()
       
   216                 .map(|e| e.is_compatible(tile.bottom_edge()))
       
   217                 .unwrap_or(true)
       
   218             {
       
   219                 bottom.insert(Tile::Outside);
       
   220             }
       
   221             if grid_left_edge
       
   222                 .as_ref()
       
   223                 .map(|e| e.is_compatible(tile.left_edge()))
       
   224                 .unwrap_or(true)
       
   225             {
       
   226                 left.insert(Tile::Outside);
       
   227             }
       
   228 
       
   229             // compatibility with itself
       
   230             if tile.left_edge().is_compatible(tile.right_edge()) {
       
   231                 left.insert(Tile::Numbered(i));
       
   232                 right.insert(Tile::Numbered(i));
       
   233             }
       
   234 
       
   235             if tile.top_edge().is_compatible(tile.bottom_edge()) {
       
   236                 top.insert(Tile::Numbered(i));
       
   237                 bottom.insert(Tile::Numbered(i));
       
   238             }
       
   239 
       
   240             // compatibility with previously defined tiles
       
   241             for p in 0..i {
       
   242                 if tiles[p].left_edge().is_compatible(tile.right_edge()) {
       
   243                     rules[p].left.insert(Tile::Numbered(i));
       
   244                     right.insert(Tile::Numbered(p));
       
   245                 }
       
   246 
       
   247                 if tiles[p].right_edge().is_compatible(tile.left_edge()) {
       
   248                     rules[p].right.insert(Tile::Numbered(i));
       
   249                     left.insert(Tile::Numbered(p));
       
   250                 }
       
   251 
       
   252                 if tiles[p].top_edge().is_compatible(tile.bottom_edge()) {
       
   253                     rules[p].top.insert(Tile::Numbered(i));
       
   254                     bottom.insert(Tile::Numbered(p));
       
   255                 }
       
   256 
       
   257                 if tiles[p].bottom_edge().is_compatible(tile.top_edge()) {
       
   258                     rules[p].bottom.insert(Tile::Numbered(i));
       
   259                     top.insert(Tile::Numbered(p));
       
   260                 }
       
   261             }
       
   262 
       
   263             rules.push(CollapseRule {
       
   264                 tile: Tile::Numbered(i),
       
   265                 top,
       
   266                 right,
       
   267                 bottom,
       
   268                 left,
       
   269             });
       
   270         }
       
   271 
       
   272         rules
   180     }
   273     }
   181 }
   274 }
   182 
   275 
   183 impl LandGenerator for WavefrontCollapseLandGenerator {
   276 impl LandGenerator for WavefrontCollapseLandGenerator {
   184     fn generate_land<T: Copy + PartialEq + Default, I: Iterator<Item = u32>>(
   277     fn generate_land<T: Copy + PartialEq + Default, I: Iterator<Item = u32>>(
   185         &self,
   278         &self,
   186         parameters: &LandGenerationParameters<T>,
   279         parameters: &LandGenerationParameters<T>,
   187         random_numbers: &mut I,
   280         random_numbers: &mut I,
   188     ) -> land2d::Land2D<T> {
   281     ) -> land2d::Land2D<T> {
   189         let tiles = self.load_template(parameters);
   282         let tiles = self.load_template(parameters);
   190 
   283         let rules = self.build_rules(&tiles);
   191         let mut rules = Vec::<CollapseRule>::new();
       
   192 
       
   193         let default_connection = HashSet::from_iter(vec![Tile::Outside, Tile::Empty].into_iter());
       
   194         for (i, tile) in tiles.iter().enumerate() {
       
   195             let mut right = default_connection.clone();
       
   196             let mut bottom = default_connection.clone();
       
   197             let mut left = default_connection.clone();
       
   198             let mut top = default_connection.clone();
       
   199 
       
   200             for p in 0..i {
       
   201                 if tiles[p].left_edge().is_compatible(tile.right_edge()) {
       
   202                     rules[p].left.insert(Tile::Numbered(i));
       
   203                     right.insert(Tile::Numbered(p));
       
   204                 }
       
   205 
       
   206                 if tiles[p].right_edge().is_compatible(tile.left_edge()) {
       
   207                     rules[p].right.insert(Tile::Numbered(i));
       
   208                     left.insert(Tile::Numbered(p));
       
   209                 }
       
   210 
       
   211                 if tiles[p].top_edge().is_compatible(tile.bottom_edge()) {
       
   212                     rules[p].top.insert(Tile::Numbered(i));
       
   213                     bottom.insert(Tile::Numbered(p));
       
   214                 }
       
   215 
       
   216                 if tiles[p].bottom_edge().is_compatible(tile.top_edge()) {
       
   217                     rules[p].bottom.insert(Tile::Numbered(i));
       
   218                     top.insert(Tile::Numbered(p));
       
   219                 }
       
   220             }
       
   221 
       
   222             rules.push(CollapseRule {
       
   223                 tile: Tile::Numbered(i),
       
   224                 top,
       
   225                 right,
       
   226                 bottom,
       
   227                 left,
       
   228             });
       
   229         }
       
   230 
   284 
   231         let mut wfc = WavefrontCollapse::new(self.template.wrap);
   285         let mut wfc = WavefrontCollapse::new(self.template.wrap);
   232         wfc.set_rules(rules);
   286         wfc.set_rules(rules);
   233 
   287 
   234         let wfc_size = if let Some(first_tile) = tiles.first() {
   288         let wfc_size = if let Some(first_tile) = tiles.first() {
   242             Size::new(1, 1)
   296             Size::new(1, 1)
   243         };
   297         };
   244 
   298 
   245         wfc.generate_map(&wfc_size, |_| {}, random_numbers);
   299         wfc.generate_map(&wfc_size, |_| {}, random_numbers);
   246 
   300 
       
   301         // render tiles into resulting land array
   247         let mut result = land2d::Land2D::new(&self.template.size, parameters.zero);
   302         let mut result = land2d::Land2D::new(&self.template.size, parameters.zero);
   248         let offset_y = result.height() - result.play_height();
   303         let offset_y = result.height() - result.play_height();
   249         let offset_x = (result.width() - result.play_width()) / 2;
   304         let offset_x = (result.width() - result.play_width()) / 2;
   250 
   305 
   251         for row in 0..wfc_size.height {
   306         for row in 0..wfc_size.height {
   270         }
   325         }
   271 
   326 
   272         result
   327         result
   273     }
   328     }
   274 }
   329 }
       
   330 
       
   331 impl From<&EdgeDescription> for Edge<String> {
       
   332     fn from(val: &EdgeDescription) -> Self {
       
   333         let edge = Edge::new(val.name.clone(), val.symmetrical.unwrap_or_default());
       
   334 
       
   335         if val.reversed.unwrap_or_default() {
       
   336             edge.reversed()
       
   337         } else {
       
   338             edge
       
   339         }
       
   340     }
       
   341 }