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() { |