From 7e88ebbfc10ca912c5ba5a5d6111c3d86192931b Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 8 Dec 2024 04:17:37 +0100 Subject: [PATCH] Initial material visualizer --- Cargo.lock | 344 +++++++++++++++++- Cargo.toml | 2 +- ray-tracing-core/src/material.rs | 1 + ray-tracing-material-visualizer/Cargo.toml | 11 + .../src/bin/plot.rs | 13 + ray-tracing-material-visualizer/src/lib.rs | 220 +++++++++++ 6 files changed, 584 insertions(+), 7 deletions(-) create mode 100644 ray-tracing-material-visualizer/Cargo.toml create mode 100644 ray-tracing-material-visualizer/src/bin/plot.rs create mode 100644 ray-tracing-material-visualizer/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 208e791..4f631e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,6 +85,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.18" @@ -401,6 +416,20 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "clap" version = "4.5.21" @@ -506,7 +535,20 @@ dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", "libc", ] @@ -521,6 +563,18 @@ dependencies = [ "libc", ] +[[package]] +name = "core-text" +version = "20.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" +dependencies = [ + "core-foundation", + "core-graphics 0.23.2", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -570,6 +624,27 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -602,6 +677,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dwrote" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70182709525a3632b2ba96b6569225467b18ecb4a77f46d255f713a6bebf05fd" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "ecolor" version = "0.24.1" @@ -741,13 +828,65 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + +[[package]] +name = "font-kit" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64b34f4efd515f905952d91bc185039863705592c0c53ae6d979805dd154520" +dependencies = [ + "bitflags 2.6.0", + "byteorder", + "core-foundation", + "core-graphics 0.23.2", + "core-text", + "dirs", + "dwrote", + "float-ord", + "freetype-sys", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", ] [[package]] @@ -756,6 +895,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -765,6 +910,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "freetype-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -786,6 +942,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gif" version = "0.13.1" @@ -840,6 +1006,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -989,7 +1178,7 @@ dependencies = [ "byteorder", "color_quant", "exr", - "gif", + "gif 0.13.1", "jpeg-decoder", "num-traits", "png", @@ -1007,7 +1196,7 @@ dependencies = [ "byteorder-lite", "color_quant", "exr", - "gif", + "gif 0.13.1", "image-webp", "num-traits", "png", @@ -1666,6 +1855,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "orbclient" version = "0.3.48" @@ -1681,7 +1876,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" dependencies = [ - "ttf-parser", + "ttf-parser 0.25.0", ] [[package]] @@ -1719,6 +1914,25 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf07ef4804cfa9aea3b04a7bbdd5a40031dbb6b4f2cbaf2b011666c80c5b4f2" +dependencies = [ + "rustc_version", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1731,6 +1945,52 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "chrono", + "font-kit", + "image 0.24.9", + "lazy_static", + "num-traits", + "pathfinder_geometry", + "plotters-backend", + "plotters-bitmap", + "plotters-svg", + "ttf-parser 0.20.0", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-bitmap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ce181e3f6bf82d6c1dc569103ca7b1bd964c60ba03d7e6cdfbb3e3eb7f7405" +dependencies = [ + "gif 0.12.0", + "image 0.24.9", + "plotters-backend", +] + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "png" version = "0.17.14" @@ -1944,6 +2204,17 @@ dependencies = [ "ray-tracing-core", ] +[[package]] +name = "ray-tracing-material-validator" +version = "0.1.0" +dependencies = [ + "plotters", + "rand", + "ray-tracing-core", + "ray-tracing-material", + "rayon", +] + [[package]] name = "ray-tracing-renderer" version = "0.1.0" @@ -2013,6 +2284,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.11.1" @@ -2063,6 +2345,15 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.41" @@ -2116,6 +2407,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.215" @@ -2488,6 +2785,12 @@ dependencies = [ "winnow 0.6.20", ] +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + [[package]] name = "ttf-parser" version = "0.25.0" @@ -2854,6 +3157,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -3078,7 +3390,7 @@ dependencies = [ "bitflags 1.3.2", "cfg_aliases", "core-foundation", - "core-graphics", + "core-graphics 0.22.3", "dispatch", "instant", "libc", @@ -3121,6 +3433,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "write16" version = "1.0.0" @@ -3179,6 +3500,17 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index d581d3f..98fc3a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-material", "ray-tracing-renderer", "ray-tracing-scene", "ray-tracing-tev", "ray-tracing-egui"] +members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-material", "ray-tracing-renderer", "ray-tracing-scene", "ray-tracing-tev", "ray-tracing-egui", "ray-tracing-material-visualizer"] resolver = "2" diff --git a/ray-tracing-core/src/material.rs b/ray-tracing-core/src/material.rs index 31498e4..fcee353 100644 --- a/ray-tracing-core/src/material.rs +++ b/ray-tracing-core/src/material.rs @@ -12,6 +12,7 @@ pub trait Material: Sync + Debug { } } +#[derive(Debug)] pub struct SampleResult { w_out: Dir3, color: Color, diff --git a/ray-tracing-material-visualizer/Cargo.toml b/ray-tracing-material-visualizer/Cargo.toml new file mode 100644 index 0000000..04b7151 --- /dev/null +++ b/ray-tracing-material-visualizer/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ray-tracing-material-validator" +version = "0.1.0" +edition = "2021" + +[dependencies] +plotters = "0.3.7" +rand = { version = "0.8.5", features = ["small_rng"] } +ray-tracing-core = { path = "../ray-tracing-core" } +ray-tracing-material = { path = "../ray-tracing-material" } +rayon = "1.10.0" diff --git a/ray-tracing-material-visualizer/src/bin/plot.rs b/ray-tracing-material-visualizer/src/bin/plot.rs new file mode 100644 index 0000000..1f2b5ee --- /dev/null +++ b/ray-tracing-material-visualizer/src/bin/plot.rs @@ -0,0 +1,13 @@ +use ray_tracing_core::color::Color; +use ray_tracing_material::{diffuse::DiffuseMaterial, mirror::Mirror}; +use ray_tracing_material_validator::generate_chart; + +fn main() -> Result<(), Box> { + let m = Mirror::new(Color::new(1.0, 1.0, 1.0)); + generate_chart("mirror.png", &m, 2)?; + + let m = DiffuseMaterial::new(Color::new(1.0, 1.0, 1.0)); + generate_chart("diffuse.png", &m, 100)?; + + Ok(()) +} diff --git a/ray-tracing-material-visualizer/src/lib.rs b/ray-tracing-material-visualizer/src/lib.rs new file mode 100644 index 0000000..d6d8d94 --- /dev/null +++ b/ray-tracing-material-visualizer/src/lib.rs @@ -0,0 +1,220 @@ +use std::ops::RangeBounds; + +use plotters::{coord::Shift, prelude::*, style::RelativeSize}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; +use ray_tracing_core::prelude::*; +use rayon::prelude::*; + +pub fn generate_chart>( + path: impl AsRef, + m: &M, + samples_per_pixel: usize, +) -> Result<(), Box> { + let root = BitMapBackend::new(&path, (800, 800)).into_drawing_area(); + + plot_material_sample(&root, m, samples_per_pixel)?; + + root.present()?; + + Ok(()) +} + +fn plot_material_sample>( + root: &DrawingArea, + m: &M, + samples_per_pixel: usize, +) -> Result<(), Box> +where + DB::ErrorType: 'static, +{ + root.fill(&WHITE)?; + + let (upper, lower) = root.split_horizontally(RelativeSize::Width(0.5)); + + let mut upper_chart = ChartBuilder::on(&upper) + .margin(5) + .x_label_area_size(30) + .top_x_label_area_size(30) + .y_label_area_size(30) + .right_y_label_area_size(30) + .caption("Upper Hemisphere", ("sans-serif", 20)) + .build_cartesian_2d(-1.0..1.0, -1.0..1.0)?; + + upper_chart + .configure_mesh() + .disable_x_mesh() + .disable_y_mesh() + .draw()?; + + let upper_area = upper_chart.plotting_area(); + + let mut lower_chart = ChartBuilder::on(&lower) + .margin(5) + .x_label_area_size(30) + .top_x_label_area_size(30) + .y_label_area_size(30) + .right_y_label_area_size(30) + .caption("Lower Hemisphere", ("sans-serif", 20)) + .build_cartesian_2d(-1.0..1.0, -1.0..1.0)?; + + lower_chart + .configure_mesh() + .disable_x_mesh() + .disable_y_mesh() + .draw()?; + + let lower_area = lower_chart.plotting_area(); + + let (xrange, yrange) = upper_area.get_pixel_range(); + let width = (xrange.end - xrange.start) as usize - 1; + let height = (yrange.end - yrange.start) as usize - 1; + + let histogram = create_historgram( + m, + width, + height, + samples_per_pixel * width * height, + Dir3::new(1.0, 1.0, 0.0).normalize(), + 0, + ); + + let map = ViridisRGB; + + let max = histogram.max(); + + for (dir, f) in histogram.iter() { + let color = map.get_color_normalized(f, 0.0, max); + if dir.y() < 0.0 { + lower_area.draw_pixel((dir.x() as f64, dir.z() as f64), &color)?; + } else { + upper_area.draw_pixel((dir.x() as f64, dir.z() as f64), &color)?; + } + } + + Ok(()) +} + +struct Histogram { + data: Vec, + inserted: usize, + width: usize, + height: usize, + max: f32, +} + +impl Histogram { + fn new(width: usize, height: usize) -> Self { + Self { + data: vec![0.0; 2 * width * height], + inserted: 0, + width, + height, + max: 0.0, + } + } + + fn discretize(&self, p: Dir3) -> usize { + (((p.x() + 1.0) * 0.5 * self.width as f32).floor() as usize) + + (((p.z() + 1.0) * 0.5 * self.height as f32).floor() as usize) * self.width + + if p.y() < 0.0 { + 2 * self.width * self.height + } else { + 0 + } + } + + fn insert(&mut self, pos: Dir3, value: f32) { + let index = self.discretize(pos); + self.data[index] += value; + self.max = f32::max(self.max, self.data[index]); + self.inserted += 1; + } + + fn max(&self) -> f32 { + self.max / (self.inserted as f32) + } + + fn iter(&self) -> impl Iterator + use<'_> { + let m = 1f32 / self.inserted as f32; + let width = self.width; + let height = self.height; + self.data + .iter() + .enumerate() + .map(move |(i, &f)| { + if i < width * height { + let x = i % width; + let z = i / width; + + let x = 2.0 * (x as f32 + 0.5) / (width as f32) - 1.0; + let z = 2.0 * (z as f32 + 0.5) / (height as f32) - 1.0; + let y = f32::sqrt(1.0 - x * x - z * z); + + (Dir3::new(x, y, z), f * m) + } else { + let x = i % width; + let z = (i - width * height) / width; + + let x = 2.0 * (x as f32 + 0.5) / (width as f32) - 1.0; + let z = 2.0 * (z as f32 + 0.5) / (height as f32) - 1.0; + let y = -f32::sqrt(1.0 - x * x - z * z); + + (Dir3::new(x, y, z), f * m) + } + }) + .filter(|(dir, _)| dir.x() * dir.x() + dir.z() * dir.z() < 1.0) + } +} + +impl ParallelExtend<(Dir3, f32)> for Histogram { + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + let (tx, rx) = std::sync::mpsc::sync_channel(100); + + std::thread::scope(move |s| { + s.spawn(move || { + while let Ok((i, f)) = rx.recv() { + self.insert(i, f) + } + }); + + { + let tx = tx; + par_iter.into_par_iter().for_each(|t| { + let _ = tx.send(t); + }); + } + }); + } +} + +fn create_historgram>( + m: &M, + width: usize, + height: usize, + executions: usize, + w_in: Dir3, + channel: usize, +) -> Histogram { + let mut h = Histogram::new(width, height); + h.par_extend( + (0..executions) + .into_par_iter() + .map_init(SmallRng::from_entropy, |rng, _| { + let sample = m.sample(w_in, rng); + + let f = match channel { + 0 => sample.color().r(), + 1 => sample.color().g(), + 2 => sample.color().b(), + _ => unreachable!(), + }; + + (sample.w_out(), f) + }), + ); + + h +}