rust/landgen/src/wavefront_collapse/generator.rs
changeset 16108 65c017453e83
parent 16106 aba25f4e4645
child 16109 2fc37552b587
equal deleted inserted replaced
16107:e12d9a4d0e04 16108:65c017453e83
     1 use super::tile_image::{Edge, TileImage};
     1 use super::tile_image::{Edge, EdgeSet, MatchSide, TileImage};
     2 use super::wavefront_collapse::{CollapseRule, Tile, WavefrontCollapse};
     2 use super::wavefront_collapse::{CollapseRule, Tile, WavefrontCollapse};
     3 use crate::{LandGenerationParameters, LandGenerator};
     3 use crate::{LandGenerationParameters, LandGenerator};
     4 use integral_geometry::Size;
     4 use integral_geometry::Size;
     5 use png::Decoder;
     5 use png::Decoder;
     6 use rand::Rng;
     6 use rand::Rng;
    27 #[derive(Debug, Clone)]
    27 #[derive(Debug, Clone)]
    28 pub struct TileDescription {
    28 pub struct TileDescription {
    29     pub name: String,
    29     pub name: String,
    30     pub weight: u8,
    30     pub weight: u8,
    31     pub edges: EdgesDescription,
    31     pub edges: EdgesDescription,
       
    32     pub anti_match: Option<[u64; 4]>,
    32     pub is_negative: Option<bool>,
    33     pub is_negative: Option<bool>,
    33     pub can_flip: Option<bool>,
    34     pub can_flip: Option<bool>,
    34     pub can_mirror: Option<bool>,
    35     pub can_mirror: Option<bool>,
    35     pub can_rotate90: Option<bool>,
    36     pub can_rotate90: Option<bool>,
    36     pub can_rotate180: Option<bool>,
    37     pub can_rotate180: Option<bool>,
   128                     }
   129                     }
   129                 }
   130                 }
   130             }
   131             }
   131         }
   132         }
   132 
   133 
   133         let [top_edge, right_edge, bottom_edge, left_edge]: [Edge<String>; 4] = [
   134         let edge_set: EdgeSet<String> = EdgeSet::new([
   134             (&tile_description.edges.top).into(),
   135             (&tile_description.edges.top).into(),
   135             (&tile_description.edges.right).into(),
   136             (&tile_description.edges.right).into(),
   136             (&tile_description.edges.bottom).into(),
   137             (&tile_description.edges.bottom).into(),
   137             (&tile_description.edges.left).into(),
   138             (&tile_description.edges.left).into(),
   138         ];
   139         ]);
   139 
   140 
   140         let tile =
   141         let tile = TileImage::<T, String>::new(
   141             TileImage::<T, String>::new(tiles_image, tile_description.weight, top_edge, right_edge, bottom_edge, left_edge);
   142             tiles_image,
       
   143             tile_description.weight,
       
   144             edge_set,
       
   145             tile_description.anti_match.unwrap_or_default(),
       
   146         );
   142 
   147 
   143         result.push(tile.clone());
   148         result.push(tile.clone());
   144 
   149 
   145         if tile_description.can_flip.unwrap_or_default() {
   150         if tile_description.can_flip.unwrap_or_default() {
   146             result.push(tile.flipped());
   151             result.push(tile.flipped());
   207             let mut bottom = default_connection.clone();
   212             let mut bottom = default_connection.clone();
   208             let mut left = default_connection.clone();
   213             let mut left = default_connection.clone();
   209             let mut top = default_connection.clone();
   214             let mut top = default_connection.clone();
   210 
   215 
   211             let iteration = [
   216             let iteration = [
   212                 (&grid_top_edge, tile.top_edge(), &mut top),
   217                 (&grid_top_edge, tile.edge_set().top(), &mut top),
   213                 (&grid_right_edge, tile.right_edge(), &mut right),
   218                 (&grid_right_edge, tile.edge_set().right(), &mut right),
   214                 (&grid_bottom_edge, tile.bottom_edge(), &mut bottom),
   219                 (&grid_bottom_edge, tile.edge_set().bottom(), &mut bottom),
   215                 (&grid_left_edge, tile.left_edge(), &mut left),
   220                 (&grid_left_edge, tile.edge_set().left(), &mut left),
   216             ];
   221             ];
   217 
   222 
   218             // compatibility with grid edges
   223             // compatibility with grid edges
   219             for (edge, tile_edge, set) in iteration {
   224             for (edge, tile_edge, set) in iteration {
   220                 for (is_compatible, tile) in edge
   225                 for (is_compatible, tile) in edge
   235                     }
   240                     }
   236                 }
   241                 }
   237             }
   242             }
   238 
   243 
   239             // compatibility with itself
   244             // compatibility with itself
   240             if tile.left_edge().is_compatible(tile.right_edge()) {
   245             if tile.is_compatible(&tile, MatchSide::OnLeft) {
   241                 left.insert(Tile::Numbered(i));
   246                 left.insert(Tile::Numbered(i));
   242                 right.insert(Tile::Numbered(i));
   247                 right.insert(Tile::Numbered(i));
   243             }
   248             }
   244 
   249 
   245             if tile.top_edge().is_compatible(tile.bottom_edge()) {
   250             if tile.is_compatible(&tile, MatchSide::OnTop) {
   246                 top.insert(Tile::Numbered(i));
   251                 top.insert(Tile::Numbered(i));
   247                 bottom.insert(Tile::Numbered(i));
   252                 bottom.insert(Tile::Numbered(i));
   248             }
   253             }
   249 
   254 
   250             // compatibility with previously defined tiles
   255             // compatibility with previously defined tiles
   251             for p in 0..i {
   256             for p in 0..i {
   252                 // Check left edge
   257                 // Check left edge
   253                 if tiles[p].left_edge().is_compatible(tile.right_edge()) {
   258                 if tiles[p].is_compatible(&tile, MatchSide::OnLeft) {
   254                     rules[p].left.insert(Tile::Numbered(i));
   259                     rules[p].left.insert(Tile::Numbered(i));
   255                     right.insert(Tile::Numbered(p));
   260                     right.insert(Tile::Numbered(p));
   256                 }
   261                 }
   257 
   262 
   258                 // Check right edge
   263                 // Check right edge
   259                 if tiles[p].right_edge().is_compatible(tile.left_edge()) {
   264                 if tiles[p].is_compatible(&tile, MatchSide::OnRight) {
   260                     rules[p].right.insert(Tile::Numbered(i));
   265                     rules[p].right.insert(Tile::Numbered(i));
   261                     left.insert(Tile::Numbered(p));
   266                     left.insert(Tile::Numbered(p));
   262                 }
   267                 }
   263 
   268 
   264                 // Check top edge
   269                 // Check top edge
   265                 if tiles[p].top_edge().is_compatible(tile.bottom_edge()) {
   270                 if tiles[p].is_compatible(&tile, MatchSide::OnTop) {
   266                     rules[p].top.insert(Tile::Numbered(i));
   271                     rules[p].top.insert(Tile::Numbered(i));
   267                     bottom.insert(Tile::Numbered(p));
   272                     bottom.insert(Tile::Numbered(p));
   268                 }
   273                 }
   269 
   274 
   270                 // Check bottom edge
   275                 // Check bottom edge
   271                 if tiles[p].bottom_edge().is_compatible(tile.top_edge()) {
   276                 if tiles[p].is_compatible(&tile, MatchSide::OnBottom) {
   272                     rules[p].bottom.insert(Tile::Numbered(i));
   277                     rules[p].bottom.insert(Tile::Numbered(i));
   273                     top.insert(Tile::Numbered(p));
   278                     top.insert(Tile::Numbered(p));
   274                 }
   279                 }
   275             }
   280             }
   276 
   281 
   277             let weight = (probability_distribution_factor * 2 * i as i32 / (tiles.len() - 1) as i32
   282             let weight = (probability_distribution_factor * 2 * i as i32 / (tiles.len() - 1) as i32
   278                 + 100
   283                 + 100
   279                 - probability_distribution_factor) as u32;
   284                 - probability_distribution_factor) as u32;
   280 
   285 
   281             rules.push(CollapseRule {
   286             rules.push(CollapseRule {
   282                 weight: weight * tile.weight as u32 + 1,
   287                 weight: weight * tile.weight as u32,
   283                 tile: Tile::Numbered(i),
   288                 tile: Tile::Numbered(i),
   284                 top,
   289                 top,
   285                 right,
   290                 right,
   286                 bottom,
   291                 bottom,
   287                 left,
   292                 left,
   342                                         *tile.get(tile_row, tile_column).unwrap_or(&parameters.zero)
   347                                         *tile.get(tile_row, tile_column).unwrap_or(&parameters.zero)
   343                                 },
   348                                 },
   344                             );
   349                             );
   345                         }
   350                         }
   346                     }
   351                     }
       
   352                 } else {
       
   353                     // couldn't find a tile to place here, dump some debug info for tile set maker
       
   354                     let mut edges = ["-", "|", "-", "|"].map(|s| s.to_owned());
       
   355 
       
   356                     if row > 0 {
       
   357                         let tile = wfc.grid().get(row - 1, column);
       
   358                         edges[0] = if let Some(Tile::Numbered(tile_index)) = tile {
       
   359                             tiles[*tile_index].edge_set().bottom().name()
       
   360                         } else {
       
   361                             format!("{:?}", tile.unwrap())
       
   362                         }
       
   363                     }
       
   364                     if column < wfc_size.width as usize - 1 {
       
   365                         let tile = wfc.grid().get(row, column + 1);
       
   366                         edges[1] = if let Some(Tile::Numbered(tile_index)) = tile {
       
   367                             tiles[*tile_index].edge_set().left().name()
       
   368                         } else {
       
   369                             format!("{:?}", tile.unwrap())
       
   370                         }
       
   371                     }
       
   372                     if row < wfc_size.height as usize - 1 {
       
   373                         let tile = wfc.grid().get(row + 1, column);
       
   374                         edges[2] = if let Some(Tile::Numbered(tile_index)) = tile {
       
   375                             tiles[*tile_index].edge_set().top().name()
       
   376                         } else {
       
   377                             format!("{:?}", tile.unwrap())
       
   378                         }
       
   379                     }
       
   380                     if column > 0 {
       
   381                         let tile = wfc.grid().get(row, column - 1);
       
   382                         edges[3] = if let Some(Tile::Numbered(tile_index)) = tile {
       
   383                             tiles[*tile_index].edge_set().right().name()
       
   384                         } else {
       
   385                             format!("{:?}", tile.unwrap())
       
   386                         }
       
   387                     }
       
   388                     eprintln!(
       
   389                         "Couldn't find a tile to place here (row, column): ({}, {}), edges are: [{}]",
       
   390                         row, column, edges.join(", "),
       
   391                     );
   347                 }
   392                 }
   348             }
   393             }
   349         }
   394         }
   350 
   395 
   351         result
   396         result