use rayon::prelude::*;
use crate::math::{Bounds3, Hit, Point3, Ray, Transformable, Vec3};
use crate::shapes::{Shape, Triangle, TriangleMesh, BVH};
#[derive(Clone, Debug)]
pub struct Mesh<S: Shape> {
pub bvh: BVH<S>,
pub bounds: Bounds3,
}
impl<S: Shape> Mesh<S> {
pub fn new(shapes: Vec<S>) -> Self {
let bvh = BVH::init(4, shapes);
Mesh {
bounds: bvh
.shapes
.iter()
.fold(Bounds3::default(), |b, s| b.include_bounds(s.bounds())),
bvh,
}
}
fn calculate_bounds(&self) -> Bounds3 {
self.bvh
.shapes
.iter()
.fold(Bounds3::default(), |b, s| b.include_bounds(s.bounds()))
}
}
impl<S: Shape> Shape for Mesh<S> {
fn intersects(&self, ray: Ray) -> Option<Hit> {
self.bvh.intersects(ray).map(|(h, _)| h)
}
fn bounds(&self) -> Bounds3 {
self.bounds
}
}
impl<I: IntoIterator<Item = TriangleMesh>> From<I> for Mesh<Triangle> {
fn from(value: I) -> Self {
Mesh::new(value.into_iter().flat_map(|m| m.triangles()).collect())
}
}
impl<S: Shape + Transformable + Clone> Transformable for Mesh<S> {
fn translate(mut self, translation: Vec3) -> Self {
let shapes = self
.bvh
.shapes
.into_par_iter()
.map(|s| s.translate(translation))
.collect();
self.bvh = BVH::init(4, shapes);
self.bounds = self.calculate_bounds();
self
}
fn rotate(mut self, origin: Point3, axis: Vec3, angle: f64) -> Self {
let shapes = self
.bvh
.shapes
.into_par_iter()
.map(|s| s.rotate(origin, axis, angle))
.collect();
self.bvh = BVH::init(4, shapes);
self.bounds = self.calculate_bounds();
self
}
fn rotate_x(self, angle: f64) -> Self {
self.rotate(Point3::default(), Vec3::X, angle)
}
fn rotate_y(self, angle: f64) -> Self {
self.rotate(Point3::default(), Vec3::Y, angle)
}
fn rotate_z(self, angle: f64) -> Self {
self.rotate(Point3::default(), Vec3::Z, angle)
}
fn scale_x(self, factor: f64) -> Self {
self.scale(Point3::default(), Vec3::new(factor, 1.0, 1.0))
}
fn scale_y(self, factor: f64) -> Self {
self.scale(Point3::default(), Vec3::new(1.0, factor, 1.0))
}
fn scale_z(self, factor: f64) -> Self {
self.scale(Point3::default(), Vec3::new(1.0, 1.0, factor))
}
fn scale_xyz(self, scale: Vec3) -> Self {
self.scale(Point3::default(), scale)
}
fn scale(mut self, origin: Point3, scale: Vec3) -> Self {
let shapes = self
.bvh
.shapes
.into_par_iter()
.map(|s| s.scale(origin, scale))
.collect();
self.bvh = BVH::init(4, shapes);
self.bounds = self.calculate_bounds();
self
}
fn look_at(self, _target: Point3, _view_up: Vec3) -> Self {
todo!()
}
}