use num_traits::{Num, Bounded, Float as NumFloat}; use std::ops::{Sub, SubAssign, Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Index, IndexMut}; use std::sync::Arc; use std::f32::consts::PI; use crate::core::pbrt::Float; use crate::core::pbrt; use crate::core::medium::Medium; pub trait Tuple: Sized + Copy + Index + IndexMut { fn data(&self) -> &[T; N]; fn data_mut(&mut self) -> &mut [T; N]; fn from_array(arr: [T; N]) -> Self; } fn min(a: T, b: T) -> T { if a < b { a } else { b }} fn max(a: T, b: T) -> T { if a > b { a } else { b }} // N-dimensional displacement #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Vector(pub [T; N]); // N-dimensional location #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Point(pub [T; N]); // N-dimensional surface normal #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Normal(pub [T; N]); macro_rules! impl_tuple_core { ($Struct:ident) => { impl Tuple for $Struct { #[inline] fn data(&self) -> &[T; N] { &self.0 } #[inline] fn data_mut(&mut self) -> &mut [T; N] { &mut self.0 } #[inline] fn from_array(arr: [T; N]) -> Self { Self(arr) } } impl Default for $Struct { fn default() -> Self { Self([T::default(); N]) } } impl Index for $Struct { type Output = T; #[inline] fn index(&self, index: usize) -> &Self::Output { &self.0[index] } } impl IndexMut for $Struct { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.0[index] } } impl Neg for $Struct where T: Neg + Copy { type Output = Self; fn neg(self) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = -result[i]; } Self(result) } } impl Mul for $Struct where T: Mul + Copy { type Output = Self; fn mul(self, rhs: T) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = result[i] * rhs; } Self(result) } } impl MulAssign for $Struct where T: MulAssign + Copy { fn mul_assign(&mut self, rhs: T) { for i in 0..N { self.0[i] *= rhs; } } } impl Div for $Struct where T: Div + Copy { type Output = Self; fn div(self, rhs: T) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = result[i] / rhs; } Self(result) } } impl DivAssign for $Struct where T: DivAssign + Copy { fn div_assign(&mut self, rhs: T) { for i in 0..N { self.0[i] /= rhs; } } } }; } impl_tuple_core!(Vector); impl_tuple_core!(Point); impl_tuple_core!(Normal); macro_rules! impl_tuple_ops { ($Struct:ident) => { impl Add for $Struct where T: Add + Copy { type Output = Self; fn add(self, rhs: Self) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = self.0[i] + rhs.0[i]; } Self(result) } } impl AddAssign for $Struct where T: AddAssign + Copy { fn add_assign(&mut self, rhs: Self) { for i in 0..N { self.0[i] += rhs.0[i]; } } } impl Sub for $Struct where T: Sub + Copy { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = self.0[i] - rhs.0[i]; } Self(result) } } impl SubAssign for $Struct where T: SubAssign + Copy { fn sub_assign(&mut self, rhs: Self) { for i in 0..N { self.0[i] -= rhs.0[i]; } } } }; } impl_tuple_ops!(Vector); impl_tuple_ops!(Normal); impl From> for Normal { fn from(v: Vector) -> Self { Self(v.0) } } impl From> for Vector { fn from(n: Normal) -> Self { Self(n.0) } } impl Sub for Point where T: Sub + Copy { type Output = Vector; fn sub(self, rhs: Self) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = self.0[i] - rhs.0[i]; } Vector(result) } } // Point + Vector -> Point impl Add> for Point where T: Add + Copy { type Output = Self; fn add(self, rhs: Vector) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = self.0[i] + rhs.0[i]; } Self(result) } } impl AddAssign> for Point where T: AddAssign + Copy { fn add_assign(&mut self, rhs: Vector) { for i in 0..N { self.0[i] += rhs.0[i]; } } } // Point - Vector -> Point impl Sub> for Point where T: Sub + Copy { type Output = Self; fn sub(self, rhs: Vector) -> Self::Output { let mut result = self.0; for i in 0..N { result[i] = self.0[i] - rhs.0[i]; } Self(result) } } impl SubAssign> for Point where T: SubAssign + Copy { fn sub_assign(&mut self, rhs: Vector) { for i in 0..N { self.0[i] -= rhs.0[i]; } } } macro_rules! impl_accessors { ($Struct:ident) => { impl $Struct { pub fn x(&self) -> T { self.0[0] } pub fn y(&self) -> T { self.0[1] } } impl $Struct { pub fn x(&self) -> T { self.0[0] } pub fn y(&self) -> T { self.0[1] } pub fn z(&self) -> T { self.0[2] } } }; } impl_accessors!(Vector); impl_accessors!(Point); impl_accessors!(Normal); // Vector stuff pub trait Dot { type Output; fn dot(self, rhs: Rhs) -> Self::Output; } pub trait Normed { type Scalar; fn norm_squared(&self) -> Self::Scalar; fn norm(&self) -> Self::Scalar where Self::Scalar: NumFloat { self.norm_squared().sqrt() } fn normalize(self) -> Self where Self: Sized, Self: Div, Self::Scalar: NumFloat; } macro_rules! impl_vector_math_for { ($Struct:ident) => { impl Dot for $Struct { type Output = T; fn dot(self, rhs: Self) -> T { let mut sum = T::zero(); for i in 0..N { sum = sum + self[i] * rhs[i]; } sum } } impl Normed for $Struct { type Scalar = T; fn norm_squared(&self) -> T { self.dot(*self) } fn normalize(self) -> Self where Self: Div, T: NumFloat { self / self.norm() } } }; } impl_vector_math_for!(Vector); impl_vector_math_for!(Normal); impl Point where T: NumFloat + Copy, Point: Sub>, // Point - Point -> Vector Vector: Normed, // Vector has a norm { pub fn distance(self, other: Self) -> T { (self - other).norm() } pub fn distance_squared(self, other: Self) -> T { (self - other).norm_squared() } } // Utility aliases and functions pub type Point2 = Point; pub type Point3 = Point; pub type Point3f = Point3; pub type Point3i = Point3; pub type Vector2 = Vector; pub type Vector3 = Vector; pub type Vector3f = Vector3; pub type Vector3i = Vector3; pub type Normal3 = Normal; pub type Normal3f = Normal3; pub type Normal3i = Normal3; impl Vector2 { pub fn new(x: T, y: T) -> Self { Self([x, y]) } } impl Point2 { pub fn new(x: T, y: T) -> Self { Self([x, y]) } } impl Vector3 { pub fn new(x: T, y: T, z: T) -> Self { Self([x, y, z]) } } impl Point3 { pub fn new(x: T, y: T, z: T) -> Self { Self([x, y, z]) } } impl Normal3 { pub fn new(x: T, y: T, z: T) -> Self { Self([x, y, z]) } } // Vector operations impl Vector3 where T: Num + Copy + Neg { pub fn cross(self, rhs: Self) -> Self { Self([ self[1] * rhs[2] - self[2] * rhs[1], self[2] * rhs[0] - self[0] * rhs[2], self[0] * rhs[1] - self[1] * rhs[0], ]) } } impl Vector3 where T: Num + NumFloat + Copy + Neg { pub fn coordinate_system(&self) -> (Self, Self) where T: NumFloat { let v2 = if self[0].abs() > self[1].abs() { Self::new(-self[2], T::zero(), self[0]) / (self[0] * self[0] + self[2] * self[2]).sqrt() } else { Self::new(T::zero(), self[2], -self[1]) / (self[1] * self[1] + self[2] * self[2]).sqrt() }; (v2, self.cross(v2)) } } impl Normal3 where T: Num + PartialOrd + Copy + Neg { pub fn face_forward(self, v: Vector3) -> Self { if self.dot(v.into()) < T::zero() { -self } else { self } } } // SPHERICAL GEOMETRY pub fn spherical_direction(sin_theta: Float, cos_theta: Float, phi: Float) -> Vector3f { Vector3f::new(sin_theta * phi.cos(), sin_theta * phi.sin(), cos_theta) } pub fn spherical_triangle_area(a: Vector3f, b: Vector3f, c: Vector3f) -> Float { (2.0 * (a.dot(b.cross(c))).atan2(1.0 + a.dot(b) + a.dot(c) + b.dot(c))).abs() } pub fn spherical_theta(v: Vector3f) -> Float { pbrt::clamp_t(v.z(), -1.0, 1.0).acos() } pub fn spherical_phi(v: Vector3f) -> Float { let p = v.y().atan2(v.x()); if p < 0.0 { p + 2.0 * PI } else { p } } // AABB bouding boxes #[derive(Debug, Copy, Clone, PartialEq)] pub struct Bounds { pub p_min: Point, pub p_max: Point, } impl Bounds where T: Num + PartialOrd + Copy { pub fn from_point(p: Point) -> Self { Self { p_min: p, p_max: p } } pub fn from_points(p1: Point, p2: Point) -> Self { let mut p_min_arr = [T::zero(); N]; let mut p_max_arr = [T::zero(); N]; for i in 0..N { if p1[i] < p2[i] { p_min_arr[i] = p1[i]; p_max_arr[i] = p2[i]; } else { p_min_arr[i] = p2[i]; p_max_arr[i] = p1[i]; } } Self { p_min: Point(p_min_arr), p_max: Point(p_max_arr) } } pub fn union_point(self, p: Point) -> Self { let mut p_min = self.p_min; let mut p_max = self.p_max; for i in 0..N { p_min[i] = min(p_min[i], p[i]); p_max[i] = max(p_max[i], p[i]); } Self { p_min, p_max } } pub fn union(self, b2: Self) -> Self { let mut p_min = self.p_min; let mut p_max = self.p_max; for i in 0..N { p_min[i] = min(p_min[i], b2.p_min[i]); p_max[i] = max(p_max[i], b2.p_max[i]); } Self { p_min, p_max } } pub fn diagonal(&self) -> Vector { self.p_max - self.p_min } pub fn volume(&self) -> T { let d = self.diagonal(); d.0.iter().fold(T::one(), |acc, &val| acc * val) } pub fn lerp(&self, t: Point) -> Point { let mut results_arr = [T::zero(); N]; for i in 0..N { results_arr[i] = pbrt::lerp(t[i], self.p_min[i], self.p_max[i]) } Point(results_arr) } pub fn max_dimension(&self) -> usize where Point: Sub>, { let d = self.diagonal(); let mut max_dim = 0; let mut max_span = d[0]; for i in 1..N { if d[i] > max_span { max_span = d[i]; max_dim = i; } } max_dim } pub fn offset(&self, p: &Point) -> Vector where Point: Sub>, Vector: DivAssign { let mut o = *p - self.p_min; let d = self.diagonal(); for i in 0..N { if d[i] > T::zero() { o[i] = o[i] / d[i]; } } o } pub fn contains(&self, p: Point) -> bool { (0..N).all(|i| p[i] >= self.p_min[i] && p[i] <= self.p_max[i]) } pub fn contains_exclusive(&self, p: Point) -> bool { (0..N).all(|i| p[i] >= self.p_min[i] && p[i] < self.p_max[i]) } pub fn is_empty(&self) -> bool { (0..N).any(|i| self.p_min[i] >= self.p_max[i]) } pub fn is_degenerate(&self) -> bool { (0..N).any(|i| self.p_min[i] > self.p_max[i]) } } impl Default for Bounds where T: Bounded + Copy, { fn default() -> Self { Self { p_min: Point([T::max_value(); N]), p_max: Point([T::min_value(); N]), } } } pub type Bounds2 = Bounds; pub type Bounds3 = Bounds; pub type Bounds3f = Bounds3; impl Bounds3 where T: Num + PartialOrd + Copy + Default { pub fn surface_area(&self) -> T { let d = self.diagonal(); let two = T::one() + T::one(); two * (d.x() * d.y() + d.x() * d.z() + d.y() * d.z()) } pub fn bounding_sphere(&self) -> (Point3, T) where < as Sub>::Output as Normed>::Scalar: NumFloat, { let two = T::one() + T::one(); let center = (self.p_min + self.diagonal()) / two; let radius = if self.contains(center) { center.distance(self.p_max) } else { T::zero() }; (center, radius) } } #[derive(Copy, Clone, Default, PartialEq)] pub struct Frame { pub x: Vector3f, pub y: Vector3f, pub z: Vector3f, } impl Frame { pub fn from_z(z: Vector3f) -> Self { let (x, y) = z.normalize().coordinate_system(); Self { x, y, z: z.normalize() } } pub fn to_local(&self, v: Vector3f) -> Vector3f { Vector3f::new(v.dot(self.x), v.dot(self.y), v.dot(self.z)) } pub fn from_local(&self, v: Vector3f) -> Vector3f { self.x * v.x() + self.y * v.y() + self.z * v.z() } } #[derive(Clone, Default)] pub struct Ray { pub o: Point3f, pub d: Vector3f, pub medium: Option>, pub time: Float, // We do this instead of creating a trait for Rayable or some gnarly thing like that pub differential: Option, } impl Ray { pub fn operator(&self, t: Float) -> Point3f { self.o + self.d * t } pub fn scale_differentials(&mut self, s: Float) { if let Some(differential) = &mut self.differential { differential.rx_origin = self.o + (differential.rx_origin - self.o) * s; differential.ry_origin = self.o + (differential.ry_origin - self.o) * s; differential.rx_direction = self.d + (differential.rx_direction - self.d) * s; differential.ry_direction = self.d + (differential.ry_direction - self.d) * s; } } } #[derive(Debug, Default, Copy, Clone)] pub struct RayDifferential { pub rx_origin: Point3f, pub ry_origin: Point3f, pub rx_direction: Vector3f, pub ry_direction: Vector3f, }