use core::{
marker::PhantomData,
ops::{Add, Index, IndexMut, Mul, Neg, Sub},
};
pub trait Ops {
fn sqrt(x: f32) -> f32;
fn acos(x: f32) -> f32;
}
pub(crate) struct Vec3<O: Ops> {
pub(crate) x: f32,
pub(crate) y: f32,
pub(crate) z: f32,
pub(crate) _phantom: PhantomData<O>,
}
impl<O: Ops> Copy for Vec3<O> {}
impl<O: Ops> Clone for Vec3<O> {
fn clone(&self) -> Self {
*self
}
}
impl<O: Ops> From<[f32; 3]> for Vec3<O> {
fn from([x, y, z]: [f32; 3]) -> Self {
Self {
x,
y,
z,
..Self::ZERO
}
}
}
impl<O: Ops> From<Vec3<O>> for [f32; 3] {
fn from(Vec3 { x, y, z, .. }: Vec3<O>) -> Self {
[x, y, z]
}
}
impl<O: Ops> Vec3<O> {
pub(crate) const ZERO: Vec3<O> = Vec3 {
x: 0.,
y: 0.,
z: 0.,
_phantom: PhantomData,
};
pub(crate) fn dot(self, rhs: Self) -> f32 {
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
}
pub(crate) fn normalize_or_zero(&mut self) {
if not_zero(self.x) || not_zero(self.y) || not_zero(self.z) {
*self = *self * self.length().recip();
}
}
pub(crate) fn normalized_or_zero(mut self) -> Self {
self.normalize_or_zero();
self
}
pub(crate) fn length_squared(self) -> f32 {
self.dot(self)
}
pub(crate) fn length(self) -> f32 {
O::sqrt(self.length_squared())
}
}
impl<O: Ops> Index<usize> for Vec3<O> {
type Output = f32;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!(),
}
}
}
impl<O: Ops> IndexMut<usize> for Vec3<O> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!(),
}
}
}
impl<O: Ops> Add for Vec3<O> {
type Output = Vec3<O>;
fn add(self, rhs: Self) -> Self::Output {
Vec3 {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
_phantom: PhantomData,
}
}
}
impl<O: Ops> Sub for Vec3<O> {
type Output = Vec3<O>;
fn sub(self, rhs: Self) -> Self::Output {
Vec3 {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
_phantom: PhantomData,
}
}
}
impl<O: Ops> Mul<f32> for Vec3<O> {
type Output = Vec3<O>;
fn mul(self, rhs: f32) -> Self::Output {
Vec3 {
x: rhs * self.x,
y: rhs * self.y,
z: rhs * self.z,
_phantom: PhantomData,
}
}
}
impl<O: Ops> Mul<Vec3<O>> for f32 {
type Output = Vec3<O>;
fn mul(self, rhs: Vec3<O>) -> Self::Output {
rhs * self
}
}
impl<O: Ops> PartialEq for Vec3<O> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl<O: Ops> Neg for Vec3<O> {
type Output = Vec3<O>;
fn neg(self) -> Self::Output {
Self {
x: -self.x,
y: -self.y,
z: -self.z,
_phantom: PhantomData,
}
}
}
pub(crate) fn fabsf(x: f32) -> f32 {
if x.is_sign_negative() { -x } else { x }
}
pub(crate) fn not_zero(x: f32) -> bool {
fabsf(x) > f32::MIN_POSITIVE
}