banished_terrain/
surface.rs1use super::Generator;
21use banished_core::noise::PerlinNoise;
22
23const NOISE_SCALE: f32 = 0.25;
24const NOISE_OCTAVES: f32 = 4.0;
25const LOW: f32 = -0.5;
26const FLAT: f32 = 0.999;
27const STEEP: f32 = 0.85;
28const SLOPE_RANGE: f32 = FLAT - STEEP;
30const R_HEIGHT: f32 = 8.0;
31const G_HEIGHT: f32 = 7.0;
32const HEIGHT_RAMP: f32 = 3.0;
33const NORMAL_Z: f32 = 2.0;
34
35type Vec3 = [f32; 3];
36
37fn normalize(v: Vec3) -> Vec3 {
39 let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
40 if len == 0.0 {
41 return v;
42 }
43 let inv = 1.0 / len;
44 [v[0] * inv, v[1] * inv, v[2] * inv]
45}
46
47fn dot(a: Vec3, b: Vec3) -> f32 {
48 a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
49}
50
51fn byte(v: f32) -> u32 {
53 (v as i64 as u64 & 0xff) as u32
54}
55
56fn height_ramp(h: f32, from: f32) -> u32 {
58 let t = ((h - from) / HEIGHT_RAMP).clamp(0.0, 1.0);
60 byte(t * 255.0)
61}
62
63struct Cell {
64 pos: Vec3,
65 normal: Vec3,
66}
67
68impl Generator {
69 fn sample(&self, x: i32, y: i32) -> f32 {
70 let hi = self.size;
71 let x = x.clamp(0, hi);
72 let y = y.clamp(0, hi);
73 self.grid[(y * (hi + 1) + x) as usize]
74 }
75
76 fn cell_normal(&self, x: i32, y: i32) -> Vec3 {
78 let dx = self.sample(x + 1, y) - self.sample(x - 1, y);
79 let dy = self.sample(x, y + 1) - self.sample(x, y - 1);
80 normalize([-dx, -dy, NORMAL_Z])
81 }
82
83 pub fn surface_map(&mut self) -> Vec<u32> {
88 let seed_y = self.rng.rand_tol(0xffffff);
89 let seed_x = self.rng.rand_tol(0xffffff);
90 let noise = PerlinNoise::new(NOISE_SCALE, NOISE_OCTAVES, seed_x, seed_y);
91 let n = self.size;
92 let mut cells = Vec::with_capacity((n * n) as usize);
93 for y in 0..n {
94 for x in 0..n {
95 cells.push(Cell {
96 pos: [x as f32, y as f32, self.sample(x, y)],
97 normal: self.cell_normal(x, y),
98 });
99 }
100 }
101
102 let mut out = vec![0u32; (n * n) as usize];
106 let mut rows: Vec<(i32, &mut [u32])> = out
107 .chunks_mut(n as usize)
108 .enumerate()
109 .map(|(y, row)| (y as i32, row))
110 .collect();
111 banished_formats::par::map_mut(&mut rows, |(y, row)| {
112 for x in 0..n {
113 row[x as usize] = surface_texel(&cells, &noise, n, x, *y);
114 }
115 });
116 out
117 }
118}
119
120fn surface_texel(cells: &[Cell], noise: &PerlinNoise, n: i32, x: i32, y: i32) -> u32 {
124 let c = &cells[(y * n + x) as usize];
125 let h = c.pos[2];
126 let up = c.normal[2];
127 let mut r = if LOW <= h {
128 let v = noise.generate(x as f32 * NOISE_SCALE, y as f32 * NOISE_SCALE);
129 let v = v * 0.5 + 0.5;
130 byte(v * v * 255.0)
131 } else {
132 0xff
133 };
134 let mut g = if FLAT > up && up > STEEP {
135 byte((1.0 - (up - STEEP) / SLOPE_RANGE) * 255.0)
136 } else if STEEP >= up {
137 0xff
138 } else {
139 0
140 };
141 if h > R_HEIGHT {
142 r = r.max(height_ramp(h, R_HEIGHT));
143 }
144 if h > G_HEIGHT {
145 g = g.max(height_ramp(h, G_HEIGHT));
146 }
147 let mut occlusion = 0.0f32;
148 let mut count = 0.0f32;
149 let mut smooth = [0.0f32; 3];
150 for dy in -10..10 {
152 let ny = y + dy;
153 if ny < 0 || ny >= n {
154 continue;
155 }
156 for dx in -10..=10 {
157 let nx = x + dx;
158 if nx < 0 || nx >= n || dx * dx + dy * dy > 100 {
159 continue;
160 }
161 let o = &cells[(ny * n + nx) as usize];
162 let dir = normalize([
163 o.pos[0] - c.pos[0],
164 o.pos[1] - c.pos[1],
165 o.pos[2] - c.pos[2],
166 ]);
167 let d = dot(c.normal, dir);
168 occlusion += if d > 0.0 { d } else { 0.0 };
169 count += 1.0;
170 if dx.abs() <= 1 && dy.abs() <= 1 {
171 for (s, n) in smooth.iter_mut().zip(o.normal) {
172 *s += n;
173 }
174 }
175 }
176 }
177 let smooth = normalize(smooth);
178 let b = byte((1.0 - occlusion / count) * smooth[2] * 255.0);
179 ((g & 0xff) << 8 | (r & 0xff)) | b << 16
180}