1use crate::image::image::{Colour, Image};
2use crate::trace::camera::Camera;
3use crate::trace::prelude::{Vec3, World};
4use crate::trace::sampling::SamplingStrategy;
5use rand::RngCore;
6use std::collections::HashMap;
7use std::sync::mpsc::Receiver;
8use std::sync::{mpsc, Arc, Mutex};
9use std::thread;
10use std::thread::JoinHandle;
11
12pub struct SceneConfig<const W: usize, const H: usize> {
13 camera: Arc<Camera<W, H>>,
14 sampling_strategy: Arc<dyn SamplingStrategy + Send + Sync>,
15 world: Arc<World>,
16 num_threads: usize,
17}
18
19impl<const W: usize, const H: usize> SceneConfig<W, H> {
20 pub fn new(
21 camera: Camera<W, H>,
22 sampling_strategy: Arc<dyn SamplingStrategy>,
23 world: World,
24 num_threads: usize,
25 ) -> Self {
26 let camera = Arc::new(camera);
27 let world = Arc::new(world);
28 SceneConfig {
29 camera,
30 sampling_strategy,
31 world,
32 num_threads,
33 }
34 }
35
36 pub fn trace(&self) -> Image<W, H> {
37 let (join_handles, rx) = self.spawn_threads(self.num_threads);
38 let mut line_map: HashMap<usize, Vec<Colour>> = HashMap::new();
39 let mut num_lines = 0usize;
40 while let Ok((y, line_colours)) = rx.recv() {
41 line_map.insert(y, line_colours);
42 num_lines += 1;
43 println!("{}/{}", num_lines, H);
44 }
45 Image::gen(|x, y| {
46 let line = line_map.get(&y).unwrap();
47 line[x]
48 })
49 }
50
51 fn spawn_threads(
52 &self,
53 num_threads: usize,
54 ) -> (Vec<JoinHandle<()>>, Receiver<(usize, Vec<Colour>)>) {
55 let (tx, rx) = mpsc::channel::<(usize, Vec<Colour>)>();
56 let line_numbers = Arc::new(Mutex::new(0..H));
57 let join_handles: Vec<JoinHandle<()>> = (0..num_threads)
58 .map(|thread_i| {
59 let tx = tx.clone();
60 let line_numbers = line_numbers.clone();
61 let camera = self.camera.clone();
62 let world = self.world.clone();
63 let sampling_strategy = self.sampling_strategy.clone();
64
65 thread::spawn(move || {
66 let mut rng: Box<dyn RngCore> = Box::new(rand::thread_rng());
67 loop {
68 let y = {
69 let mut line_numbers = line_numbers.lock().unwrap(); line_numbers.next()
71 };
72
73 if let Some(y) = y {
74 let mut line_colours: Vec<Colour> = Vec::with_capacity(W);
75 for x in 0..W {
76 let ss = sampling_strategy.clone(); let sample_rays =
78 camera.sampling_rays_for_pixel(&mut rng, ss, x, y);
79 let num_samples = sample_rays.len();
80 let sample_sum: Vec3 = sample_rays
81 .iter()
82 .map(|ray| world.trace(&mut rng, ray).0)
83 .sum();
84 let avg_colour: Colour = (sample_sum / (num_samples as f64))
85 .map(|c| c.powf(1.0 / camera.gamma))
86 .into();
87 line_colours.push(avg_colour);
88 }
89 tx.send((y, line_colours)).unwrap(); } else {
91 break;
92 }
93 }
94 })
95 })
96 .collect();
97
98 (join_handles, rx)
99 }
100}