From 7268c23784e0bb0e20354b5c8b7f5cab701a3725 Mon Sep 17 00:00:00 2001
From: Barney Davis <barneydmedia@gmail.com>
Date: Thu, 19 Sep 2019 12:28:05 -0400
Subject: [PATCH] [WIP] #212 - Multi-threaded NoiseMapBuilder with Rayon

---
 Cargo.toml                     |  4 +++
 src/utils/noise_map_builder.rs | 61 +++++++++++++++++++++-------------
 2 files changed, 42 insertions(+), 23 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 5f60f8a7..ed1384f8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,12 +9,16 @@ license = "Apache-2.0/MIT"
 keywords = ["math", "random"]
 authors = ["The Noise-rs Developers."]
 
+[profile.release]
+debug = true
+
 [lib]
 name = "noise"
 
 [dependencies]
 rand = "0.5"
 image = { version = "0.18", optional = true }
+rayon = "1.2.0"
 
 [features]
 default = ["image"]
diff --git a/src/utils/noise_map_builder.rs b/src/utils/noise_map_builder.rs
index c2feb422..135260e6 100644
--- a/src/utils/noise_map_builder.rs
+++ b/src/utils/noise_map_builder.rs
@@ -1,6 +1,10 @@
+extern crate rayon;
+
 use math::interp;
 use noise_fns::NoiseFn;
 use utils::noise_map::NoiseMap;
+use std::sync::{Arc, RwLock};
+use self::rayon::prelude::*;
 
 pub trait NoiseMapBuilder<'a> {
     fn set_size(self, width: usize, height: usize) -> Self;
@@ -205,34 +209,45 @@ impl<'a> NoiseMapBuilder<'a> for PlaneMapBuilder<'a> {
         let x_step = x_extent / width as f64;
         let y_step = y_extent / height as f64;
 
+        let x_bounds = self.x_bounds;
+        let y_bounds = self.y_bounds;
+        let is_seamless = self.is_seamless;
+
         for y in 0..height {
             let current_y = self.y_bounds.0 + y_step * y as f64;
-
-            for x in 0..width {
-                let current_x = self.x_bounds.0 + x_step * x as f64;
-
-                let final_value = if self.is_seamless {
-                    let sw_value = self.source_module.get([current_x, current_y, 0.0]);
-                    let se_value = self.source_module
-                        .get([current_x + x_extent, current_y, 0.0]);
-                    let nw_value = self.source_module
-                        .get([current_x, current_y + y_extent, 0.0]);
-                    let ne_value =
-                        self.source_module
-                            .get([current_x + x_extent, current_y + y_extent, 0.0]);
-
-                    let x_blend = 1.0 - ((current_x - self.x_bounds.0) / x_extent);
-                    let y_blend = 1.0 - ((current_y - self.y_bounds.0) / y_extent);
-
-                    let y0 = interp::linear(sw_value, se_value, x_blend);
-                    let y1 = interp::linear(nw_value, ne_value, x_blend);
-
-                    interp::linear(y0, y1, y_blend)
+            let locked = RwLock::new(self);
+
+            // split tasks into parallel threads, then collect
+            let final_values: Vec<_> = (0..width).into_par_iter().map(|x| {
+                let current_x = x_bounds.0 + x_step * x as f64;
+                let readable =  locked.read().unwrap();
+
+                let final_value = if is_seamless {
+                  let sw_value = readable.source_module.get([current_x, current_y, 0.0]);
+                  let se_value = readable.source_module
+                    .get([current_x + x_extent, current_y, 0.0]);
+                  let nw_value = readable.source_module
+                    .get([current_x, current_y + y_extent, 0.0]);
+                  let ne_value =
+                    readable.source_module
+                      .get([current_x + x_extent, current_y + y_extent, 0.0]);
+                  let x_blend = 1.0 - ((current_x - x_bounds.0) / x_extent);
+                  let y_blend = 1.0 - ((current_y - y_bounds.0) / y_extent);
+
+                  let y0 = interp::linear(sw_value, se_value, x_blend);
+                  let y1 = interp::linear(nw_value, ne_value, x_blend);
+
+                  interp::linear(y0, y1, y_blend)
                 } else {
-                    self.source_module.get([current_x, current_y, 0.0])
+                  readable.source_module.get([current_x, current_y, 0.0])
                 };
 
-                result_map.set_value(x, y, final_value);
+                final_value
+            }).collect();
+
+            // write results back to data structure
+            for x in 0..width {
+              result_map.set_value(x, y, final_values[x]);
             }
         }