1use super::prelude::*;
2use crate::image::prelude::*;
3use crate::linalg::ray::Ray;
4use crate::trace::sampling::SamplingStrategy;
5use crate::trace::world::World;
6use rand::RngCore;
7use std::sync::mpsc::Receiver;
8use std::sync::{mpsc, Arc, Mutex};
9use std::thread;
10use std::thread::JoinHandle;
11
12pub struct Camera<const W: usize, const H: usize> {
17 aspect_ratio: f64,
18 origin: Vec3,
19 right: Vec3,
20 up: Vec3,
21 forward: Vec3,
22 viewport_top_left: Vec3,
23 pub gamma: f64,
24}
25
26impl<const W: usize, const H: usize> Camera<W, H> {
27 pub unsafe fn new_unchecked(
34 origin: Vec3,
35 right: Vec3,
36 up: Vec3,
37 focal_length: f64,
38 gamma: f64,
39 ) -> Self {
40 let aspect_ratio = W as f64 / H as f64;
41 let forward = right.cross(up);
42
43 let viewport_middle = origin + forward * focal_length;
44 let viewport_top_left = viewport_middle - right * 0.5 + up * 0.5 / aspect_ratio;
45
46 Self {
47 aspect_ratio,
48 origin,
49 right,
50 up,
51 forward,
52 viewport_top_left,
53 gamma,
54 }
55 }
56
57 pub fn sampling_rays_for_pixel(
58 &self,
59 rng: &mut Box<dyn RngCore>,
60 sampling_strategy: Arc<dyn SamplingStrategy>,
61 x: usize,
62 y: usize,
63 ) -> Vec<Ray<f64, 3>> {
64 sampling_strategy
65 .get_sample_positions(rng, x, y)
66 .into_iter()
67 .map(|(x, y)| {
68 let direction =
69 self.viewport_top_left + self.right * x - self.up * y / self.aspect_ratio;
70 Ray::new(self.origin, direction)
71 })
72 .collect()
73 }
74
75 fn trace_sample(&self, rng: &mut Box<dyn RngCore>, world: &World, x: f64, y: f64) -> Colour {
76 let direction = self.viewport_top_left + self.right * x - self.up * y / self.aspect_ratio;
77 let ray = Ray::new(self.origin, direction);
78 world.trace(rng, &ray)
79 }
80
81 fn spawn_threads<S: SamplingStrategy + Clone + 'static>(
82 &'static self,
83 sampling_strategy: S,
84 world: Arc<World>,
85 num_threads: usize,
86 ) -> (Vec<JoinHandle<()>>, Receiver<Vec<Colour>>) {
87 let (tx, rx) = mpsc::channel::<Vec<Colour>>();
88 let lines_numbers = Arc::new(Mutex::new(0..H));
89 let join_handles = (0..num_threads).map(|_| {
90 let line_nums = lines_numbers.clone();
91 let tx = tx.clone();
92 let sampling_strategy = sampling_strategy.clone();
93 });
94 thread::spawn(move || {
95 let mut rng: Box<dyn RngCore> = Box::new(rand::thread_rng());
96 world.trace(&mut rng, &Ray::new(self.origin, self.forward));
97 });
98 todo!()
99 }
100}