bs-trace 0.3.0

Free RayTracing software
Documentation
use super::prelude::*;
use crate::image::prelude::*;
use crate::linalg::ray::Ray;
use crate::trace::sampling::SamplingStrategy;
use crate::trace::world::World;
use rand::RngCore;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::thread::JoinHandle;

/// A camera in 3D space, with an associated viewport.
///
/// The const generic parameters `W` and `H` represent the width and height of the viewport in
/// pixels.
pub struct Camera<const W: usize, const H: usize> {
    aspect_ratio: f64,
    origin: Vec3,
    right: Vec3,
    up: Vec3,
    forward: Vec3,
    viewport_top_left: Vec3,
    pub gamma: f64,
}

impl<const W: usize, const H: usize> Camera<W, H> {
    /// Constructs a camera with the given origin, orientation and focal length.
    ///
    /// # Safety
    ///
    /// It is the responsibility of the caller to ensure that the `right` and `up` vectors are
    /// orthonormal.
    pub unsafe fn new_unchecked(
        origin: Vec3,
        right: Vec3,
        up: Vec3,
        focal_length: f64,
        gamma: f64,
    ) -> Self {
        let aspect_ratio = W as f64 / H as f64;
        let forward = right.cross(up);

        let viewport_middle = origin + forward * focal_length;
        let viewport_top_left = viewport_middle - right * 0.5 + up * 0.5 / aspect_ratio;

        Self {
            aspect_ratio,
            origin,
            right,
            up,
            forward,
            viewport_top_left,
            gamma,
        }
    }

    pub fn sampling_rays_for_pixel(
        &self,
        rng: &mut Box<dyn RngCore>,
        sampling_strategy: Arc<dyn SamplingStrategy>,
        x: usize,
        y: usize,
    ) -> Vec<Ray<f64, 3>> {
        sampling_strategy
            .get_sample_positions(rng, x, y)
            .into_iter()
            .map(|(x, y)| {
                let direction =
                    self.viewport_top_left + self.right * x - self.up * y / self.aspect_ratio;
                Ray::new(self.origin, direction)
            })
            .collect()
    }

    fn trace_sample(&self, rng: &mut Box<dyn RngCore>, world: &World, x: f64, y: f64) -> Colour {
        let direction = self.viewport_top_left + self.right * x - self.up * y / self.aspect_ratio;
        let ray = Ray::new(self.origin, direction);
        world.trace(rng, &ray)
    }

    fn spawn_threads<S: SamplingStrategy + Clone + 'static>(
        &'static self,
        sampling_strategy: S,
        world: Arc<World>,
        num_threads: usize,
    ) -> (Vec<JoinHandle<()>>, Receiver<Vec<Colour>>) {
        let (tx, rx) = mpsc::channel::<Vec<Colour>>();
        let lines_numbers = Arc::new(Mutex::new(0..H));
        let join_handles = (0..num_threads).map(|_| {
            let line_nums = lines_numbers.clone();
            let tx = tx.clone();
            let sampling_strategy = sampling_strategy.clone();
        });
        thread::spawn(move || {
            let mut rng: Box<dyn RngCore> = Box::new(rand::thread_rng());
            world.trace(&mut rng, &Ray::new(self.origin, self.forward));
        });
        todo!()
    }
}