1use crate::noise::algorithms::Algorithm as NoiseAlgorithm;
39use crate::noise::Noise;
40use crate::random::algorithms::Algorithm as RandomAlgorithm;
41use crate::random::{Random, Rng};
42use crate::{FPosition, Position, UPosition};
43use ilyvion_util::non_nan::NonNan;
44use impl_ops::*;
45use std::ops::{self, AddAssign, MulAssign};
46
47#[derive(Clone, Debug)]
49#[cfg_attr(
50 feature = "serialization",
51 derive(serde_derive::Serialize, serde_derive::Deserialize)
52)]
53pub struct HeightMap {
54 width: usize,
55 height: usize,
56 values: Vec<f32>,
57}
58
59impl HeightMap {
60 pub fn new(width: usize, height: usize) -> Self {
67 assert!(width > 0 && height > 0);
68
69 Self {
70 width,
71 height,
72 values: vec![0.0; width * height],
73 }
74 }
75
76 pub fn new_with_values(width: usize, height: usize, values: &[f32]) -> Self {
83 assert!(width > 0 && height > 0);
84 assert_eq!(values.len(), width * height);
85
86 Self {
87 width,
88 height,
89 values: values.to_vec(),
90 }
91 }
92
93 pub fn width(&self) -> usize {
95 self.width
96 }
97
98 pub fn height(&self) -> usize {
100 self.height
101 }
102
103 pub fn values(&self) -> &[f32] {
105 &self.values
106 }
107
108 pub fn values_mut(&mut self) -> &mut [f32] {
110 &mut self.values
111 }
112
113 pub fn value(&self, position: UPosition) -> f32 {
119 self.get_value(position.x as usize, position.y as usize)
120 }
121
122 pub fn set_value(&mut self, position: UPosition, value: f32) {
128 self.values[position.x as usize + position.y as usize * self.width] = value;
129 }
130
131 pub fn interpolated_value(&self, position: FPosition) -> f32 {
137 let i_position = position.trunc_u();
138 if i_position.x as usize >= self.width - 1 || i_position.y as usize >= self.height - 1 {
139 self.value(i_position)
140 } else {
141 let dx = position.x - i_position.x as f32;
142 let dy = position.y - i_position.y as f32;
143 let c1 = self.value(i_position);
144 let c2 = self.value(i_position + (1, 0));
145 let c3 = self.value(i_position + (0, 1));
146 let c4 = self.value(i_position + (1, 1));
147 let top = (1.0 - dx) * c1 + dx * c2;
148 let bottom = (1.0 - dx) * c3 + dx * c4;
149
150 (1.0 - dy) * top + dy * bottom
151 }
152 }
153
154 pub fn slope(&self, position: UPosition) -> f32 {
160 const DIX: [i32; 8] = [-1, 0, 1, -1, 1, -1, 0, 1];
161 const DIY: [i32; 8] = [-1, -1, -1, 0, 0, 1, 1, 1];
162
163 let mut min_dy = 0.0;
164 let mut max_dy = 0.0;
165 let v = self.value(position);
166 for (nx, ny) in Iterator::zip(DIX.iter(), DIY.iter())
167 .map(|(&dx, &dy)| (position.x as i32 + dx, position.y as i32 + dy))
168 {
169 if nx >= 0 && nx < self.width as i32 && ny >= 0 && ny <= self.height as i32 {
170 let n_slope = self.get_value(nx as usize, ny as usize) - v;
171 if n_slope > max_dy {
172 max_dy = n_slope;
173 } else if n_slope < min_dy {
174 min_dy = n_slope;
175 }
176 }
177 }
178
179 (max_dy + min_dy).atan2(1.0)
180 }
181
182 pub fn normal(&self, position: FPosition, water_level: f32) -> [f32; 3] {
188 let mut n = [0.0, 0.0, 1.0];
189
190 if position.x >= self.width as f32 - 1.0 || position.y >= self.height as f32 - 1.0 {
191 return n;
192 }
193
194 let mut h0 = self.interpolated_value(position);
195 if h0 < water_level {
196 h0 = water_level;
197 }
198
199 let mut hx = self.interpolated_value(position + (1.0, 0.0));
200 if hx < water_level {
201 hx = water_level;
202 }
203
204 let mut hy = self.interpolated_value(position + (0.0, 1.0));
205 if hy < water_level {
206 hy = water_level;
207 }
208
209 n[0] = 255.0 * (h0 - hx);
210 n[1] = 255.0 * (h0 - hy);
211 n[2] = 16.0;
212
213 let inv_len = 1.0 / (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
215 n[0] *= inv_len;
216 n[1] *= inv_len;
217 n[2] *= inv_len;
218
219 n
220 }
221
222 pub fn count_cells(&self, min: f32, max: f32) -> usize {
224 self.values
225 .iter()
226 .filter(|&&v| v >= min && v <= max)
227 .count()
228 }
229
230 pub fn has_land_on_border(&self, water_level: f32) -> bool {
233 for x in 0..self.width {
234 if self.get_value(x, 0) > water_level
235 || self.get_value(x, self.height - 1) > water_level
236 {
237 return true;
238 }
239 }
240 for y in 0..self.height {
241 if self.get_value(0, y) > water_level || self.get_value(self.width - 1, y) > water_level
242 {
243 return true;
244 }
245 }
246
247 false
248 }
249
250 pub fn min_max(&self) -> MinMax {
252 self.values
253 .iter()
254 .fold((std::f32::MAX, std::f32::MIN), |(min, max), &v| {
255 (min.min(v), max.max(v))
256 })
257 .into()
258 }
259
260 pub fn clamp(&mut self, min: f32, max: f32) {
266 assert!(min <= max);
267
268 self.values
269 .iter_mut()
270 .for_each(|v| *v = v.max(min).min(max))
271 }
272
273 pub fn normalize(&mut self, min: f32, max: f32) {
292 assert!(min <= max);
293
294 let MinMax {
295 min: cur_min,
296 max: cur_max,
297 } = self.min_max();
298
299 let inv_max = if cur_max - cur_min == 0.0 {
300 0.0
301 } else {
302 (f64::from(max) - f64::from(min)) / (f64::from(cur_max) - f64::from(cur_min))
303 };
304
305 self.values.iter_mut().for_each(|v| {
307 *v = (f64::from(min) + (f64::from(*v) - f64::from(cur_min)) * inv_max) as f32
308 });
309 }
310
311 pub fn clear(&mut self) {
313 for v in &mut self.values {
314 *v = 0.0;
315 }
316 }
317
318 pub fn lerp(&self, other: &Self, coefficient: f32) -> Self {
320 assert_eq!(self.width, other.width);
321 assert_eq!(self.height, other.height);
322 assert!(coefficient >= 0.0 && coefficient <= 1.0);
323
324 let mut result = Self::new(self.width, self.height);
325 for (v, (&sv, &ov)) in result
326 .values
327 .iter_mut()
328 .zip(Iterator::zip(self.values.iter(), other.values.iter()))
329 {
330 *v = sv + (ov - sv) * coefficient;
331 }
332
333 result
334 }
335
336 pub fn add_hill(&mut self, position: FPosition, radius: f32, height: f32) {
339 let radius2 = radius * radius;
340 let coefficient = height / radius2;
341
342 let min_x = (position.x - radius).max(0.0) as usize;
343 let max_x = (position.x + radius).min(self.width as f32) as usize;
344 let min_y = (position.y - radius).max(0.0) as usize;
345 let max_y = (position.y + radius).min(self.height as f32) as usize;
346
347 for x in min_x..max_x {
348 let x_dist = (x as f32 - position.x) * (x as f32 - position.x);
349 for y in min_y..max_y {
350 let z = radius2 - x_dist - (y as f32 - position.y) * (y as f32 - position.y);
351 if z > 0.0 {
352 *self.get_value_mut(x, y) += z * coefficient;
353 }
354 }
355 }
356 }
357
358 pub fn dig_hill(&mut self, position: FPosition, radius: f32, height: f32) {
362 let radius2 = radius * radius;
363 let coefficient = height / radius2;
364
365 let min_x = (position.x - radius).max(0.0) as usize;
366 let max_x = (position.x + radius).min(self.width as f32) as usize;
367 let min_y = (position.y - radius).max(0.0) as usize;
368 let max_y = (position.y + radius).min(self.height as f32) as usize;
369
370 for x in min_x..max_x {
371 let x_dist = (x as f32 - position.x) * (x as f32 - position.x);
372 for y in min_y..max_y {
373 let dist = x_dist + (y as f32 - position.y) * (y as f32 - position.y);
374 if dist < radius2 {
375 let z = (radius2 - dist) * coefficient;
376 let value = self.get_value_mut(x, y);
377 if height > 0.0 {
378 if *value < z {
379 *value = z;
380 }
381 } else if *value > 0.0 {
382 *value = z;
383 }
384 }
385 }
386 }
387 }
388
389 pub fn dig_bezier(
393 &mut self,
394 positions: [UPosition; 4],
395 start_radius: f32,
396 start_depth: f32,
397 end_radius: f32,
398 end_depth: f32,
399 ) {
400 let mut x_from = positions[0].x as usize;
401 let mut y_from = positions[0].y as usize;
402
403 let mut t = 0.0_f32;
404 while t <= 1.0 {
405 let it = 1.0 - t;
406
407 let x_to = (positions[0].x as f32 * it * it * it
408 + 3.0 * positions[1].x as f32 * t * it * it
409 + 3.0 * positions[2].x as f32 * t * t * it
410 + positions[3].x as f32 * t * t * t) as usize;
411 let y_to = (positions[0].y as f32 * it * it * it
412 + 3.0 * positions[1].y as f32 * t * it * it
413 + 3.0 * positions[2].y as f32 * t * t * it
414 + positions[3].y as f32 * t * t * t) as usize;
415
416 if x_to != x_from || y_to != y_from {
417 let radius = start_radius + (end_radius - start_radius) * t;
418 let depth = start_depth + (end_depth - start_depth) * t;
419 self.dig_hill((x_to as f32, y_to as f32).into(), radius, depth);
420 x_from = x_to;
421 y_from = y_to;
422 }
423
424 t += 0.001;
425 }
426 }
427
428 pub fn rain_erosion<A: RandomAlgorithm>(
436 &mut self,
437 mut drops: u32,
438 erosion_coefficient: f32,
439 aggregation_coefficient: f32,
440 random: &mut Random<A>,
441 ) {
442 const DX: [i32; 8] = [-1, 0, 1, -1, 1, -1, 0, 1];
443 const DY: [i32; 8] = [-1, -1, -1, 0, 0, 1, 1, 1];
444
445 while drops > 0 {
446 let mut cur_x = random.get_i32(0, (self.width - 1) as i32);
447 let mut cur_y = random.get_i32(0, (self.height - 1) as i32);
448 let mut slope;
449 let mut sediment = 0.0;
450
451 loop {
452 let mut next_x = 0;
453 let mut next_y = 0;
454 let v = self.get_value(cur_x as usize, cur_y as usize);
455 slope = 0.0;
456 for (nx, ny) in
457 Iterator::zip(DX.iter(), DY.iter()).map(|(&dx, &dy)| (cur_x + dx, cur_y + dy))
458 {
459 if nx >= 0 && nx < self.width as i32 && ny >= 0 && ny < self.height as i32 {
460 let n_slope = v - self.get_value(nx as usize, ny as usize);
461 if n_slope > slope {
462 slope = n_slope;
463 next_x = nx;
464 next_y = ny;
465 }
466 }
467 }
468 if slope > 0.0 {
469 *self.get_value_mut(cur_x as usize, cur_y as usize) -=
470 erosion_coefficient * slope;
471 cur_x = next_x;
472 cur_y = next_y;
473 sediment += slope;
474 } else {
475 *self.get_value_mut(cur_x as usize, cur_y as usize) +=
476 aggregation_coefficient * sediment;
477 }
478
479 if slope <= 0.0 {
480 break;
481 }
482 }
483 drops -= 1;
484 }
485 }
486
487 pub fn kernel_transform(&mut self, cells: &[NeighborCell], min_level: f32, max_level: f32) {
506 for x in 0..self.width {
507 let mut offset = x;
508 for y in 0..self.height {
509 if self.values[offset] >= min_level && self.values[offset] <= max_level {
510 let mut val = 0.0;
511 let mut total_weight = 0.0;
512 for cell in cells {
513 let nx = x as i32 + cell.relative_position.x;
514 let ny = y as i32 + cell.relative_position.y;
515 if nx >= 0 && nx < self.width as i32 && ny >= 0 && ny < self.height as i32 {
516 val += f64::from(cell.weight)
517 * f64::from(self.get_value(nx as usize, ny as usize));
518 total_weight += f64::from(cell.weight);
519 }
520 }
521 self.values[offset] = (val / total_weight) as f32;
522 }
523 offset += self.width;
524 }
525 }
526 }
527
528 pub fn add_voronoi<A: RandomAlgorithm>(
530 &mut self,
531 sites: usize,
532 coefficients: &[f32],
533 random: &mut Random<A>,
534 ) {
535 struct Point {
536 x: i32,
537 y: i32,
538 dist: NonNan<f32>,
539 }
540
541 assert!(sites >= coefficients.len());
542
543 let mut points = Vec::with_capacity(sites);
544 for _ in 0..sites {
545 points.push(Point {
546 x: random.get_i32(0, (self.width - 1) as i32),
547 y: random.get_i32(0, (self.height - 1) as i32),
548 dist: 0.0.into(),
549 });
550 }
551 for x in 0..self.width {
552 let mut offset = x;
553 for y in 0..self.height {
554 for point in &mut points {
556 point.dist = ((point.x - x as i32) as f32 * (point.x - x as i32) as f32
557 + (point.y - y as i32) as f32 * (point.y - y as i32) as f32)
558 .into();
559 }
560 for coefficient in coefficients {
561 let min_dist_point = points.iter_mut().min_by_key(|p| p.dist).unwrap();
562 self.values[offset] += coefficient * *min_dist_point.dist;
563 min_dist_point.dist = std::f32::MAX.into();
564 }
565 offset += self.width;
566 }
567 }
568 }
569
570 pub fn mid_point_displacement<A: RandomAlgorithm>(
581 &mut self,
582 random: &mut Random<A>,
583 roughness: f32,
584 ) {
585 let mut step = 1;
586 let mut offset = 1.0;
587 let init_sz = self.width.min(self.height);
588 let mut sz = init_sz;
589 self.values[0] = random.get_f32(0.0, 1.0);
590 self.values[sz - 1] = random.get_f32(0.0, 1.0);
591 self.values[(sz - 1) * sz] = random.get_f32(0.0, 1.0);
592 self.values[sz * sz - 1] = random.get_f32(0.0, 1.0);
593 while sz > 0 {
594 for x in 0..step {
596 for y in 0..step {
597 let diamond_x = sz / 2 + x * sz;
598 let diamond_y = sz / 2 + y * sz;
599
600 let mut z = self.get_value(x * sz, y * sz);
601 z += self.get_value((x + 1) * sz, y * sz);
602 z += self.get_value((x + 1) * sz, (y + 1) * sz);
603 z += self.get_value(x * sz, (y + 1) * sz);
604 z *= 0.25;
605
606 self.set_mpd_height(random, diamond_x, diamond_y, z, offset);
607 }
608 }
609 offset *= roughness;
610
611 for x in 0..step {
613 for y in 0..step {
614 let diamond_x = sz / 2 + x * sz;
615 let diamond_y = sz / 2 + y * sz;
616
617 self.set_mdp_height_square(
619 random,
620 diamond_x,
621 diamond_y - sz / 2,
622 init_sz,
623 sz / 2,
624 offset,
625 );
626 self.set_mdp_height_square(
628 random,
629 diamond_x,
630 diamond_y + sz / 2,
631 init_sz,
632 sz / 2,
633 offset,
634 );
635 self.set_mdp_height_square(
637 random,
638 diamond_x - sz / 2,
639 diamond_y,
640 init_sz,
641 sz / 2,
642 offset,
643 );
644 self.set_mdp_height_square(
646 random,
647 diamond_x + sz / 2,
648 diamond_y,
649 init_sz,
650 sz / 2,
651 offset,
652 );
653 }
654 }
655 sz /= 2;
656 step *= 2;
657 }
658 }
659
660 pub fn add_fbm<A: NoiseAlgorithm>(
670 &mut self,
671 noise: &mut Noise<A>,
672 octaves: f32,
673 coordinates: FbmCoordinateParameters,
674 delta: f32,
675 scale: f32,
676 ) {
677 assert_eq!(
678 noise.dimensions, 2,
679 "add_fbm requires a 2D noise generator."
680 );
681
682 let x_coefficient = coordinates.mul_x / self.width as f32;
683 let y_coefficient = coordinates.mul_y / self.height as f32;
684
685 for x in 0..self.width {
686 let mut f = [0.0; 2];
687 let mut offset = x;
688 f[0] = (x as f32 + coordinates.add_x) * x_coefficient;
689 for y in 0..self.height {
690 f[1] = (y as f32 + coordinates.add_y) * y_coefficient;
691 let value = delta + noise.fbm(&f, octaves) * scale;
692 self.values[offset] += value;
693 offset += self.width;
694 }
695 }
696 }
697
698 pub fn scale_fbm<A: NoiseAlgorithm>(
710 &mut self,
711 noise: &mut Noise<A>,
712 coordinates: FbmCoordinateParameters,
713 octaves: f32,
714 delta: f32,
715 scale: f32,
716 ) {
717 assert_eq!(
718 noise.dimensions, 2,
719 "scale_fbm requires a 2D noise generator."
720 );
721
722 let x_coefficient = coordinates.mul_x / self.width as f32;
723 let y_coefficient = coordinates.mul_y / self.height as f32;
724
725 for x in 0..self.width {
726 let mut f = [0.0; 2];
727 let mut offset = x;
728 f[0] = (x as f32 + coordinates.add_x) * x_coefficient;
729 for y in 0..self.height {
730 f[1] = (y as f32 + coordinates.add_y) * y_coefficient;
731 let value = delta + noise.fbm(&f, octaves) * scale;
732 self.values[offset] *= value;
733 offset += self.width;
734 }
735 }
736 }
737
738 #[inline]
739 fn get_value(&self, x: usize, y: usize) -> f32 {
740 assert!(x < self.width);
741 assert!(y < self.height);
742
743 self.values[x + y * self.width]
744 }
745
746 #[inline]
747 fn get_value_mut(&mut self, x: usize, y: usize) -> &mut f32 {
748 assert!(x < self.width);
749 assert!(y < self.height);
750
751 &mut self.values[x + y * self.width]
752 }
753
754 fn set_mdp_height_square<A: RandomAlgorithm>(
755 &mut self,
756 random: &mut Random<A>,
757 x: usize,
758 y: usize,
759 init_sz: usize,
760 sz: usize,
761 offset: f32,
762 ) {
763 let mut z = 0.0;
764 let mut count = 0;
765 if y >= sz {
766 z += self.get_value(x, y - sz);
767 count += 1;
768 }
769 if x >= sz {
770 z += self.get_value(x - sz, y);
771 count += 1;
772 }
773 if y + sz < init_sz {
774 z += self.get_value(x, y + sz);
775 count += 1;
776 }
777 if x + sz < init_sz {
778 z += self.get_value(x + sz, y);
779 count += 1;
780 }
781 z /= count as f32;
782 self.set_mpd_height(random, x, y, z, offset);
783 }
784
785 fn set_mpd_height<A: RandomAlgorithm>(
786 &mut self,
787 random: &mut Random<A>,
788 x: usize,
789 y: usize,
790 mut z: f32,
791 offset: f32,
792 ) {
793 z += random.get_f32(-offset, offset);
794 *self.get_value_mut(x, y) = z;
795 }
796}
797
798impl_op_ex!(+ |a: &HeightMap, b: &HeightMap| -> HeightMap {
799 assert_eq!(a.width, b.width);
800 assert_eq!(a.height, b.height);
801
802 let mut result = a.clone();
803 for (r, &o) in result.values.iter_mut().zip(b.values.iter()) {
804 *r += o
805 }
806
807 result
808});
809
810impl AddAssign<f32> for HeightMap {
811 fn add_assign(&mut self, rhs: f32) {
812 self.values.iter_mut().for_each(|v| *v += rhs);
813 }
814}
815
816impl_op_ex!(*|a: &HeightMap, b: &HeightMap| -> HeightMap {
817 assert_eq!(a.width, b.width);
818 assert_eq!(a.height, b.height);
819
820 let mut result = a.clone();
821 for (r, &o) in result.values.iter_mut().zip(b.values.iter()) {
822 *r *= o
823 }
824
825 result
826});
827
828impl MulAssign<f32> for HeightMap {
829 fn mul_assign(&mut self, rhs: f32) {
830 self.values.iter_mut().for_each(|v| *v *= rhs);
831 }
832}
833
834#[derive(Copy, Clone, Debug)]
836pub struct MinMax {
837 pub min: f32,
839 pub max: f32,
841}
842
843impl From<(f32, f32)> for MinMax {
844 fn from((min, max): (f32, f32)) -> Self {
845 Self { min, max }
846 }
847}
848
849#[derive(Copy, Clone, Debug)]
851pub struct NeighborCell {
852 pub relative_position: Position,
856
857 pub weight: f32,
860}
861
862#[derive(Copy, Clone, Debug)]
864pub struct FbmCoordinateParameters {
865 pub mul_x: f32,
867 pub mul_y: f32,
869 pub add_x: f32,
871 pub add_y: f32,
873}