use std::convert::TryFrom;
use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
use nanorand::tls::TlsWyRand;
use crate::math::Vec3;
use crate::util::random_float;
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Vec4 {
pub x: f64,
pub y: f64,
pub z: f64,
pub w: f64,
}
impl Vec4 {
pub const X: Vec4 = Vec4 {
x: 1.0,
y: 0.0,
z: 0.0,
w: 0.0,
};
pub const Y: Vec4 = Vec4 {
x: 0.0,
y: 1.0,
z: 0.0,
w: 0.0,
};
pub const Z: Vec4 = Vec4 {
x: 0.0,
y: 0.0,
z: 1.0,
w: 0.0,
};
pub const W: Vec4 = Vec4 {
x: 0.0,
y: 0.0,
z: 0.0,
w: 1.0,
};
pub const ZERO: Vec4 = Vec4 {
x: 0.0,
y: 0.0,
z: 0.0,
w: 0.0,
};
pub fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
Vec4 { x, y, z, w }
}
pub fn splat(value: f64) -> Self {
Vec4 {
x: value,
y: value,
z: value,
w: value,
}
}
pub fn random(rng: &mut TlsWyRand, min: f64, max: f64) -> Self {
Vec4 {
x: random_float(rng, min, max),
y: random_float(rng, min, max),
z: random_float(rng, min, max),
w: random_float(rng, min, max),
}
}
#[doc(alias = "length")]
pub fn magnitude(&self) -> f64 {
Self::dot(*self, *self).sqrt()
}
#[doc(alias = "length_squared")]
pub fn magnitude_squared(&self) -> f64 {
Self::dot(*self, *self)
}
pub fn abs(&self) -> f64 {
self.magnitude()
}
pub fn normalize(&self) -> Self {
assert_ne!(self.magnitude(), 0.0, "Can't normalize zero vector");
*self / self.magnitude()
}
pub fn dot(vec_a: Vec4, vec_b: Vec4) -> f64 {
vec_a.x * vec_b.x + vec_a.y * vec_b.y + vec_a.z * vec_b.z + vec_a.w * vec_b.w
}
pub fn xyz(&self) -> Vec3 {
Vec3::new(self.x, self.y, self.z)
}
}
impl Add<Vec4> for Vec4 {
type Output = Vec4;
fn add(self, rhs: Vec4) -> Self::Output {
Vec4 {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
w: self.w + rhs.w,
}
}
}
impl AddAssign<Vec4> for Vec4 {
fn add_assign(&mut self, rhs: Vec4) {
*self = *self + rhs;
}
}
impl Sub<Vec4> for Vec4 {
type Output = Vec4;
fn sub(self, rhs: Vec4) -> Self::Output {
Vec4 {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
w: self.w - rhs.w,
}
}
}
impl SubAssign<Vec4> for Vec4 {
fn sub_assign(&mut self, rhs: Vec4) {
*self = *self - rhs;
}
}
impl Mul<f64> for Vec4 {
type Output = Vec4;
fn mul(self, rhs: f64) -> Self::Output {
Vec4 {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
w: self.w * rhs,
}
}
}
impl MulAssign<f64> for Vec4 {
fn mul_assign(&mut self, rhs: f64) {
*self = *self * rhs;
}
}
impl Mul<Vec4> for f64 {
type Output = Vec4;
fn mul(self, rhs: Vec4) -> Self::Output {
rhs * self
}
}
impl Div<f64> for Vec4 {
type Output = Vec4;
fn div(self, rhs: f64) -> Self::Output {
let rhs_inverse = 1.0 / rhs;
Vec4 {
x: self.x * rhs_inverse,
y: self.y * rhs_inverse,
z: self.z * rhs_inverse,
w: self.w * rhs_inverse,
}
}
}
impl DivAssign<f64> for Vec4 {
fn div_assign(&mut self, rhs: f64) {
*self = *self / rhs;
}
}
impl Neg for Vec4 {
type Output = Vec4;
fn neg(self) -> Self::Output {
Vec4 {
x: -self.x,
y: -self.y,
z: -self.z,
w: -self.w,
}
}
}
impl From<[f64; 4]> for Vec4 {
fn from(s: [f64; 4]) -> Self {
Vec4 {
x: s[0],
y: s[1],
z: s[2],
w: s[3],
}
}
}
impl From<(f64, f64, f64, f64)> for Vec4 {
fn from(t: (f64, f64, f64, f64)) -> Self {
Vec4 {
x: t.0,
y: t.1,
z: t.2,
w: t.3,
}
}
}
impl TryFrom<Vec<f64>> for Vec4 {
type Error = &'static str;
fn try_from(v: Vec<f64>) -> Result<Self, Self::Error> {
if v.len() != 4 {
Err("Vec4 can only be build from a vector of length 4.")
} else {
Ok(Vec4 {
x: v[0],
y: v[1],
z: v[2],
w: v[3],
})
}
}
}
impl TryFrom<&[f64]> for Vec4 {
type Error = &'static str;
fn try_from(s: &[f64]) -> Result<Self, Self::Error> {
if s.len() != 4 {
Err("Vec4 can only be build from a slice of length 4.")
} else {
Ok(Vec4 {
x: s[0],
y: s[1],
z: s[2],
w: s[3],
})
}
}
}
impl Index<usize> for Vec4 {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
3 => &self.w,
_ => panic!(
"index out of bounds: the len is 4 but the index is {}",
index
),
}
}
}
impl IndexMut<usize> for Vec4 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
3 => &mut self.w,
_ => panic!(
"index out of bounds: the len is 4 but the index is {}",
index
),
}
}
}