1use super::{Generator, PathPoint};
4use banished_core::noise::PerlinNoise;
5
6fn normalize(v: [f32; 2]) -> [f32; 2] {
8 let len = sqrtf(v[0] * v[0] + v[1] * v[1]);
9 if len == 0.0 {
10 return v;
11 }
12 let inv = 1.0 / len;
13 [v[0] * inv, v[1] * inv]
14}
15
16const STAMP_CUTOFF: f32 = 0.99;
18const LAKE_STEEPNESS: f32 = 2.25;
20const HILL_STEEPNESS: f32 = 1.75;
22
23const FIRST_PATH: [f32; 5] = [2.0, 10.0, 1.25, 4.0, 4.0];
25const BRANCH_PATH: [f32; 5] = [1.5, 8.0, 1.25, 1.5, 16.0];
27
28fn crosses(p0: [f32; 2], p1: [f32; 2], q0: [f32; 2], q1: [f32; 2]) -> bool {
31 let (qdy, qdx) = (q1[1] - q0[1], q1[0] - q0[0]);
32 let (pdy, pdx) = (p1[1] - p0[1], p1[0] - p0[0]);
33 let (oy, ox) = (p0[1] - q0[1], p0[0] - q0[0]);
34 let den = pdx * qdy - qdx * pdy;
35 if den == 0.0 {
36 return false;
37 }
38 let ua = (qdx * oy - ox * qdy) / den;
39 let ub = (pdx * oy - ox * pdy) / den;
40 ua > 0.0 && 1.0 > ua && ub > 0.0 && 1.0 > ub
41}
42
43fn sqrtf(x: f32) -> f32 {
44 x.sqrt()
45}
46
47fn powf(base: f32, exp: f32) -> f32 {
49 (base as f64).powf(exp as f64) as f32
50}
51
52impl Generator {
53 pub fn stage1_noise(&mut self) {
58 let w = self.width();
59 self.grid = vec![0.0; w * w];
60 let a = self.rng.rand_tol(0xffffff);
61 let b = self.rng.rand_tol(0xffffff);
62 let near = PerlinNoise::new(0.5, 5.0, b, a);
63 let a = self.rng.rand_tol(0xffffff);
64 let b = self.rng.rand_tol(0xffffff);
65 let far = PerlinNoise::new(0.25, 5.0, b, a);
66 let half = self.size >> 1;
67 let radius = self.size as f32 * 0.25 + 16.0;
68 for y in 0..w as i32 {
69 let dy = (y - half) * (y - half);
70 let (yf, ynear, yfar) = (y as f32, y as f32 * 0.25, y as f32 * 0.1);
71 let _ = yf;
72 for x in 0..w as i32 {
73 let dist = sqrtf(((x - half) * (x - half) + dy) as f32);
74 let p = powf(1.1, -(dist - radius));
75 let weight = 1.0 / (p + 1.0);
76 let g1 = near.generate(x as f32 * 0.25, ynear);
77 let low = (g1 + 1.0) * 8.0;
78 let g2 = far.generate(x as f32 * 0.1, yfar);
79 let mut high = (g2 + 0.25) * 48.0 + g1;
80 if high < 2.0 {
81 high = 2.0;
82 }
83 self.grid[y as usize * w + x as usize] = (1.0 - weight) * low + high * weight;
84 }
85 }
86 }
87
88 pub fn stage2_records(&mut self) {
92 while self.paths.is_empty() {
93 self.build_path(self.size + 1, self.size as f32, FIRST_PATH, -1);
94 }
95 self.place_lakes();
96 for _ in 0..self.record.at(0x20) {
97 for _ in 0..1000 {
98 let idx = self.rng.rand_below(self.paths.len() as u32) as i32;
99 if self.build_path(self.size + 1, self.size as f32, BRANCH_PATH, idx) {
100 break;
101 }
102 }
103 }
104 }
105
106 fn displace(&mut self, pts: &mut [PathPoint], i0: usize, i1: usize, bound: f32, scale: f32) {
108 if i1 - i0 < 2 {
109 return;
110 }
111 let (a, b) = (pts[i0].pos, pts[i1].pos);
112 let mid = [(b[0] + a[0]) * 0.5, (b[1] + a[1]) * 0.5];
113 let d = [b[0] - a[0], b[1] - a[1]];
114 let n = normalize([-d[1], d[0]]);
115 let lo = -bound;
116 let p = loop {
117 let r = self.rng.rand_float_tol() * scale * 0.666;
118 let p = [n[0] * r + mid[0], n[1] * r + mid[1]];
119 let u1 = normalize([b[0] - p[0], b[1] - p[1]]);
120 let u2 = normalize([a[0] - p[0], a[1] - p[1]]);
121 let dot = u2[1] * u1[1] + u1[0] * u2[0];
122 if lo > p[0] || (!(p[0] > lo) && lo > p[1]) {
123 continue;
124 }
125 if p[0] > bound || (!(bound > p[0]) && p[1] > bound) {
126 continue;
127 }
128 if dot > 0.0 {
129 continue;
130 }
131 break p;
132 };
133 let scale = scale * 0.5;
134 let m = ((i1 - i0) >> 1) + i0;
135 pts[m].pos = p;
136 self.displace(pts, i0, m, bound, scale);
137 self.displace(pts, m, i1, bound, scale);
138 }
139
140 fn build_path(&mut self, count: i32, extent: f32, params: [f32; 5], from: i32) -> bool {
144 let count = count as usize;
145 let mut pts = vec![
146 PathPoint {
147 pos: [0.0, 0.0],
148 params
149 };
150 count
151 ];
152 let last = count - 1;
153 if from < 0 {
154 pts[0].pos = [0.0, extent * -0.5];
155 match self.rng.rand_below(3) {
156 0 => pts[last].pos = [0.0, extent * 0.5],
157 1 => pts[last].pos = [extent * 0.5, 0.0],
158 2 => pts[last].pos = [extent * -0.5, 0.0],
159 _ => {}
160 }
161 let a = self.rng.rand_float_tol();
162 let b = self.rng.rand_float_tol();
163 pts[count >> 1].pos = [b * extent * 0.125, a * extent * 0.125];
164 self.displace(&mut pts, 0, count >> 1, extent * 0.5, extent * 0.25);
165 self.displace(&mut pts, count >> 1, last, extent * 0.5, extent * 0.25);
166 } else {
167 let base = &self.paths[from as usize];
168 let q = base.len() as i32 / 4;
169 let k = self.rng.rand_range(q, q * 3);
170 pts[0].pos = self.paths[from as usize][k as usize].pos;
171 let v = self.rng.rand_float_tol() * extent * 0.5;
172 match self.rng.rand_below(4) {
173 0 => pts[last].pos = [v, extent * 0.5],
174 1 => pts[last].pos = [extent * 0.5, v],
175 2 => pts[last].pos = [extent * -0.5, v],
176 3 => pts[last].pos = [v, extent * -0.5],
177 _ => {}
178 }
179 self.displace(&mut pts, 0, last, extent * 0.5, extent * 0.25);
180 }
181
182 for i in 0..count {
184 let (mut best, mut best_j) = (1_000_000.0f32, -2i64);
185 for (j, q) in pts.iter().enumerate() {
186 if i == j {
187 continue;
188 }
189 let d = [pts[i].pos[0] - q.pos[0], pts[i].pos[1] - q.pos[1]];
190 let ls = d[0] * d[0] + d[1] * d[1];
191 if best > ls {
192 best = ls;
193 best_j = j as i64;
194 }
195 }
196 if best_j != i as i64 + 1 && best_j != i as i64 - 1 {
197 return false;
198 }
199 }
200 for i in 0..last {
202 let (p0, p1) = (pts[i].pos, pts[i + 1].pos);
203 for j in 0..last {
204 if j == i || j + 1 == i || j == i + 1 {
205 continue;
206 }
207 if crosses(p0, p1, pts[j].pos, pts[j + 1].pos) {
208 return false;
209 }
210 }
211 for path in &self.paths {
212 for c in 0..path.len().saturating_sub(1) {
213 if crosses(p0, p1, path[c].pos, path[c + 1].pos) {
214 return false;
215 }
216 }
217 }
218 }
219 self.paths.push(pts);
220 true
221 }
222
223 fn place_lakes(&mut self) {
225 let r = self.record;
226 let count = self.rng.rand_below((r.at(0x2c) - r.at(0x28) + 1) as u32) as i32 + r.at(0x28);
227 let depth = self.rng.rand_below((r.at(0x34) - r.at(0x30)) as u32) as i32 + r.at(0x30);
228 let depth_f = depth as f32;
229 let floor = (depth - r.at(0x40)) as f32;
230 let span = ((r.at(0) >> 1) - 2) as f32 - depth_f;
231 let (rmin, rspan) = (r.at(0x3c) as f32, (r.at(0x40) - r.at(0x3c)) as f32);
232 for _ in 0..count {
233 let a = self.rng.rand_float_tol();
234 let b = self.rng.rand_float_tol();
235 let (y, x) = (span * a, b * span);
236 for _ in 0..r.at(0x38) {
237 let radius = self.rng.rand_float() * rspan + rmin;
238 let spread = self.rng.rand_float() * 0.5 + 0.5;
239 let dy = self.rng.rand_float_tol();
240 let reach = depth_f - radius;
241 let dx = self.rng.rand_float_tol();
242 let v = normalize([dx, dy]);
243 self.points
244 .push([reach * v[0] * spread + x, reach * v[1] * spread + y, radius]);
245 }
246 self.points.push([x, y, floor]);
247 self.lakes.push([x, y, depth_f]);
248 }
249 }
250
251 pub fn stage3_shape(&mut self) {
255 self.place_hills();
256 self.rasterise_records();
257 }
258
259 fn place_hills(&mut self) {
262 let r = self.record;
263 let edge = ((r.at(0) >> 1) - 2) as f32;
264 let scatter = |rng: &mut banished_core::random::Random, lo: i32, hi: i32| -> [f32; 3] {
265 let radius = rng.rand_float() * (hi - lo) as f32 + lo as f32;
266 let a = rng.rand_float_tol();
267 let b = rng.rand_float_tol();
268 let span = edge - (radius as i32) as f32;
269 [span * b, span * a, radius]
270 };
271 let mut exclusions: Vec<[f32; 3]> = Vec::new();
273 for _ in 0..r.at(0x10) {
274 exclusions.push(scatter(&mut self.rng, r.at(0x14), r.at(0x18)));
275 }
276 for _ in 0..r.at(0x04) {
277 let c = scatter(&mut self.rng, r.at(0x08), r.at(0x0c));
278 let blocked = exclusions.iter().any(|e| {
279 let d = [c[0] - e[0], c[1] - e[1]];
280 e[2] > sqrtf(d[1] * d[1] + d[0] * d[0]) + c[2]
281 });
282 if !blocked {
283 self.vec28.push(c);
284 }
285 }
286
287 let n = self.vec28.len();
289 let mut labels = vec![-1i32; n];
290 if n == 0 {
291 return;
292 }
293 labels[0] = 0;
294 let mut next = 0i32;
295 for i in 0..n {
296 let mut cur = next;
297 labels[i] = cur;
298 let mut merge = std::collections::BTreeSet::from([cur]);
299 for j in 0..i {
300 let (a, b) = (self.vec28[i], self.vec28[j]);
301 let d = [a[0] - b[0], a[1] - b[1]];
302 let dist = sqrtf(d[1] * d[1] + d[0] * d[0]);
303 if a[2] + b[2] > dist * 1.2 {
304 merge.insert(labels[j]);
305 if labels[j] < cur {
306 cur = labels[j];
307 }
308 }
309 }
310 let mut max = 0;
311 for l in labels.iter_mut().take(i + 1) {
312 if max < *l {
313 max = *l;
314 }
315 if merge.contains(l) {
316 *l = cur;
317 }
318 }
319 next = max + 1;
320 }
321
322 let unique: std::collections::BTreeSet<i32> = labels.iter().copied().collect();
324 let mut groups: Vec<Vec<usize>> = unique
325 .iter()
326 .map(|&l| (0..n).filter(|&c| labels[c] == l).collect())
327 .collect();
328
329 for g in 1..groups.len() {
331 let a = groups[g][self.rng.rand_below(groups[g].len() as u32) as usize];
332 let mut b = groups[0][self.rng.rand_below(groups[0].len() as u32) as usize];
333 let mut best = 1_000_000.0f32;
334 for &c in &groups[0] {
335 let d = [
336 self.vec28[a][0] - self.vec28[c][0],
337 self.vec28[a][1] - self.vec28[c][1],
338 ];
339 let len = sqrtf(d[0] * d[0] + d[1] * d[1]);
340 if best > len {
341 best = len;
342 b = c;
343 }
344 }
345 let delta = [
346 self.vec28[b][0] - self.vec28[a][0],
347 self.vec28[b][1] - self.vec28[a][1],
348 ];
349 let length = sqrtf(delta[0] * delta[0] + delta[1] * delta[1]);
350 let dir = normalize(delta);
351 let mut cur = [self.vec28[a][0], self.vec28[a][1]];
352 let mut t = 0.0f32;
353 while length > t {
354 self.vec28.push([cur[0], cur[1], 10.0]);
355 t += 2.0;
356 cur = [cur[0] + dir[0] * 2.0, cur[1] + dir[1] * 2.0];
357 }
358 let moved = std::mem::take(&mut groups[g]);
359 groups[0].extend(moved);
360 }
361 }
362
363 fn stamp(&self, aux: &mut [f32], at: [f32; 2], r: f32, base: f32, value: f32, raise: bool) {
367 let mut reach = 1.0f32;
368 let mut w = 1.0 / (powf(base, -(1.0 - r)) + 1.0);
369 while STAMP_CUTOFF > w {
370 reach += 1.0;
371 w = 1.0 / (powf(base, -(reach - r)) + 1.0);
372 }
373 let width = self.size + 1;
374 let half = self.size >> 1;
375 let (cx, cy) = (at[0] as i32 + half, at[1] as i32 + half);
376 let ext = reach as i32 + 1;
377 for dy in -ext..=ext {
378 let row = cy + dy;
379 if row < 0 || row >= width {
380 continue;
381 }
382 for dx in -ext..=ext {
383 let col = cx + dx;
384 if col < 0 || col >= width {
385 continue;
386 }
387 let d = sqrtf((dx * dx + dy * dy) as f32);
388 let w = 1.0 / (powf(base, -(d - r)) + 1.0);
389 let cell = &mut aux[(row * width + col) as usize];
390 if raise {
391 let v = (1.0 - w) * value;
392 if v > *cell {
393 *cell = v;
394 }
395 } else {
396 let v = w * value;
397 if *cell > v {
398 *cell = v;
399 }
400 }
401 }
402 }
403 }
404
405 fn rasterise_records(&mut self) {
408 let n = self.grid.len();
409 let (mut carve, mut raise, mut hills) = (vec![1.0f32; n], vec![0.0f32; n], vec![1.0f32; n]);
410 for path in &self.paths {
411 for p in path {
412 let [depth, r1, b1, r2, b2] = p.params;
413 self.stamp(&mut carve, p.pos, r1, b1, 1.0, false);
414 self.stamp(&mut raise, p.pos, r2, b2, depth, true);
415 }
416 }
417 for p in &self.points {
418 self.stamp(&mut raise, [p[0], p[1]], p[2], LAKE_STEEPNESS, 2.0, true);
419 }
420 for c in &self.vec28 {
421 self.stamp(&mut hills, [c[0], c[1]], c[2], HILL_STEEPNESS, 1.0, false);
422 }
423 for i in 0..n {
424 self.grid[i] = carve[i] * self.grid[i] * hills[i] - raise[i];
425 }
426 }
427
428 pub fn stage4_downhill(&mut self) {
434 let w = self.size + 1;
435 for _ in 0..self.record.at(0x24) {
436 let mut x = self.rng.rand_below((w - 2) as u32) as i32 + 1;
437 let mut y = self.rng.rand_below((w - 2) as u32) as i32 + 1;
438 loop {
439 let idx = y * w + x;
440 let h = self.grid[idx as usize];
441 if 0.0 >= h {
442 break;
443 }
444 let (mut low, mut low_idx, mut lx, mut ly) = (h, idx, -1, -1);
445 for ny in [y - 1, y, y + 1] {
446 for nx in [x - 1, x, x + 1] {
447 let v = self.grid[(ny * w + nx) as usize];
448 if low > v {
449 (low, low_idx, lx, ly) = (v, ny * w + nx, nx, ny);
450 }
451 }
452 }
453 let mut d = (h - low) * 0.0625;
454 if d > 0.8 {
455 d = 0.8;
456 }
457 self.grid[idx as usize] = (1.0 - d) * h + d * low;
458 self.grid[low_idx as usize] = (1.0 - d) * low + d * h;
459 if low_idx == idx || lx < 1 || ly < 1 || lx >= w - 1 || ly >= w - 1 {
460 break;
461 }
462 (x, y) = (lx, ly);
463 }
464 }
465 }
466
467 pub fn stage5_smooth(&mut self) {
472 let n = self.grid.len();
473 let (mut carve, mut raise) = (vec![1.0f32; n], vec![0.0f32; n]);
474 for path in &self.paths {
475 for p in path {
476 let [depth, r1, b1, r2, b2] = p.params;
477 self.stamp(&mut carve, p.pos, r1, b1, 1.0, false);
478 self.stamp(&mut raise, p.pos, r2, b2, depth, true);
479 }
480 }
481 for p in &self.points {
482 self.stamp(&mut raise, [p[0], p[1]], p[2], LAKE_STEEPNESS, 2.0, true);
483 }
484 for i in 0..n {
485 self.grid[i] = carve[i] * self.grid[i] - raise[i];
486 }
487 self.blur();
488 self.blur();
489 }
490
491 fn blur(&mut self) {
495 let w = self.size + 1;
496 let clamp = |v: i32| v.clamp(0, w - 1);
497 let mut out = vec![0.0f32; self.grid.len()];
498 for y in 0..self.size {
499 for x in 0..self.size {
500 let at = |gx: i32, gy: i32| self.grid[(clamp(gy) * w + clamp(gx)) as usize];
501 let mut sum = at(x, y) * 2.0;
502 let mut weight = 2.0f32;
503 for dy in [-1, 1] {
504 sum += at(x - 1, y + dy);
505 weight += 1.0;
506 }
507 out[(y * w + x) as usize] = sum / weight;
508 }
509 }
510 self.grid = out;
511 }
512}