use std::sync::Arc; use crate::{ aabb::AABB, cuboid::Cuboid, hitable::{Hit, HitRecord}, material::Material, ray::Ray, vec3::Vec3, }; #[derive(Debug)] pub struct Glowybox { p_min: Vec3, p_max: Vec3, main: Cuboid, edges: [Cuboid; 12], } impl Glowybox { // This clippy doesn't work right with Arc. #[allow(clippy::needless_pass_by_value)] pub fn new( p_min: Vec3, p_max: Vec3, edge_thickness: f32, main_material: Arc, edge_material: Arc, ) -> Glowybox { assert!(p_min.x < p_max.x); assert!(p_min.y < p_max.y); assert!(p_min.z < p_max.z); let main = Cuboid::new(p_min, p_max, main_material); // Top edges let ht = edge_thickness / 2.; let edges = [ // Top edges Cuboid::new( [p_min.x - ht, p_max.y - ht, p_min.z - ht].into(), [p_min.x + ht, p_max.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_min.x - ht, p_max.y - ht, p_min.z - ht].into(), [p_max.x + ht, p_max.y + ht, p_min.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_max.x - ht, p_max.y - ht, p_min.z - ht].into(), [p_max.x + ht, p_max.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_min.x - ht, p_max.y - ht, p_max.z - ht].into(), [p_max.x + ht, p_max.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), // Bottom edges Cuboid::new( [p_min.x - ht, p_min.y - ht, p_min.z - ht].into(), [p_min.x + ht, p_min.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_min.x - ht, p_min.y - ht, p_min.z - ht].into(), [p_max.x + ht, p_min.y + ht, p_min.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_max.x - ht, p_min.y - ht, p_min.z - ht].into(), [p_max.x + ht, p_min.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_min.x - ht, p_min.y - ht, p_max.z - ht].into(), [p_max.x + ht, p_min.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), // Middle edges Cuboid::new( [p_min.x - ht, p_min.y - ht, p_min.z - ht].into(), [p_min.x + ht, p_max.y + ht, p_min.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_min.x - ht, p_min.y - ht, p_max.z - ht].into(), [p_min.x + ht, p_max.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_max.x - ht, p_min.y - ht, p_min.z - ht].into(), [p_max.x + ht, p_max.y + ht, p_min.z + ht].into(), Arc::clone(&edge_material), ), Cuboid::new( [p_max.x - ht, p_min.y - ht, p_max.z - ht].into(), [p_max.x + ht, p_max.y + ht, p_max.z + ht].into(), Arc::clone(&edge_material), ), ]; let p_min = [p_min.x - ht, p_min.y - ht, p_min.z - ht].into(); let p_max = [p_max.x + ht, p_max.y + ht, p_max.z + ht].into(); Glowybox { p_min, p_max, main, edges, } } } impl Hit for Glowybox { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let mut edge_hit = None; for edge in &self.edges { if let Some(hit) = edge.hit(r, t_min, t_max) { edge_hit = Some(hit); break; } } let main_hit = self.main.hit(r, t_min, t_max); match (edge_hit, main_hit) { (Some(ehit), Some(mhit)) => { if mhit.t < ehit.t { Some(mhit) } else { Some(ehit) } } (Some(ehit), None) => Some(ehit), (None, Some(mhit)) => Some(mhit), _ => None, } } fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option { Some(AABB::new(self.p_min, self.p_max)) } }