use crate::objects::hit::Hit; use crate::objects::sphere::Sphere; use crate::objects::traits::Hittable; use crate::objects::triangle::Triangle; use crate::ray::Ray; use crate::{objects::materials::traits::Material, vec3::Vec3}; use std::fmt::Debug; use std::sync::Arc; pub struct Quad { p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3, material: Arc, normal: Vec3, } impl Quad { pub fn new(p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3, material: Arc) -> Self { Self { p1, p2, p3, p4, material, normal: (p2 - p1).cross(&(p4 - p1)).get_unit(), } } pub fn corner_spheres(&self) -> Vec { vec![ Sphere::new(self.p1, 1., self.material.clone()), Sphere::new(self.p2, 1., self.material.clone()), Sphere::new(self.p3, 1., self.material.clone()), Sphere::new(self.p4, 1., self.material.clone()), ] } pub fn hit( p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3, material: Arc, normal: Vec3, r: &Ray, ) -> Option { let isct1 = Triangle::hit(p1, p2, p4, material.clone(), normal, r); let isct2 = Triangle::hit(p2, p3, p4, material.clone(), normal, r); if isct1.is_some() { return isct1; } isct2 } } impl Debug for Quad { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Triangle") .field("p1", &self.p1) .field("p2", &self.p2) .field("p3", &self.p3) .field("p4", &self.p4) .field("material", &self.material) .finish() } } impl Hittable for Quad { fn hit(&self, r: &Ray) -> Option { Quad::hit( self.p1, self.p2, self.p3, self.p4, self.material.clone(), self.normal, r, ) } fn normal_at(&self, _p: &Vec3) -> Vec3 { // FIXME: might cause ownership issues self.normal } }