vrust 0.0.1

VRust game engine
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use std::sync::Arc;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use super::super::objc;
use super::super::system::file::File;
use super::super::util::cell::DebugCell;
use super::number::Number;

#[repr(simd)]
pub struct SVec4D(pub f64, pub f64, pub f64, pub f64);
#[repr(simd)]
pub struct SVec3D(pub f64, pub f64, pub f64);
#[repr(simd)]
pub struct SVec2D(pub f64, pub f64);
#[repr(simd)]
pub struct SVec4F(pub f32, pub f32, pub f32, pub f32);
#[repr(simd)]
pub struct SVec3F(pub f32, pub f32, pub f32);
#[repr(simd)]
pub struct SVec2F(pub f32, pub f32);
#[repr(simd)]
pub struct SVec4U32(pub u32, pub u32, pub u32, pub u32);
#[repr(simd)]
pub struct SVec3U32(pub u32, pub u32, pub u32);
#[repr(simd)]
pub struct SVec2U32(pub u32, pub u32);

#[repr(usize)]
#[derive(Debug, Clone, Copy)]
pub enum Axis {
    X,
    Y,
    Z,
    W,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Vec4<T>
where
    T: Number,
{
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T,
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
unsafe impl<T> objc::Encode for Vec4<T>
where
    T: Number,
{
    fn encode() -> objc::Encoding {
        let encoding = format!(
            "{{?={}{}{}{}}}",
            T::objc_encode(),
            T::objc_encode(),
            T::objc_encode(),
            T::objc_encode()
        );
        unsafe { objc::Encoding::from_str(&encoding) }
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct Vec3<T>
where
    T: Number,
{
    pub x: T,
    pub y: T,
    pub z: T,
}

macro_rules! as_expr { ($e:expr) => {$e} }

macro_rules! op3 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<'a, 'b, T> $tra<&'b Vec3<T>> for &'a Vec3<T> where T: Number {
            type Output = Vec3<T>;
            fn $func(self, other: &'b Vec3<T>) -> Vec3<T> {
                Vec3 {
                    x: as_expr!(self.x $opt other.x),
                    y: as_expr!(self.y $opt other.y),
                    z: as_expr!(self.z $opt other.z),
                }
            }
        }
    )
}

macro_rules! sop3 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<'a, T> $tra<T> for &'a Vec3<T> where T: Number {
            type Output = Vec3<T>;
            fn $func(self, other: T) -> Vec3<T> {
                Vec3 {
                    x: as_expr!(self.x $opt other),
                    y: as_expr!(self.y $opt other),
                    z: as_expr!(self.z $opt other),
                }
            }
        }
    )
}

macro_rules! opasg3 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<'a, T> $tra<&'a Vec3<T>> for Vec3<T> where T: Number {
            fn $func(&mut self, other: &'a Vec3<T>) {
                as_expr!(self.x $opt other.x);
                as_expr!(self.y $opt other.y);
                as_expr!(self.z $opt other.z);
            }
        }
    )
}

macro_rules! sopasg3 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<T> $tra<T> for Vec3<T> where T: Number {
            fn $func(&mut self, other: T) {
                as_expr!(self.x $opt other);
                as_expr!(self.y $opt other);
                as_expr!(self.z $opt other);
            }
        }
    )
}

op3!(add, Add, +);
op3!(sub, Sub, -);
op3!(mul, Mul, *);
op3!(div, Div, /);

sop3!(add, Add, +);
sop3!(sub, Sub, -);
sop3!(mul, Mul, *);
sop3!(div, Div, /);

opasg3!(add_assign, AddAssign, +=);
opasg3!(sub_assign, SubAssign, -=);
opasg3!(mul_assign, MulAssign, *=);
opasg3!(div_assign, DivAssign, /=);

sopasg3!(add_assign, AddAssign, +=);
sopasg3!(sub_assign, SubAssign, -=);
sopasg3!(mul_assign, MulAssign, *=);
sopasg3!(div_assign, DivAssign, /=);

impl<'a, E> Neg for &'a Vec3<E>
where
    E: Number + Neg<Output = E>,
{
    type Output = Vec3<E>;
    fn neg(self) -> Vec3<E> {
        Vec3 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }
}

