pub use num_traits::{cast, Float, One, Zero};
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub struct Vector2<S> {
pub x: S,
pub y: S,
}
impl<S: Sized> Vector2<S> {
pub const fn new(x: S, y: S) -> Self {
Vector2 { x, y }
}
#[inline]
pub fn normalize(self) -> Self
where
S: One + Float + std::ops::Div + std::ops::Mul,
{
self * (S::one() / self.magnitude())
}
#[inline]
pub fn magnitude(self) -> S
where
S: Float,
{
Float::sqrt(Self::dot(self, self))
}
#[inline]
pub fn dot(a: Self, b: Self) -> <S as std::ops::Add>::Output
where
S: std::ops::Mul<Output = S> + std::ops::Add,
{
a.x * b.x + a.y * b.y
}
#[inline]
pub fn distance(self, other: Self) -> S
where
S: Float,
{
(other - self).magnitude()
}
pub fn extend(self, z: S) -> Vector3<S> {
Vector3::new(self.x, self.y, z)
}
pub fn map<F, T>(self, mut f: F) -> Vector2<T>
where
F: FnMut(S) -> T,
{
Vector2::new(f(self.x), f(self.y))
}
}
impl<S: Zero + Copy + PartialEq> Zero for Vector2<S> {
#[inline]
fn zero() -> Self {
Vector2::new(S::zero(), S::zero())
}
#[inline]
fn is_zero(&self) -> bool {
*self == Vector2::zero()
}
}
impl<S> std::ops::Add<Vector2<S>> for Vector2<S>
where
S: std::ops::Add<Output = S> + Copy,
{
type Output = Self;
fn add(self, other: Vector2<S>) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl<S> std::ops::Sub<Vector2<S>> for Vector2<S>
where
S: std::ops::Sub<Output = S> + Copy,
{
type Output = Self;
fn sub(self, other: Vector2<S>) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl<S> std::ops::Mul<S> for Vector2<S>
where
S: std::ops::Mul<Output = S> + Copy,
{
type Output = Self;
fn mul(self, s: S) -> Self {
Self {
x: self.x * s,
y: self.y * s,
}
}
}
impl<S> From<Point2<S>> for Vector2<S> {
fn from(p: Point2<S>) -> Self {
Self::new(p.x, p.y)
}
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub struct Vector3<S> {
pub x: S,
pub y: S,
pub z: S,
}
impl<S> Vector3<S> {
pub const fn new(x: S, y: S, z: S) -> Self {
Vector3 { x, y, z }
}
pub fn extend(self, w: S) -> Vector4<S> {
Vector4::new(self.x, self.y, self.z, w)
}
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub struct Vector4<S> {
pub x: S,
pub y: S,
pub z: S,
pub w: S,
}
impl<S> Vector4<S> {
pub const fn new(x: S, y: S, z: S, w: S) -> Self {
Vector4 { x, y, z, w }
}
}
impl<S> std::ops::Mul<S> for Vector4<S>
where
S: std::ops::Mul<Output = S> + Copy,
{
type Output = Self;
fn mul(self, s: S) -> Self {
Self {
x: self.x * s,
y: self.y * s,
z: self.z * s,
w: self.w * s,
}
}
}
impl<S> std::ops::Mul<Vector4<S>> for Vector4<S>
where
S: std::ops::Mul<Output = S> + std::ops::Add<Output = S> + Copy,
{
type Output = S;
fn mul(self, other: Vector4<S>) -> S {
other.x * self.x + other.y * self.y + other.z * self.z + other.w * self.w
}
}
impl<S> std::ops::Add<Vector4<S>> for Vector4<S>
where
S: std::ops::Add<Output = S> + Copy,
{
type Output = Self;
fn add(self, other: Vector4<S>) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
w: self.w + other.w,
}
}
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub struct Point2<S> {
pub x: S,
pub y: S,
}
impl<S> Point2<S> {
pub const fn new(x: S, y: S) -> Self {
Point2 { x, y }
}
pub fn map<F, T>(self, mut f: F) -> Point2<T>
where
F: FnMut(S) -> T,
{
Point2::new(f(self.x), f(self.y))
}
}
impl<S> From<Vector2<S>> for Point2<S> {
fn from(v: Vector2<S>) -> Self {
Self::new(v.x, v.y)
}
}
impl<S> std::ops::Div<S> for Point2<S>
where
S: std::ops::Div<Output = S> + Copy,
{
type Output = Self;
fn div(self, s: S) -> Self {
Self {
x: self.x / s,
y: self.y / s,
}
}
}
impl<S> std::ops::Mul<S> for Point2<S>
where
S: std::ops::Mul<Output = S> + Copy,
{
type Output = Self;
fn mul(self, s: S) -> Self {
Self {
x: self.x * s,
y: self.y * s,
}
}
}
impl<S> std::ops::Add<Vector2<S>> for Point2<S>
where
S: std::ops::Add<Output = S> + Copy,
{
type Output = Self;
fn add(self, other: Vector2<S>) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl<S> std::ops::Sub<Vector2<S>> for Point2<S>
where
S: std::ops::Sub<Output = S> + Copy,
{
type Output = Self;
fn sub(self, other: Vector2<S>) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl<S> std::ops::Sub<Point2<S>> for Point2<S>
where
S: std::ops::Sub<Output = S> + Copy,
{
type Output = Vector2<S>;
fn sub(self, other: Point2<S>) -> Vector2<S> {
Vector2 {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Matrix4<S> {
pub x: Vector4<S>,
pub y: Vector4<S>,
pub z: Vector4<S>,
pub w: Vector4<S>,
}
impl<S: Copy + Zero + One> Matrix4<S> {
#[inline]
#[rustfmt::skip]
pub fn new(
c0r0: S, c0r1: S, c0r2: S, c0r3: S,
c1r0: S, c1r1: S, c1r2: S, c1r3: S,
c2r0: S, c2r1: S, c2r2: S, c2r3: S,
c3r0: S, c3r1: S, c3r2: S, c3r3: S,
) -> Self {
Self {
x: Vector4::new(c0r0, c0r1, c0r2, c0r3),
y: Vector4::new(c1r0, c1r1, c1r2, c1r3),
z: Vector4::new(c2r0, c2r1, c2r2, c2r3),
w: Vector4::new(c3r0, c3r1, c3r2, c3r3),
}
}
#[inline]
#[rustfmt::skip]
pub fn identity() -> Self {
Matrix4::new(
S::one(), S::zero(), S::zero(), S::zero(),
S::zero(), S::one(), S::zero(), S::zero(),
S::zero(), S::zero(), S::one(), S::zero(),
S::zero(), S::zero(), S::zero(), S::one(),
)
}
#[inline]
pub fn from_translation(v: Vector3<S>) -> Self {
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
S::one(), S::zero(), S::zero(), S::zero(),
S::zero(), S::one(), S::zero(), S::zero(),
S::zero(), S::zero(), S::one(), S::zero(),
v.x, v.y, v.z, S::one(),
)
}
#[inline]
pub fn row(&self, n: usize) -> Vector4<S> {
match n {
0 => Vector4::new(self.x.x, self.y.x, self.z.x, self.w.x),
1 => Vector4::new(self.x.y, self.y.y, self.z.y, self.w.y),
2 => Vector4::new(self.x.z, self.y.z, self.z.z, self.w.z),
3 => Vector4::new(self.x.w, self.y.w, self.z.w, self.w.w),
_ => panic!("Matrix4::row: invalid row number: {}", n),
}
}
#[inline]
pub fn from_scale(value: S) -> Matrix4<S> {
Matrix4::from_nonuniform_scale(value, value, value)
}
#[inline]
#[rustfmt::skip]
pub fn from_nonuniform_scale(x: S, y: S, z: S) -> Matrix4<S> {
Matrix4::new(
x, S::zero(), S::zero(), S::zero(),
S::zero(), y, S::zero(), S::zero(),
S::zero(), S::zero(), z, S::zero(),
S::zero(), S::zero(), S::zero(), S::one(),
)
}
}
impl<S> std::ops::Mul<Matrix4<S>> for Matrix4<S>
where
S: std::ops::Mul<Output = S> + std::ops::Add<Output = S> + Copy,
{
type Output = Self;
#[rustfmt::skip]
fn mul(self, rhs: Matrix4<S>) -> Matrix4<S> {
let a = self.x;
let b = self.y;
let c = self.z;
let d = self.w;
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4 {
x: a * rhs.x.x + b * rhs.x.y + c * rhs.x.z + d * rhs.x.w,
y: a * rhs.y.x + b * rhs.y.y + c * rhs.y.z + d * rhs.y.w,
z: a * rhs.z.x + b * rhs.z.y + c * rhs.z.z + d * rhs.z.w,
w: a * rhs.w.x + b * rhs.w.y + c * rhs.w.z + d * rhs.w.w,
}
}
}
impl std::ops::Mul<Vector3<f32>> for Matrix4<f32> {
type Output = Vector3<f32>;
fn mul(self, vec: Vector3<f32>) -> Vector3<f32> {
let vec = vec.extend(1.);
Vector3::new(self.row(0) * vec, self.row(1) * vec, self.row(2) * vec)
}
}
impl std::ops::Mul<Point2<f32>> for Matrix4<f32> {
type Output = Point2<f32>;
fn mul(self, p: Point2<f32>) -> Point2<f32> {
let vec = Vector4::new(p.x, p.y, 0., 1.);
Point2::new(self.row(0) * vec, self.row(1) * vec)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Ortho<S> {
pub left: S,
pub right: S,
pub bottom: S,
pub top: S,
pub near: S,
pub far: S,
}
impl<S: Float> From<Ortho<S>> for Matrix4<S> {
fn from(ortho: Ortho<S>) -> Matrix4<S> {
let two: S = cast(2).unwrap();
let c0r0 = two / (ortho.right - ortho.left);
let c0r1 = S::zero();
let c0r2 = S::zero();
let c0r3 = S::zero();
let c1r0 = S::zero();
let c1r1 = two / (ortho.top - ortho.bottom);
let c1r2 = S::zero();
let c1r3 = S::zero();
let c2r0 = S::zero();
let c2r1 = S::zero();
let c2r2 = -two / (ortho.far - ortho.near);
let c2r3 = S::zero();
let c3r0 = -(ortho.right + ortho.left) / (ortho.right - ortho.left);
let c3r1 = -(ortho.top + ortho.bottom) / (ortho.top - ortho.bottom);
let c3r2 = -(ortho.far + ortho.near) / (ortho.far - ortho.near);
let c3r3 = S::one();
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3,
c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3,
)
}
}