1#![doc = include_str!("../README.md")]
2
3#[cfg(target_arch = "wasm32")]
4use js_sys::{Array, Object, Reflect};
5use rand::Rng;
6use rand_distr::{Beta, Distribution};
7#[cfg(target_arch = "wasm32")]
8use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
9
10#[cfg(target_arch = "wasm32")]
11#[global_allocator]
12static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
13
14pub struct Output {
16 pub data: Vec<Vec<f32>>,
18 pub max: f32,
20 pub min: f32,
22}
23
24#[cfg(not(target_arch = "wasm32"))]
26pub struct Runner {
27 data: Vec<Vec<f32>>,
28 max: f32,
29 min: f32,
30 width: usize,
31 height: usize,
32 depth: f32,
33 rough: f32,
34 side: usize,
35}
36
37#[cfg(target_arch = "wasm32")]
38#[wasm_bindgen]
39pub struct Runner {
40 data: Vec<Vec<f32>>,
41 max: f32,
42 min: f32,
43 width: usize,
44 height: usize,
45 depth: f32,
46 rough: f32,
47 side: usize,
48}
49
50static DEFAULT_WIDTH: usize = 129;
51static DEFAULT_HEIGHT: usize = 129;
52static DEFAULT_DEPTH: f32 = 2000.0;
53static DEFAULT_ROUGH: f32 = 1.0;
54
55#[cfg(target_arch = "wasm32")]
56#[wasm_bindgen]
57impl Runner {
58 #[wasm_bindgen(constructor)]
59 pub fn wasm_new(width: usize, height: usize, depth: Option<f32>, rough: Option<f32>) -> Self {
60 let mut runner = Self::new();
61 runner.set_width(width);
62 runner.set_height(height);
63 if depth.is_some() {
64 runner.set_depth(depth.unwrap());
65 }
66 if rough.is_some() {
67 runner.set_rough(rough.unwrap());
68 }
69 runner
70 }
71
72 #[wasm_bindgen(js_name = ds)]
73 pub fn wasm_ds(&mut self) -> Result<Object, JsValue> {
74 let output = self.ds();
75
76 let data = Array::from(&JsValue::from(
77 output
78 .data
79 .into_iter()
80 .map(|x| {
81 x.into_iter()
82 .map(|v| JsValue::from_f64(v as f64))
83 .collect::<Array>()
84 })
85 .collect::<Array>(),
86 ));
87
88 let obj = Object::new();
89 Reflect::set(&obj, &"data".into(), &data.into())?;
90 Reflect::set(&obj, &"max".into(), &output.max.into())?;
91 Reflect::set(&obj, &"min".into(), &output.min.into())?;
92 Ok(obj)
93 }
94}
95
96impl Runner {
97 pub fn new() -> Self {
99 let mut runner = Self {
100 data: Vec::new(),
101 max: f32::MIN,
102 min: f32::MAX,
103 width: 0,
104 height: 0,
105 depth: DEFAULT_DEPTH,
106 rough: DEFAULT_ROUGH,
107 side: 0,
108 };
109 runner.set_width(DEFAULT_WIDTH);
110 runner.set_height(DEFAULT_HEIGHT);
111 runner
112 }
113
114 pub fn ds(&mut self) -> Output {
117 self.ds_with_rng(&mut rand::thread_rng())
118 }
119
120 pub fn ds_with_rng(&mut self, rng: &mut impl Rng) -> Output {
122 let beta = Beta::new(3.0, 3.0).unwrap();
123 let p = self.side - 1;
124 self.data[0][0] = beta.sample(rng) * self.depth;
125 self.data[0][p] = beta.sample(rng) * self.depth;
126 self.data[p][0] = beta.sample(rng) * self.depth;
127 self.data[p][p] = beta.sample(rng) * self.depth;
128
129 self.shape(self.side as f32, self.side as f32, rng);
130
131 if self.data.len() != self.width {
132 self.data.truncate(self.width);
133 }
134 if self.data[0].len() != self.height {
135 for i in 0..self.width {
136 self.data[i].truncate(self.height);
137 }
138 }
139
140 Output {
141 data: self.data.clone(),
142 max: self.max,
143 min: self.min,
144 }
145 }
146
147 pub fn set_depth(&mut self, depth: f32) {
151 if depth >= 0.0 && depth != self.depth {
152 self.depth = depth;
153 }
154 }
155
156 pub fn set_height(&mut self, height: usize) {
160 if height >= 2 && height != self.height {
161 self.height = height;
162 if self.height > self.width {
163 self.set_side(self.height);
164 }
165 }
166 }
167
168 pub fn set_rough(&mut self, rough: f32) {
171 if rough != self.rough {
172 self.rough = rough;
173 }
174 }
175
176 pub fn set_width(&mut self, width: usize) {
180 if width >= 2 && width != self.width {
181 self.width = width;
182 if self.width > self.height {
183 self.set_side(self.width);
184 }
185 }
186 }
187
188 fn diamond(&mut self, x: f32, y: f32, half_w: f32, half_h: f32, rng: &mut impl Rng) {
189 let mut corners = vec![];
190 if x - half_w > 0.0 {
191 corners.push(self.data[(x - half_w) as usize][y as usize]);
192 }
193 if y - half_h > 0.0 {
194 corners.push(self.data[x as usize][(y - half_h) as usize]);
195 }
196 if x + half_w < self.side as f32 {
197 corners.push(self.data[(x + half_w) as usize][y as usize]);
198 }
199 if y + half_h < self.side as f32 {
200 corners.push(self.data[x as usize][(y + half_h) as usize]);
201 }
202
203 let mut base = 0.0;
204 for v in &corners {
205 base += v;
206 }
207 let n = self.randomize(base / corners.len() as f32, half_w + half_h, rng);
208
209 if (x as usize) < self.width && (y as usize) < self.height {
210 if n < self.min {
211 self.min = n;
212 }
213 if n > self.max {
214 self.max = n;
215 }
216 }
217
218 self.data[x as usize][y as usize] = n;
219 }
220
221 fn is_corner(&self, x: f32, y: f32) -> bool {
222 let p = (self.side - 1) as f32;
223 (x == 0.0 && y == 0.0) || (x == 0.0 && y == p) || (x == p && y == 0.0) || (x == p && y == p)
224 }
225
226 fn randomize(&mut self, base: f32, range: f32, rng: &mut impl Rng) -> f32 {
227 let r: f32 = rng.gen();
228
229 base + (r - base / self.depth) * range * self.rough
230 }
231
232 fn set_side(&mut self, max_side: usize) {
233 let side = if ((max_side - 1) as f32).log2() % 1.0 == 0.0 {
234 max_side
235 } else {
236 let n = (max_side as f32).log2();
237 (2 as usize).pow((n + if n % 1.0 == 0.0 { 0.0 } else { 1.0 }).floor() as u32) + 1
238 };
239 self.side = side;
240 self.data = vec![vec![0.0; side]; side];
241 }
242
243 fn shape(&mut self, size_w: f32, size_h: f32, rng: &mut impl Rng) {
244 if size_w <= 2.0 || size_h <= 2.0 {
245 return;
246 }
247
248 let half_w = (size_w / 2.0).floor();
249 let half_h = (size_h / 2.0).floor();
250 let side = self.side as f32;
251 let mut y = half_h;
252 while y < side {
253 let mut x = half_w;
254 while x < side {
255 if self.is_corner(x, y) {
256 continue;
257 }
258 self.square(x, y, half_w, half_h, rng);
259 x += size_w - 1.0;
260 }
261 y += size_h - 1.0;
262 }
263
264 y = 0.0;
265 while y < side {
266 let mut x = if (y / half_h) % 2.0 == 0.0 {
267 half_w
268 } else {
269 0.0
270 };
271 while x < side {
272 if self.is_corner(x, y) {
273 continue;
274 }
275 self.diamond(x, y, half_w, half_h, rng);
276 x += size_w - 1.0;
277 }
278 y += half_h;
279 }
280
281 self.shape((size_w / 2.0).ceil(), (size_h / 2.0).ceil(), rng);
282 }
283
284 fn square(&mut self, x: f32, y: f32, half_w: f32, half_h: f32, rng: &mut impl Rng) {
285 let base = (self.data[(x - half_w) as usize][(y - half_h) as usize]
286 + self.data[(x + half_w) as usize][(y - half_h) as usize]
287 + self.data[(x + half_w) as usize][(y + half_h) as usize]
288 + self.data[(x - half_w) as usize][(y + half_h) as usize])
289 / 4.0;
290 let n = self.randomize(base, half_w + half_h, rng);
291
292 if (x as usize) < self.width && (y as usize) < self.height {
293 if n < self.min {
294 self.min = n;
295 }
296 if n > self.max {
297 self.max = n;
298 }
299 }
300
301 self.data[x as usize][y as usize] = n;
302 }
303}