impl<T> Vec3<T>
where
    T: Number,
{
    pub fn new(e: T) -> Self {
        Vec3 { x: e, y: e, z: e }
    }

    pub fn new_from_file(f: &Arc<DebugCell<File>>) -> Self {
        let mut f = f.borrow_mut();
        Vec3 {
            x: f.read_type(),
            y: f.read_type(),
            z: f.read_type(),
        }
    }

    pub fn dot(&self, o: &Vec3<T>) -> T {
        (self.x * o.x) + (self.y * o.y) + (self.z * o.z)
    }

    pub fn cross(&self, o: &Vec3<T>) -> Self {
        Vec3 {
            x: self.y * o.z - self.z * o.y,
            y: self.z * o.x - self.x * o.z,
            z: self.x * o.y - self.y * o.x,
        }
    }

    pub fn length(&self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }

    pub fn absolute_length(&self) -> T {
        self.x.abs() + self.y.abs() + self.z.abs()
    }

    pub fn square_length(&self) -> T {
        (self.x * self.x) + (self.y * self.y) + (self.z * self.z)
    }

    pub fn normalize(&mut self) {
        let len = ((self.x * self.x) + (self.y * self.y) + (self.z * self.z)).sqrt();
        self.x /= len;
        self.y /= len;
        self.z /= len;
    }

    pub fn normalized(&self) -> Self {
        let len = ((self.x * self.x) + (self.y * self.y) + (self.z * self.z)).sqrt();
        Vec3 {
            x: self.x / len,
            y: self.y / len,
            z: self.z / len,
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
unsafe impl<T> objc::Encode for Vec3<T>
where
    T: Number,
{
    fn encode() -> objc::Encoding {
        let encoding = format!("![3{}]", T::objc_encode());
        unsafe { objc::Encoding::from_str(&encoding) }
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Vec2<T>
where
    T: Number,
{
    pub x: T,
    pub y: T,
}

macro_rules! op2 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<'a, 'b, T> $tra<&'b Vec2<T>> for &'a Vec2<T> where T: Number {
            type Output = Vec2<T>;
            fn $func(self, other: &'b Vec2<T>) -> Vec2<T> {
                Vec2 {
                    x: as_expr!(self.x $opt other.x),
                    y: as_expr!(self.y $opt other.y),
                }
            }
        }
    )
}

macro_rules! sop2 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<'a, T> $tra<T> for &'a Vec2<T> where T: Number {
            type Output = Vec2<T>;
            fn $func(self, other: T) -> Vec2<T> {
                Vec2 {
                    x: as_expr!(self.x $opt other),
                    y: as_expr!(self.y $opt other),
                }
            }
        }
    )
}

macro_rules! opasg2 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<'a, T> $tra<&'a Vec2<T>> for Vec2<T> where T: Number {
            fn $func(&mut self, other: &'a Vec2<T>) {
                as_expr!(self.x $opt other.x);
                as_expr!(self.y $opt other.y);
            }
        }
    )
}

macro_rules! sopasg2 {
    ($func:ident, $tra:ident, $opt:tt) => (
        impl<T> $tra<T> for Vec2<T> where T: Number {
            fn $func(&mut self, other: T) {
                as_expr!(self.x $opt other);
                as_expr!(self.y $opt other);
            }
        }
    )
}

op2!(add, Add, +);
op2!(sub, Sub, -);
op2!(mul, Mul, *);
op2!(div, Div, /);

sop2!(add, Add, +);
sop2!(sub, Sub, -);
sop2!(mul, Mul, *);
sop2!(div, Div, /);

opasg2!(add_assign, AddAssign, +=);
opasg2!(sub_assign, SubAssign, -=);
opasg2!(mul_assign, MulAssign, *=);
opasg2!(div_assign, DivAssign, /=);

sopasg2!(add_assign, AddAssign, +=);
sopasg2!(sub_assign, SubAssign, -=);
sopasg2!(mul_assign, MulAssign, *=);
sopasg2!(div_assign, DivAssign, /=);

impl<'a, E> Neg for &'a Vec2<E>
where
    E: Number + Neg<Output = E>,
{
    type Output = Vec2<E>;
    fn neg(self) -> Vec2<E> {
        Vec2 {
            x: -self.x,
            y: -self.y,
        }
    }
}

impl<T> Vec2<T>
where
    T: Number,
{
    pub fn new(e: T) -> Vec2<T> {
        Vec2 { x: e, y: e }
    }

    pub fn dot(&self, o: &Vec2<T>) -> T {
        self.x * o.x + self.y * o.y
    }

    pub fn cross(&self, o: &Vec2<T>) -> Vec2<T> {
        println!("{:?}", o);
        println!("In 2D we can not have a cross product");
        Vec2 {
            x: T::new(0.0),
            y: T::new(0.0),
        }
    }

    pub fn length(&self) -> T {
        (self.x * self.x + self.y * self.y).sqrt()
    }

    pub fn absolute_length(&self) -> T {
        self.x.abs() + self.y.abs()
    }

    pub fn square_length(&self) -> T {
        self.x * self.x + self.y * self.y
    }

    pub fn normalize(&mut self) {
        let len = (self.x * self.x + self.y * self.y).sqrt();
        self.x /= len;
        self.y /= len;
    }

    pub fn normalized(&self) -> Vec2<T> {
        let len = (self.x * self.x + self.y * self.y).sqrt();
        Vec2 {
            x: self.x / len,
            y: self.y / len,
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
unsafe impl<T> objc::Encode for Vec2<T>
where
    T: Number,
{
    fn encode() -> objc::Encoding {
        let encoding = format!("{{?={}{}}}", T::objc_encode(), T::objc_encode());
        unsafe { objc::Encoding::from_str(&encoding) }
    }
}