1use crate::{ Camera, Color, Ray, Real, Shape, shape::Group };
2use rayon::iter::{ IntoParallelIterator, ParallelIterator };
3
4pub struct RayTracer {
5 pub camera : Camera,
6 pub ixsize : u32,
7 pub iysize : u32,
8 pub spp : u32,
9 pub rdepth : u32
10}
11
12impl RayTracer {
13 pub fn new(camera: Camera, ixsize: u32, spp: u32, rdepth: u32) -> Self {
14 let iysize = (ixsize as Real / camera.ratio) as u32;
15 Self { camera, ixsize, iysize, spp, rdepth }
16 }
17
18 fn get_st(&self, (x, y): (Real, Real)) -> (Real, Real) {
19 (x / (self.ixsize - 1) as Real, (self.iysize as Real - y - 1.0) / (self.iysize - 1) as Real)
20 }
21
22 fn sample_vars(&self) -> impl Iterator< Item = (Real, Real) > {
23 (0..self.spp).map(|_| (rand::random(), rand::random()))
24 }
25
26 fn ray_color(world: &Group, ray: Ray, depth: u32) -> Color {
27 match (0..depth).try_fold(
28 (Color::new(1.0, 1.0, 1.0), ray),
29 |(color, ray), _| world.hit(ray, 0.001..Real::INFINITY)
30 .ok_or_else(|| {
31 let t = 0.5 * (1.0 + ray.dir.normalize().y);
32 color * ((1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.86, 0.92, 1.0)) })
33 .and_then(|hr| hr.mat.scatter(ray, &hr)
34 .map(|(scattered, attenuation)| (color * attenuation, scattered))
35 .ok_or_else(|| Color::new(0.0, 0.0, 0.0)))) {
36 Ok(_) => Color::new(0.0, 0.0, 0.0),
37 Err(color) => color,
38 }
39 }
40
41 pub fn draw(&self, world: &Group) -> Vec< Color > {
42 let pbar = indicatif::ProgressBar::new(self.iysize as u64);
43 let sv = self.sample_vars().collect::< Vec< _ > >();
44
45 (0..self.iysize).into_par_iter().map(|y| {
46 let ret = (0..self.ixsize).map(|x|
47 Color::mix(sv.iter().map(|(xp, yp)| {
48 let (xx, yy) = (x as Real + xp, y as Real + yp);
49 let (s, t) = self.get_st((xx, yy));
50 let ray = self.camera.get_ray((s, t));
51 Self::ray_color(&world, ray, self.rdepth)
52 }))
53 ).collect::< Vec< _ > >();
54 pbar.inc(1);
55 ret
56 }).flatten().collect::< Vec< _ > >()
57 }
58}