1use std::collections::{BTreeMap, HashMap};
23
24use super::PathPoint;
25
26const CELL_INV: f32 = 0.25;
28
29fn cell(v: f32) -> i32 {
31 (v * CELL_INV) as i32
32}
33
34fn length(v: [f32; 2]) -> f32 {
35 (v[0] * v[0] + v[1] * v[1]).sqrt()
36}
37
38fn dot(a: [f32; 2], b: [f32; 2]) -> f32 {
40 b[1] * a[1] + b[0] * a[0]
41}
42
43fn normalize(v: [f32; 2]) -> [f32; 2] {
45 let l = length(v);
46 if l == 0.0 {
47 return v;
48 }
49 let inv = 1.0 / l;
50 [v[0] * inv, v[1] * inv]
51}
52
53fn sub(a: [f32; 2], b: [f32; 2]) -> [f32; 2] {
54 [a[0] - b[0], a[1] - b[1]]
55}
56
57struct Segment {
59 a: [f32; 2],
60 b: [f32; 2],
61 d: [f32; 2],
62 len: f32,
63 perp: [f32; 2],
64 lo: (i32, i32),
66 hi: (i32, i32),
67}
68
69fn clear_of(segments: &[Segment], p: [f32; 2], w: f32) -> bool {
73 let r = w * 1.1;
74 let lo = (cell(p[0] - r), cell(p[1] - r));
75 let hi = (cell(p[0] + r), cell(p[1] + r));
76 for s in segments {
77 if s.hi.0 < lo.0 || hi.0 < s.lo.0 || s.hi.1 < lo.1 || hi.1 < s.lo.1 {
78 continue;
79 }
80 let da = sub(p, s.a);
81 if w > dot(da, da).sqrt() {
82 return false;
83 }
84 let db = sub(p, s.b);
85 if w > dot(db, db).sqrt() {
86 return false;
87 }
88 let t = dot(da, s.d);
89 if 0.0 < t && t < s.len {
90 let q = [t + (s.a[0] + s.d[0]), t + (s.a[1] + s.d[1])];
91 let e = sub(q, p);
92 if dot(e, e).sqrt() < w {
93 return false;
94 }
95 }
96 }
97 true
98}
99
100#[derive(Default)]
102struct Bank {
103 points: Vec<[f32; 2]>,
104 cells: HashMap<(i32, i32), Vec<usize>>,
105}
106
107impl Bank {
108 fn add(&mut self, p: [f32; 2]) {
109 let i = self.points.len();
110 self.points.push(p);
111 self.cells
112 .entry((cell(p[0]), cell(p[1])))
113 .or_default()
114 .push(i);
115 }
116
117 fn nearest(&self, p: [f32; 2], w: f32, index: &mut usize) -> [f32; 2] {
121 let r = w * 2.0;
122 let lo = (cell(p[0] - r), cell(p[1] - r));
123 let hi = (cell(p[0] + r), cell(p[1] + r));
124 let mut best = 1_000_000.0f32;
125 let mut out = p;
126 for y in lo.1..=hi.1 {
127 for x in lo.0..=hi.0 {
128 let Some(list) = self.cells.get(&(x, y)) else {
129 continue;
130 };
131 for &i in list.iter().rev() {
132 let d = length(sub(p, self.points[i]));
133 if d < best {
134 best = d;
135 *index = i;
136 out = self.points[i];
137 }
138 }
139 }
140 }
141 out
142 }
143
144 fn resample(&self, start: usize, count: usize, total: f32) -> Vec<[f32; 2]> {
146 let pts = &self.points;
147 let step = total / count as f32;
148 let mut seg = start;
149 let mut seg_len = length(sub(pts[seg], pts[seg + 1]));
150 let mut end = seg_len;
151 let mut pos = 0.0f32;
152 let mut out = Vec::with_capacity(count);
153 while out.len() < count {
154 if pos < end {
155 let f = 1.0 - (end - pos) / seg_len;
156 let g = 1.0 - f;
157 out.push([
158 g * pts[seg][0] + f * pts[seg + 1][0],
159 g * pts[seg][1] + f * pts[seg + 1][1],
160 ]);
161 pos += step;
162 } else {
163 seg += 1;
164 if pts.len() <= seg + 1 {
165 break;
166 }
167 seg_len = length(sub(pts[seg], pts[seg + 1]));
168 end += seg_len;
169 }
170 }
171 out
172 }
173
174 fn rows(
177 &self,
178 start: usize,
179 count: usize,
180 total: f32,
181 v_step: f32,
182 v_start: f32,
183 out: &mut Vec<([f32; 2], f32)>,
184 ) {
185 let pts = &self.points;
186 let step = total / count as f32;
187 let mut seg = start;
188 let mut seg_len = length(sub(pts[seg], pts[seg + 1]));
189 let mut end = seg_len;
190 let mut pos = 0.0f32;
191 let mut n = 0;
192 while n < count {
193 if pos < end {
194 let f = 1.0 - (end - pos) / seg_len;
195 let g = 1.0 - f;
196 let p = [
197 g * pts[seg][0] + f * pts[seg + 1][0],
198 g * pts[seg][1] + f * pts[seg + 1][1],
199 ];
200 let v = ((end - g * seg_len) / total) * v_step + v_start;
201 out.push((p, v));
202 pos += step;
203 n += 1;
204 } else {
205 seg += 1;
206 if pts.len() <= seg + 1 {
207 break;
208 }
209 let d = sub(pts[seg], pts[seg + 1]);
210 seg_len = dot(d, d).sqrt();
211 end += seg_len;
212 }
213 }
214 }
215
216 fn walked(&self, from: usize, to: usize) -> f32 {
218 let mut sum = 0.0f32;
219 for m in from..to.saturating_sub(1) {
220 let d = sub(self.points[m], self.points[m + 1]);
221 sum += dot(d, d).sqrt();
222 }
223 sum
224 }
225
226 fn walked_length(&self, from: usize, to: usize) -> f32 {
227 let mut sum = 0.0f32;
228 for m in from..to.saturating_sub(1) {
229 sum += length(sub(self.points[m], self.points[m + 1]));
230 }
231 sum
232 }
233}
234
235pub fn river_strip(path: &[PathPoint]) -> (Vec<[f32; 4]>, Vec<u16>) {
239 let n = path.len();
240 if n < 2 {
241 return (Vec::new(), Vec::new());
242 }
243 let segments: Vec<Segment> = path
245 .windows(2)
246 .map(|w| {
247 let a = [w[0].pos[0] + 0.5, w[0].pos[1] - 0.5];
248 let b = [w[1].pos[0] + 0.5, w[1].pos[1] - 0.5];
249 let diff = sub(b, a);
250 let len = length(diff);
251 let d = normalize(diff);
252 let (min, max) = (
253 [a[0].min(b[0]), a[1].min(b[1])],
254 [a[0].max(b[0]), a[1].max(b[1])],
255 );
256 Segment {
257 a,
258 b,
259 d,
260 len,
261 perp: [-d[1], d[0]],
262 lo: (cell(min[0]), cell(min[1])),
263 hi: (cell(max[0]), cell(max[1])),
264 }
265 })
266 .collect();
267 let w = path[0].params[3] + 2.0;
268 let (mut bank_a, mut bank_b) = (Bank::default(), Bank::default());
269 for i in 0..n.saturating_sub(2) {
270 let s = &segments[i];
271 let next = &segments[i + 1];
272 let steps = ((s.len * 4.0) as i32).max(1);
273 let (dxl, dyl) = (s.d[0] * s.len, s.d[1] * s.len);
274 let (px, py) = (s.perp[0] * w, s.perp[1] * w);
275 for k in 0..=steps {
276 let t = k as f32 / steps as f32;
277 let p = [s.a[0] + dxl * t, dyl * t + s.a[1]];
278 let left = [p[0] - px, p[1] - py];
279 if clear_of(&segments, left, w) {
280 bank_a.add(left);
281 }
282 let right = [px + p[0], py + p[1]];
283 if clear_of(&segments, right, w) {
284 bank_b.add(right);
285 }
286 }
287 let cross = next.d[1] * s.d[0] - next.d[0] * s.d[1];
289 let left_turn = cross > 0.0;
290 let sign = if left_turn { -1.0f32 } else { 1.0 };
291 let cos = next.d[0] * s.d[0] + next.d[1] * s.d[1];
292 let arc = ((banished_core::crt::acosf(cos) * 57.29578 / 90.0 * 20.0) as i32).max(1);
293 for k in 0..arc {
294 let t = k as f32 / arc as f32;
295 let u = 1.0 - t;
296 let p = normalize([
297 u * s.perp[0] + next.perp[0] * t,
298 u * s.perp[1] + next.perp[1] * t,
299 ]);
300 let q = [s.b[0] + p[0] * w * sign, s.b[1] + sign * (p[1] * w)];
301 if clear_of(&segments, q, w) {
302 if left_turn {
303 bank_a.add(q);
304 } else {
305 bank_b.add(q);
306 }
307 }
308 }
309 }
310 let tangents: Vec<[f32; 2]> = (0..n)
312 .map(|i| {
313 let back = if 0 < i {
314 normalize(sub(path[i - 1].pos, path[i].pos))
315 } else {
316 [0.0, 0.0]
317 };
318 let ahead = if i + 1 < n {
319 normalize(sub(path[i].pos, path[i + 1].pos))
320 } else {
321 [0.0, 0.0]
322 };
323 normalize([ahead[0] + back[0], ahead[1] + back[1]])
324 })
325 .collect();
326 let mut rows_a: Vec<([f32; 2], f32)> = Vec::new();
328 let mut rows_b: Vec<([f32; 2], f32)> = Vec::new();
329 let (mut ia, mut ib) = (0usize, 0usize);
330 let (mut ja, mut jb) = (0usize, 0usize);
331 let mut v_acc = -16.0f32;
332 let mut prev_mid = [0.0f32; 2];
333 let mut first = true;
334 for i in 0..n - 1 {
335 for k in 0..4 {
336 let t = k as f32 * 0.25;
337 let u = 1.0 - t;
338 let dir = normalize([
339 u * tangents[i][0] + t * tangents[i + 1][0],
340 u * tangents[i][1] + t * tangents[i + 1][1],
341 ]);
342 let pa = bank_a.nearest(path[i].pos, w, &mut ja);
343 let pb = bank_b.nearest(path[i].pos, w, &mut jb);
344 if ja <= ia || jb <= ib || (ja == 0 && jb == 0) {
345 continue;
346 }
347 if dot(normalize(sub(pa, pb)), dir).abs() >= 0.02 {
348 continue;
349 }
350 let len_a = bank_a.walked(ia, ja);
351 let len_b = bank_b.walked_length(ib, jb);
352 let most = if len_b < len_a { len_a } else { len_b };
353 if len_a < 2.0 && len_b < 2.0 {
354 continue;
355 }
356 let count = (most as i32).max(1);
357 let (step_a, step_b) = (len_a / count as f32, len_b / count as f32);
358 if step_a < 0.001 || step_b < 0.001 {
359 continue;
360 }
361 let count = count as usize;
362 let a = bank_a.resample(ia, count, len_a);
363 let b = bank_b.resample(ib, count, len_b);
364 let mut mid_len = 0.0f32;
365 for m in 0..count - 1 {
366 let next = [
367 0.5 * (a[m + 1][0] + b[m + 1][0]),
368 0.5 * (a[m + 1][1] + b[m + 1][1]),
369 ];
370 let cur = [0.5 * (a[m][0] + b[m][0]), 0.5 * (a[m][1] + b[m][1])];
371 mid_len += length(sub(cur, next));
372 }
373 if !first {
374 let start = [0.5 * (b[0][0] + a[0][0]), 0.5 * (b[0][1] + a[0][1])];
375 v_acc += length(sub(prev_mid, start)) / 32.0;
376 }
377 let last = count - 1;
378 prev_mid = [
379 0.5 * (b[last][0] + a[last][0]),
380 0.5 * (a[last][1] + b[last][1]),
381 ];
382 first = false;
383 let v_step = mid_len / 32.0;
384 bank_a.rows(ia, count, len_a, v_step, v_acc, &mut rows_a);
385 bank_b.rows(ib, count, len_b, v_step, v_acc, &mut rows_b);
386 v_acc = rows_a.last().map_or(v_acc, |r| r.1);
387 ia = ja;
388 ib = jb;
389 }
390 }
391 let mut vertices: Vec<[f32; 4]> = Vec::new();
393 let mut seen: BTreeMap<[u32; 4], u16> = BTreeMap::new();
394 let mut index = |v: [f32; 4], vertices: &mut Vec<[f32; 4]>| -> u16 {
395 let key = v.map(|f| if f == 0.0 { 0 } else { f.to_bits() });
397 *seen.entry(key).or_insert_with(|| {
398 vertices.push(v);
399 (vertices.len() - 1) as u16
400 })
401 };
402 let mut indices = Vec::new();
403 for r in 0..rows_a.len().saturating_sub(1) {
404 let (a0, va0) = rows_a[r];
405 let (a1, va1) = rows_a[r + 1];
406 let (b0, vb0) = rows_b[r];
407 let (b1, vb1) = rows_b[r + 1];
408 let lerp =
409 |p: [f32; 2], q: [f32; 2], t: f32| [p[0] + t * (q[0] - p[0]), p[1] + (q[1] - p[1]) * t];
410 let (mut u0, mut u1) = (0.0f32, 0.25f32);
411 let (mut p0, mut p1, mut s0, mut s1) = (a0, a1, va0, va1);
412 for _ in 0..4 {
413 let q0 = lerp(a0, b0, u1);
414 let q1 = lerp(a1, b1, u1);
415 let t0 = va0 + (vb0 - va0) * u1;
416 let t1 = va1 + (vb1 - va1) * u1;
417 let ia = index([p0[0], p0[1], u0, s0], &mut vertices);
418 let ib = index([q0[0], q0[1], u1, t0], &mut vertices);
419 let ic = index([q1[0], q1[1], u1, t1], &mut vertices);
420 let id = index([p1[0], p1[1], u0, s1], &mut vertices);
421 indices.extend_from_slice(&[ia, ic, ib, ia, id, ic]);
422 u0 = u1;
423 u1 += 0.25;
424 (p0, p1, s0, s1) = (q0, q1, t0, t1);
425 }
426 }
427 (vertices, indices)
428}
429
430#[derive(Debug, Clone, Default, PartialEq)]
438pub struct WaterMesh {
439 pub vertices: Vec<[u8; 16]>,
441 pub indices: Vec<u16>,
443 pub rivers: Vec<[i32; 4]>,
445 pub lakes: Vec<[i32; 4]>,
447}
448
449fn water_vertex(x: i16, y: i16, z: i16, u: i16, v: i16, alpha: u8) -> [u8; 16] {
450 let mut out = [0u8; 16];
451 for (k, s) in [x, y, z, 0, u, v].into_iter().enumerate() {
452 out[2 * k..2 * k + 2].copy_from_slice(&s.to_le_bytes());
453 }
454 out[12] = 0x7f;
455 out[13] = 0x7f;
456 out[14] = alpha;
457 out
458}
459
460pub fn water_mesh(
466 paths: &[Vec<PathPoint>],
467 lakes: &[[f32; 3]],
468 heights: &[i16],
469 size: usize,
470) -> WaterMesh {
471 let mut mesh = WaterMesh::default();
472 for (i, path) in paths.iter().enumerate() {
474 let (vertices, indices) = river_strip(path);
475 mesh.rivers.push([
476 mesh.indices.len() as i32,
477 mesh.vertices.len() as i32,
478 vertices.len() as i32,
479 indices.len() as i32,
480 ]);
481 let z = (-192.0 - i as f32) as i32 as i16;
482 mesh.vertices.extend(vertices.iter().map(|v| {
483 water_vertex(
484 (v[0] * 48.0) as i32 as i16,
485 (v[1] * 48.0) as i32 as i16,
486 z,
487 (v[2] * 1024.0) as i32 as i16,
488 (v[3] * 1024.0) as i32 as i16,
489 0xff,
490 )
491 }));
492 mesh.indices.extend_from_slice(&indices);
493 }
494 let width = size + 1;
495 let half = (size >> 1) as i32;
496 let height = |gx: i32, gy: i32| -> f32 {
497 let (x, y) = (gx.clamp(0, width as i32 - 1), gy.clamp(0, width as i32 - 1));
498 heights[y as usize * width + x as usize] as i32 as f32 * 0.00390625
499 };
500 for (i, lake) in lakes.iter().enumerate() {
501 let [cx, cy, r] = *lake;
502 let outer = r + 2.0;
503 let first_index = mesh.indices.len();
504 let first_vertex = mesh.vertices.len();
505 let (x0, y0) = ((cx - outer) as i32, (cy - outer) as i32);
506 let (x1, y1) = ((cx + outer) as i32, (cy + outer) as i32);
507 let fade = outer - r;
508 let z = (i as f32 - 191.0) as i32 as i16;
509 let mut local: Vec<[u8; 16]> = Vec::new();
510 let mut seen: HashMap<[u8; 16], u16> = HashMap::new();
511 let mut indices = Vec::new();
512 for y in y0..y1 {
513 for x in x0..x1 {
514 let corners = [
515 (x, y, height(half + x, half + y)),
516 (x + 1, y, height(half + 1 + x, half + y)),
517 (x + 1, y + 1, height(half + 1 + x, half + 1 + y)),
518 (x, y + 1, height(half + x, half + 1 + y)),
519 ];
520 let mut above = true;
521 let mut clear = true;
522 let mut alpha = [0.0f32; 4];
523 for (k, &(px, py, pz)) in corners.iter().enumerate() {
524 if pz <= -0.75 {
525 above = false;
526 }
527 let d = [px as f32 - cx, py as f32 - cy, pz - 0.0];
528 let dist = (d[1] * d[1] + d[0] * d[0] + d[2] * d[2]).sqrt();
530 let a = 1.0 - (dist - r) / fade;
531 alpha[k] = if a < 0.0 {
532 0.0
533 } else if 1.0 < a {
534 clear = false;
535 1.0
536 } else {
537 if 0.0 < a {
538 clear = false;
539 }
540 a
541 };
542 }
543 if clear || above {
544 continue;
545 }
546 let mut quad = [0u16; 4];
547 for (k, &(px, py, _)) in corners.iter().enumerate() {
548 let (vx, vy) = (
549 (px as f32 * 48.0) as i32 as i16,
550 (py as f32 * 48.0) as i32 as i16,
551 );
552 let v = water_vertex(vx, vy, z, vx, vy, (alpha[k] * 255.0) as i64 as u8);
553 quad[k] = *seen.entry(v).or_insert_with(|| {
554 local.push(v);
555 (local.len() - 1) as u16
556 });
557 }
558 indices.extend_from_slice(&[quad[0], quad[1], quad[2], quad[0], quad[2], quad[3]]);
559 }
560 }
561 mesh.lakes.push([
562 first_index as i32,
563 first_vertex as i32,
564 local.len() as i32,
565 indices.len() as i32,
566 ]);
567 mesh.vertices.extend(local);
568 mesh.indices.extend(indices);
569 }
570 mesh
571}