pub mod plane;
pub mod sphere;
use crate::{
color::Color,
material::{Lambertian, Material},
ray::Ray,
vec3::*,
};
use std::{ops::Range, rc::Rc};
pub struct HitRecord {
pub p: Point3,
pub normal: Vec3,
pub mat: Rc<dyn Material>,
pub t: f64,
pub front_face: bool,
}
pub struct HittableList {
pub objects: Vec<Box<dyn Hittable>>,
}
impl HitRecord {
pub fn set_face_normal<'a>(&mut self, r: &Ray, outward_normal: &Vec3) {
self.front_face = dot(&r.direction, outward_normal) < 0.0;
match self.front_face == true {
true => self.normal = *outward_normal,
false => self.normal = -*outward_normal,
}
}
pub fn set_material(&mut self, mat: Rc<dyn Material>) {
self.mat = mat;
}
}
impl Default for HitRecord {
fn default() -> Self {
HitRecord {
p: Point3::from(0.0),
normal: Vec3::from(0.0),
mat: Rc::new(Lambertian::new(Color::from(0.5))),
t: 0.0,
front_face: false,
}
}
}
impl HittableList {
pub fn new() -> Self {
HittableList {
objects: Vec::new(),
}
}
pub fn add<T: Hittable + 'static>(&mut self, object: T) {
self.objects.push(Box::new(object));
}
pub fn as_simple_vec(&self) -> Vec<String> {
let mut out = vec![];
for object in &self.objects {
out.push(object.as_string());
}
out
}
pub fn as_info_vec(&self) -> Vec<Vec<String>> {
let mut out = vec![];
for object in &self.objects {
out.push(object.as_info_vec());
}
out
}
}
impl Hittable for HittableList {
fn hit(&self, r: &Ray, ray_t: Range<f64>, rec: &mut HitRecord) -> bool {
let mut hit_anything = false;
let mut closest_so_far = ray_t.end;
for object in self.objects.iter() {
let mut temp_rec: HitRecord = Default::default();
if object.hit(r, ray_t.start..closest_so_far, &mut temp_rec) {
hit_anything = true;
closest_so_far = temp_rec.t;
*rec = temp_rec;
}
}
return hit_anything;
}
}
pub trait Hittable: HittableClone {
fn hit(&self, _r: &Ray, _ray_t: Range<f64>, _rec: &mut HitRecord) -> bool {
false
}
fn as_string(&self) -> String {
"Hittable".to_string()
}
fn as_info_vec(&self) -> Vec<String> {
vec![]
}
}
pub trait HittableClone {
fn clone_box(&self) -> Box<dyn Hittable>;
}
impl<T> HittableClone for T
where
T: 'static + Hittable + Clone,
{
fn clone_box(&self) -> Box<dyn Hittable> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Hittable> {
fn clone(&self) -> Box<dyn Hittable> {
self.clone_box()
}
}
impl Clone for HittableList {
fn clone(&self) -> Self {
HittableList {
objects: self.objects.iter().map(|obj| obj.clone()).collect(),
}
}
}