// There are many math functions in this file, so we allow single letter variable names. #![allow(clippy::many_single_char_names)] use crate::aabb::AABB; use crate::hitable::Hit; use crate::hitable::HitRecord; use crate::material::Material; use crate::ray::Ray; use crate::vec3::Vec3; pub struct XYRect where M: Material, { x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: M, } impl XYRect where M: Material, { pub fn new(x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: M) -> XYRect { XYRect { x0, x1, y0, y1, k, material, } } } impl Hit for XYRect where M: Material, { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let t = (self.k - r.origin.z) / r.direction.z; if t < t_min || t > t_max { return None; } let x = r.origin.x + t * r.direction.x; let y = r.origin.y + t * r.direction.y; if x < self.x0 || x > self.x1 || y < self.y0 || y > self.y1 { return None; } let u = (x - self.x0) / (self.x1 - self.x0); let v = (y - self.y0) / (self.y1 - self.y0); Some(HitRecord { t, uv: (u, v), p: r.point_at_parameter(t), normal: Vec3::new(0., 0., 1.), material: &self.material, }) } fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option { Some(AABB::new( Vec3::new(self.x0, self.y0, self.k - 0.0001), Vec3::new(self.x1, self.y1, self.k + 0.0001), )) } } pub struct XZRect where M: Material, { x0: f32, x1: f32, z0: f32, z1: f32, k: f32, material: M, } impl XZRect where M: Material, { pub fn new(x0: f32, x1: f32, z0: f32, z1: f32, k: f32, material: M) -> XZRect { XZRect { x0, x1, z0, z1, k, material, } } } impl Hit for XZRect where M: Material, { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let t = (self.k - r.origin.y) / r.direction.y; if t < t_min || t > t_max { return None; } let x = r.origin.x + t * r.direction.x; let z = r.origin.z + t * r.direction.z; if x < self.x0 || x > self.x1 || z < self.z0 || z > self.z1 { return None; } let u = (x - self.x0) / (self.x1 - self.x0); let v = (z - self.z0) / (self.z1 - self.z0); Some(HitRecord { t, uv: (u, v), p: r.point_at_parameter(t), normal: Vec3::new(0., 1., 0.), material: &self.material, }) } fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option { Some(AABB::new( Vec3::new(self.x0, self.k - 0.0001, self.z0), Vec3::new(self.x1, self.k + 0.0001, self.z1), )) } } pub struct YZRect where M: Material, { y0: f32, y1: f32, k: f32, z0: f32, z1: f32, material: M, } impl YZRect where M: Material, { pub fn new(y0: f32, y1: f32, z0: f32, z1: f32, k: f32, material: M) -> YZRect { YZRect { y0, y1, z0, z1, k, material, } } } impl Hit for YZRect where M: Material, { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let t = (self.k - r.origin.x) / r.direction.x; if t < t_min || t > t_max { return None; } let y = r.origin.y + t * r.direction.y; let z = r.origin.z + t * r.direction.z; if y < self.y0 || y > self.y1 || z < self.z0 || z > self.z1 { return None; } let u = (y - self.y0) / (self.y1 - self.y0); let v = (z - self.z0) / (self.z1 - self.z0); Some(HitRecord { t, uv: (u, v), p: r.point_at_parameter(t), normal: Vec3::new(1., 0., 0.), material: &self.material, }) } fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option { Some(AABB::new( Vec3::new(self.k - 0.0001, self.y0, self.z0), Vec3::new(self.k + 0.0001, self.y1, self.z1), )) } }