bs_trace/trace/
cfg.rs

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(); // TODO don't unwrap
70                            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(); // TODO don't fucking clone this every time
77                                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(); // TODO don't unwrap
90                        } else {
91                            break;
92                        }
93                    }
94                })
95            })
96            .collect();
97
98        (join_handles, rx)
99    }
100}