5 use png::Decoder; |
5 use png::Decoder; |
6 use std::collections::HashSet; |
6 use std::collections::HashSet; |
7 use std::fs::File; |
7 use std::fs::File; |
8 use std::io::BufReader; |
8 use std::io::BufReader; |
9 |
9 |
10 pub struct WavefrontCollapseLandGenerator {} |
10 pub struct WavefrontCollapseLandGenerator { |
|
11 pub size: Size, |
|
12 } |
11 |
13 |
12 impl WavefrontCollapseLandGenerator { |
14 impl WavefrontCollapseLandGenerator { |
13 pub fn new() -> Self { |
15 pub fn new(size: &Size) -> Self { |
14 Self {} |
16 Self { size: *size } |
15 } |
17 } |
16 |
18 |
17 pub fn load_template<T: Copy + PartialEq + Default>( |
19 pub fn load_template<T: Copy + PartialEq + Default>( |
18 &self, |
20 &self, |
19 parameters: &LandGenerationParameters<T>, |
21 parameters: &LandGenerationParameters<T>, |
47 parameters.basic |
49 parameters.basic |
48 }; |
50 }; |
49 } |
51 } |
50 } |
52 } |
51 |
53 |
52 let top_edge = Edge::new("edge".to_owned(), false); |
54 let top_edge = Edge::new("ef".to_owned(), false); |
53 let right_edge = Edge::new("edge".to_owned(), false); |
55 let right_edge = top_edge.reversed(); |
54 let bottom_edge = Edge::new("edge".to_owned(), false); |
56 let bottom_edge = Edge::new("ee".to_owned(), true); |
55 let left_edge = Edge::new("edge".to_owned(), false); |
57 let left_edge = bottom_edge.clone(); |
56 |
58 |
57 let tile = |
59 let tile = |
58 TileImage::<T, String>::new(tiles_image, top_edge, right_edge, bottom_edge, left_edge); |
60 TileImage::<T, String>::new(tiles_image, top_edge, right_edge, bottom_edge, left_edge); |
59 |
61 |
60 result.push(tile.clone()); |
62 result.push(tile.clone()); |
61 result.push(tile.mirrored()); |
63 result.push(tile.rotated90()); |
|
64 result.push(tile.rotated180()); |
|
65 result.push(tile.rotated270()); |
62 |
66 |
63 result |
67 result |
64 } |
68 } |
65 } |
69 } |
66 |
70 |
80 let mut bottom = default_connection.clone(); |
84 let mut bottom = default_connection.clone(); |
81 let mut left = default_connection.clone(); |
85 let mut left = default_connection.clone(); |
82 let mut top = default_connection.clone(); |
86 let mut top = default_connection.clone(); |
83 |
87 |
84 for p in 0..i { |
88 for p in 0..i { |
85 if tiles[p].left_edge() == tile.right_edge() { |
89 if tiles[p].left_edge().is_compatible(tile.right_edge()) { |
86 rules[p].left.insert(Tile::Numbered(i)); |
90 rules[p].left.insert(Tile::Numbered(i)); |
87 right.insert(Tile::Numbered(p)); |
91 right.insert(Tile::Numbered(p)); |
88 } |
92 } |
89 |
93 |
90 if tiles[p].right_edge() == tile.left_edge() { |
94 if tiles[p].right_edge().is_compatible(tile.left_edge()) { |
91 rules[p].right.insert(Tile::Numbered(i)); |
95 rules[p].right.insert(Tile::Numbered(i)); |
92 left.insert(Tile::Numbered(p)); |
96 left.insert(Tile::Numbered(p)); |
93 } |
97 } |
94 |
98 |
95 if tiles[p].top_edge() == tile.bottom_edge() { |
99 if tiles[p].top_edge().is_compatible(tile.bottom_edge()) { |
96 rules[p].top.insert(Tile::Numbered(i)); |
100 rules[p].top.insert(Tile::Numbered(i)); |
97 bottom.insert(Tile::Numbered(p)); |
101 bottom.insert(Tile::Numbered(p)); |
98 } |
102 } |
99 |
103 |
100 if tiles[p].bottom_edge() == tile.top_edge() { |
104 if tiles[p].bottom_edge().is_compatible(tile.top_edge()) { |
101 rules[p].bottom.insert(Tile::Numbered(i)); |
105 rules[p].bottom.insert(Tile::Numbered(i)); |
102 top.insert(Tile::Numbered(p)); |
106 top.insert(Tile::Numbered(p)); |
103 } |
107 } |
104 } |
108 } |
105 |
109 |
113 } |
117 } |
114 |
118 |
115 let mut wfc = WavefrontCollapse::default(); |
119 let mut wfc = WavefrontCollapse::default(); |
116 wfc.set_rules(rules); |
120 wfc.set_rules(rules); |
117 |
121 |
118 wfc.generate_map(&Size::new(40, 20), |_| {}, random_numbers); |
122 let wfc_size = if let Some(first_tile) = tiles.first() { |
|
123 let tile_size = first_tile.size(); |
|
124 |
|
125 Size::new( |
|
126 self.size.width / tile_size.width, |
|
127 self.size.height / tile_size.height, |
|
128 ) |
|
129 } else { |
|
130 Size::new(1, 1) |
|
131 }; |
|
132 |
|
133 wfc.generate_map(&wfc_size, |_| {}, random_numbers); |
119 |
134 |
120 let grid = wfc.grid(); |
135 let grid = wfc.grid(); |
121 |
136 |
122 for r in 0..grid.height() { |
137 for r in 0..grid.height() { |
123 for c in 0..grid.width() { |
138 for c in 0..grid.width() { |
125 } |
140 } |
126 |
141 |
127 println!(); |
142 println!(); |
128 } |
143 } |
129 |
144 |
130 todo!("build result") |
145 let mut result = land2d::Land2D::new(&self.size, parameters.zero); |
|
146 |
|
147 for row in 0..wfc_size.height { |
|
148 for column in 0..wfc_size.width { |
|
149 if let Some(Tile::Numbered(tile_index)) = wfc.grid().get(row, column) { |
|
150 let tile = &tiles[*tile_index]; |
|
151 |
|
152 for tile_row in 0..tile.size().height { |
|
153 for tile_column in 0..tile.size().width { |
|
154 result.map( |
|
155 (row * tile.size().height + tile_row) as i32, |
|
156 (column * tile.size().width + tile_column) as i32, |
|
157 |p| { |
|
158 *p = |
|
159 *tile.get(tile_row, tile_column).unwrap_or(¶meters.zero) |
|
160 }, |
|
161 ); |
|
162 } |
|
163 } |
|
164 } |
|
165 } |
|
166 } |
|
167 |
|
168 result |
131 } |
169 } |
132 } |
170 } |
133 |
171 |
134 #[cfg(test)] |
172 #[cfg(test)] |
135 mod tests { |
173 mod tests { |
136 use super::WavefrontCollapseLandGenerator; |
174 use super::WavefrontCollapseLandGenerator; |
137 use crate::{LandGenerationParameters, LandGenerator}; |
175 use crate::{LandGenerationParameters, LandGenerator}; |
138 use integral_geometry::Size; |
176 use integral_geometry::Size; |
|
177 use std::fs::File; |
|
178 use std::io::BufWriter; |
|
179 use std::path::Path; |
139 use vec2d::Vec2D; |
180 use vec2d::Vec2D; |
140 |
181 |
141 #[test] |
182 #[test] |
142 fn test_generation() { |
183 fn test_generation() { |
143 let wfc_gen = WavefrontCollapseLandGenerator::new(); |
184 let wfc_gen = WavefrontCollapseLandGenerator::new(&Size::new(2048, 1024)); |
144 let landgen_params = LandGenerationParameters::new(0u8, 255u8, 0, true, true); |
185 let landgen_params = LandGenerationParameters::new(0u32, 0xff000000u32, 0, true, true); |
145 wfc_gen.generate_land(&landgen_params, &mut std::iter::repeat(1u32)); |
186 let land = wfc_gen.generate_land(&landgen_params, &mut std::iter::repeat(0u32)); |
146 } |
187 |
147 } |
188 let path = Path::new(r"output.png"); |
|
189 let file = File::create(path).unwrap(); |
|
190 let ref mut w = BufWriter::new(file); |
|
191 |
|
192 let mut encoder = png::Encoder::new(w, land.width() as u32, land.height() as u32); // Width is 2 pixels and height is 1. |
|
193 encoder.set_color(png::ColorType::Rgba); |
|
194 encoder.set_depth(png::BitDepth::Eight); |
|
195 encoder.set_source_gamma(png::ScaledFloat::from_scaled(45455)); // 1.0 / 2.2, scaled by 100000 |
|
196 encoder.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2)); // 1.0 / 2.2, unscaled, but rounded |
|
197 let source_chromaticities = png::SourceChromaticities::new( |
|
198 // Using unscaled instantiation here |
|
199 (0.31270, 0.32900), |
|
200 (0.64000, 0.33000), |
|
201 (0.30000, 0.60000), |
|
202 (0.15000, 0.06000), |
|
203 ); |
|
204 encoder.set_source_chromaticities(source_chromaticities); |
|
205 let mut writer = encoder.write_header().unwrap(); |
|
206 |
|
207 writer.write_image_data(land.raw_pixel_bytes()).unwrap(); // Save |
|
208 } |
|
209 } |