use std::convert::*;
use std::ops::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "vulkano")]
use vulkano::pipeline::vertex::{VertexMember, VertexMemberTy};
#[cfg(feature = "vulkano")]
use vulkano::format::ClearValue;
use super::*;
pub trait Vector {
type Scalar;
const DIMS: usize;
fn length(&self) -> Self::Scalar;
fn dot(&self, other: &Self) -> Self::Scalar;
fn ones() -> Self;
fn zeros() -> Self;
fn unit(&self) -> Self;
fn scalar_mul(&self, s: &Self::Scalar) -> Self;
fn vector_add(&self, v: &Self) -> Self;
}
macro_rules! decl_vec {
($name:ident, $($dims:ident),+) => {
#[repr(C)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct $name {
$(pub $dims: f32),+
}
impl $name {
#[doc = "Create a new vector with the given components."]
#[inline(always)]
pub fn new($($dims: f32),+) -> Self {
$name {
$($dims),+
}
}
$(#[doc = "Create a unit vector along this axis."]
pub fn $dims() -> Self {
let mut v = Self::zeros();
v.$dims = 1.0;
v
})+
#[doc = "Get the angle between this vector and another."]
pub fn angle_between(&self, other: &$name) -> Angle {
Angle::acos(self.dot(&other) / self.length() / other.length()).unwrap()
}
}
impl Vector for $name {
type Scalar = f32;
const DIMS: usize = count_args!($($dims),+);
fn length(&self) -> f32 {
self.dot(self).sqrt()
}
fn dot(&self, other: &Self) -> f32 {
0.0 $(+ self.$dims * other.$dims)+
}
#[inline(always)]
fn ones() -> Self {
$name::new($(replace_tt!($dims, 1.0)),+)
}
#[inline(always)]
fn zeros() -> Self {
$name::new($(replace_tt!($dims, 0.0)),+)
}
fn unit(&self) -> Self {
self / self.length()
}
#[inline(always)]
fn scalar_mul(&self, s: &f32) -> Self {
s * self
}
#[inline(always)]
fn vector_add(&self, v: &Self) -> Self {
self + v
}
}
#[cfg(feature = "vulkano")]
unsafe impl VertexMember for $name {
#[inline(always)]
fn format() -> (VertexMemberTy, usize) {
(VertexMemberTy::F32, count_args!($($dims),+))
}
}
impl Default for $name {
#[inline(always)]
fn default() -> $name {
$name::zeros()
}
}
impl AsRef<[f32]> for $name {
#[inline(always)]
fn as_ref(&self) -> &[f32] {
unsafe { &*(self as *const $name as *const [f32; count_args!($($dims),+)]) }
}
}
impl AsMut<[f32]> for $name {
#[inline(always)]
fn as_mut(&mut self) -> &mut [f32] {
unsafe { &mut *(self as *mut $name as *mut [f32; count_args!($($dims),+)]) }
}
}
impl Into<Vec<f32>> for $name {
fn into(self) -> Vec<f32> {
Vec::from(self.as_ref())
}
}
impl Index<usize> for $name {
type Output = f32;
#[inline(always)]
fn index(&self, idx: usize) -> &f32 {
&self.as_ref()[idx]
}
}
impl IndexMut<usize> for $name {
#[inline(always)]
fn index_mut(&mut self, idx: usize) -> &mut f32 {
&mut self.as_mut()[idx]
}
}
impl ApproxEq for $name {
fn approx_eq(self, rhs: $name) -> bool {
$(self.$dims.approx_eq(rhs.$dims))&+
}
#[doc = "Compare two vectors for approximate equality.\n\n"]
#[doc = "Uses a third vector for component-wise thresholds."]
fn within_threshold(self, rhs: $name, threshold: $name) -> bool {
$(self.$dims.within_threshold(rhs.$dims, threshold.$dims))&+
}
}
decl_vec!(@VECTOP $name, Add, add, +, $($dims),+);
decl_vec!(@VECTOP $name, Sub, sub, -, $($dims),+);
decl_vec!(@VECTOP $name, Mul, mul, *, $($dims),+);
decl_vec!(@VECTOP $name, Div, div, /, $($dims),+);
decl_vec!(@VECTASGN $name, AddAssign, add_assign, +=, $($dims),+);
decl_vec!(@VECTASGN $name, SubAssign, sub_assign, -=, $($dims),+);
decl_vec!(@VECTASGN $name, MulAssign, mul_assign, *=, $($dims),+);
decl_vec!(@VECTASGN $name, DivAssign, div_assign, /=, $($dims),+);
decl_vec!(@SCALAR_MUL $name, $($dims),+);
decl_vec!(@SCALAR_DIV $name, $($dims),+);
decl_vec!(@MULASGN $name, f32, $($dims),+);
decl_vec!(@MULASGN $name, &f32, $($dims),+);
decl_vec!(@DIVASGN $name, f32, $($dims),+);
decl_vec!(@DIVASGN $name, &f32, $($dims),+);
decl_vec!(@NEG $name, $name, $($dims),+);
decl_vec!(@NEG $name, &$name, $($dims),+);
};
(@VECTOP $name:ident, $trait:ident, $func:ident, $op:tt, $($dims:ident),+) => {
decl_vec!(@VECTOP_SINGLE $name, $trait, $func, $op, $name, $name, $($dims),+);
decl_vec!(@VECTOP_SINGLE $name, $trait, $func, $op, $name, &$name, $($dims),+);
decl_vec!(@VECTOP_SINGLE $name, $trait, $func, $op, &$name, $name, $($dims),+);
decl_vec!(@VECTOP_SINGLE $name, $trait, $func, $op, &$name, &$name, $($dims),+);
};
(@VECTOP_SINGLE $name:ident, $trait:ident, $func:ident, $op:tt, $lhs:ty, $rhs:ty, $($dims:ident),+) => {
impl $trait<$rhs> for $lhs {
type Output = $name;
#[doc = "Component-wise arithemetic operation."]
fn $func(self, rhs: $rhs) -> $name {
$name {
$($dims: self.$dims $op rhs.$dims),+
}
}
}
};
(@VECTASGN $name:ident, $trait:ident, $func:ident, $op:tt, $($dims:ident),+) => {
decl_vec!(@VECTASGN_SINGLE $name, $trait, $func, $op, $name, $($dims),+);
decl_vec!(@VECTASGN_SINGLE $name, $trait, $func, $op, &$name, $($dims),+);
};
(@VECTASGN_SINGLE $name:ident, $trait:ident, $func:ident, $op:tt, $rhs:ty, $($dims:ident),+) => {
impl $trait<$rhs> for $name {
#[doc = "Component-wise arithmetic assignment operation."]
fn $func(&mut self, rhs: $rhs) {
$(self.$dims $op rhs.$dims;)+
}
}
};
(@SCALAR_MUL $name:ident, $($dims:ident),+) => {
decl_vec!(@SCALAR_MUL_SINGLE $name, $name, f32, $($dims),+);
decl_vec!(@SCALAR_MUL_SINGLE $name, $name, &f32, $($dims),+);
decl_vec!(@SCALAR_MUL_SINGLE $name, &$name, f32, $($dims),+);
decl_vec!(@SCALAR_MUL_SINGLE $name, &$name, &f32, $($dims),+);
};
(@SCALAR_MUL_SINGLE $name:ident, $lhs:ty, $rhs:ty, $($dims:ident),+) => {
impl Mul<$rhs> for $lhs {
type Output = $name;
fn mul(self, rhs: $rhs) -> $name {
$name {
$($dims: self.$dims * rhs),+
}
}
}
impl Mul<$lhs> for $rhs {
type Output = $name;
fn mul(self, rhs: $lhs) -> $name {
$name {
$($dims: rhs.$dims * self),+
}
}
}
};
(@MULASGN $name:ident, $rhs:ty, $($dims:ident),+) => {
impl MulAssign<$rhs> for $name {
fn mul_assign(&mut self, rhs: $rhs) {
$(self.$dims *= rhs;)+
}
}
};
(@SCALAR_DIV $name:ident, $($dims:ident),+) => {
decl_vec!(@SCALAR_DIV_SINGLE $name, $name, f32, $($dims),+);
decl_vec!(@SCALAR_DIV_SINGLE $name, $name, &f32, $($dims),+);
decl_vec!(@SCALAR_DIV_SINGLE $name, &$name, f32, $($dims),+);
decl_vec!(@SCALAR_DIV_SINGLE $name, &$name, &f32, $($dims),+);
};
(@SCALAR_DIV_SINGLE $name:ident, $lhs:ty, $rhs:ty, $($dims:ident),+) => {
impl Div<$rhs> for $lhs {
type Output = $name;
fn div(self, rhs: $rhs) -> $name {
$name {
$($dims: self.$dims / rhs),+
}
}
}
};
(@DIVASGN $name:ident, $rhs:ty, $($dims:ident),+) => {
impl DivAssign<$rhs> for $name {
fn div_assign(&mut self, rhs: $rhs) {
$(self.$dims /= rhs;)+
}
}
};
(@NEG $name:ident, $type:ty, $($dims:ident),+) => {
impl Neg for $type {
type Output = $name;
fn neg(self) -> $name {
$name {
$($dims: -self.$dims),+
}
}
}
};
}
decl_vec!(Vec2, x, y);
decl_vec!(Vec3, x, y, z);
decl_vec!(Vec4, x, y, z, w);
impl Vec2 {
#[inline(always)]
pub fn extend(self, z: f32) -> Vec3 {
Vec3 {
x: self.x,
y: self.y,
z,
}
}
}
#[cfg(feature = "vulkano")]
impl Into<ClearValue> for Vec2 {
#[inline(always)]
fn into(self) -> ClearValue {
ClearValue::Float([self.x, self.y, 0.0, 1.0])
}
}
impl Vec3 {
pub fn cross(self, other: &Vec3) -> Vec3 {
Vec3 {
x: self.y * other.z - self.z * other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
#[inline(always)]
pub fn extend(self, w: f32) -> Vec4 {
Vec4 {
x: self.x,
y: self.y,
z: self.z,
w,
}
}
#[inline(always)]
pub fn homogeneous(self) -> Vec4 {
self.extend(1.0)
}
#[inline(always)]
pub fn truncate(self) -> Vec2 {
Vec2 {
x: self.x,
y: self.y,
}
}
}
#[cfg(feature = "vulkano")]
impl Into<ClearValue> for Vec3 {
#[inline(always)]
fn into(self) -> ClearValue {
ClearValue::Float([self.x, self.y, self.z, 1.0])
}
}
impl Vec4 {
#[inline(always)]
pub fn truncate(self) -> Vec3 {
Vec3 {
x: self.x,
y: self.y,
z: self.z,
}
}
pub fn homogenize(self) -> Vec3 {
self.truncate() / self.w
}
}
#[cfg(feature = "vulkano")]
impl Into<ClearValue> for Vec4 {
#[inline(always)]
fn into(self) -> ClearValue {
ClearValue::Float([self.x, self.y, self.z, self.w])
}
}
pub fn project<V: Vector>(from: &V, onto: &V) -> V {
onto.scalar_mul(&from.unit().dot(&onto.unit()))
}
#[inline(always)]
pub fn length<V: Vector>(v: &V) -> V::Scalar {
v.length()
}
#[inline(always)]
pub fn dot<V: Vector>(a: &V, b: &V) -> V::Scalar {
a.dot(b)
}
#[inline(always)]
pub fn normalize<V: Vector>(v: &V) -> V {
v.unit()
}
pub fn cross(a: &Vec3, b: &Vec3) -> Vec3 {
a.cross(b)
}
#[cfg(test)]
macro_rules! test_vec {
($name:ident, $($dims:ident),+) => {
#[test]
fn dimension() {
assert_eq!($name::DIMS, count_args!($($dims),+));
}
#[test]
fn ones() {
let v = $name::ones();
$(assert_approx_eq!(v.$dims, 1.0);)+
}
#[test]
fn zeros() {
let v = $name::zeros();
$(assert_approx_eq!(v.$dims, 0.0);)+
}
#[test]
fn add() {
let v = $name::ones() + $name::ones();
$(assert_approx_eq!(v.$dims, 2.0);)+
let mut v = $name::ones();
v += $name::ones();
$(assert_approx_eq!(v.$dims, 2.0);)+
}
#[test]
fn sub() {
let v = $name::ones() - $name::ones();
$(assert_approx_eq!(v.$dims, 0.0);)+
let mut v = $name::ones();
v -= $name::ones();
$(assert_approx_eq!(v.$dims, 0.0);)+
}
#[test]
fn scalar_mul() {
let v = $name::ones() * 2.0;
$(assert_approx_eq!(v.$dims, 2.0);)+
let v = 2.0_f32 * $name::ones();
$(assert_approx_eq!(v.$dims, 2.0);)+
let mut v = $name::ones();
v *= 2.0;
$(assert_approx_eq!(v.$dims, 2.0);)+
}
#[test]
fn scalar_div() {
let v = $name::ones() / 2.0;
$(assert_approx_eq!(v.$dims, 0.5);)+
let mut v = $name::ones();
v /= 2.0;
$(assert_approx_eq!(v.$dims, 0.5);)+
}
#[test]
fn unit_axes() {
$(let v = $name::$dims();
assert_approx_eq!(v.$dims, 1.0);
assert_approx_eq!(v.length(), 1.0);)+
}
#[test]
fn dot() {
assert_approx_eq!($name::ones().dot(&$name::ones()), ($name::DIMS as f32));
let v = $name::ones() * 2.0;
assert_approx_eq!(v.dot(&v), (count_args!($($dims),+) as f32 * 4.0));
$(let v = $name::$dims() * 3.0;
assert_approx_eq!(v.dot(&v), 9.0);)+
}
#[test]
fn length() {
assert_approx_eq!($name::zeros().length(), 0.0);
assert_approx_eq!($name::ones().length(), (count_args!($($dims),+) as f32).sqrt());
$(assert_approx_eq!($name::$dims().length(), 1.0);)+
}
#[test]
fn index() {
let mut v = $name::zeros();
for i in 0..count_args!($($dims),+) {
v[i] = i as f32;
}
for i in 0..count_args!($($dims),+) {
assert_approx_eq!(v[i], (i as f32));
}
}
#[test]
fn into_vec() {
let v: Vec<_> = $name::zeros().into();
assert_eq!(v.len(), count_args!($($dims),+));
for n in v {
assert_approx_eq!(n, 0.0);
}
}
};
}
#[cfg(test)]
mod test_vec2 {
use super::*;
test_vec!(Vec2, x, y);
use std::mem::{size_of, align_of};
#[test]
fn mem_layout() {
assert_eq!(size_of::<Vec2>(), 8);
assert_eq!(align_of::<Vec2>(), 4);
assert_eq!(offset_of!(Vec2, x), 0);
assert_eq!(offset_of!(Vec2, y), 4);
}
}
#[cfg(test)]
mod test_vec3 {
use super::*;
test_vec!(Vec3, x, y, z);
use std::mem::{size_of, align_of};
#[test]
fn mem_layout() {
assert_eq!(size_of::<Vec3>(), 12);
assert_eq!(align_of::<Vec3>(), 4);
assert_eq!(offset_of!(Vec3, x), 0);
assert_eq!(offset_of!(Vec3, y), 4);
assert_eq!(offset_of!(Vec3, z), 8);
}
}
#[cfg(test)]
mod test_vec4 {
use super::*;
test_vec!(Vec4, x, y, z, w);
use std::mem::{size_of, align_of};
#[test]
fn mem_layout() {
assert_eq!(size_of::<Vec4>(), 16);
assert_eq!(align_of::<Vec4>(), 4);
assert_eq!(offset_of!(Vec4, x), 0);
assert_eq!(offset_of!(Vec4, y), 4);
assert_eq!(offset_of!(Vec4, z), 8);
assert_eq!(offset_of!(Vec4, w), 12);
}
}