use core::ops::{Add, Mul, Neg, Sub};
use crate::Fixed;
fn normalising_shift(largest: u64) -> u32 {
largest.leading_zeros().saturating_sub(26)
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Vec2 {
pub x: Fixed,
pub y: Fixed,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Vec3 {
pub x: Fixed,
pub y: Fixed,
pub z: Fixed,
}
impl Vec2 {
pub const ZERO: Self = Self {
x: Fixed::ZERO,
y: Fixed::ZERO,
};
pub const X: Self = Self {
x: Fixed::ONE,
y: Fixed::ZERO,
};
pub const Y: Self = Self {
x: Fixed::ZERO,
y: Fixed::ONE,
};
#[must_use]
pub const fn new(x: Fixed, y: Fixed) -> Self {
Self { x, y }
}
#[must_use]
pub const fn from_ints(x: i32, y: i32) -> Self {
Self {
x: Fixed::from_int(x),
y: Fixed::from_int(y),
}
}
#[must_use]
pub fn dot(self, other: Self) -> Fixed {
self.x.saturating_mul(other.x) + self.y.saturating_mul(other.y)
}
#[must_use]
pub fn cross(self, other: Self) -> Fixed {
self.x.saturating_mul(other.y) - self.y.saturating_mul(other.x)
}
#[must_use]
pub fn length_squared(self) -> Fixed {
self.dot(self)
}
#[must_use]
pub fn length_squared_wide(self) -> crate::Wide {
self.x.wide_mul(self.x) + self.y.wide_mul(self.y)
}
#[must_use]
pub fn length(self) -> Fixed {
self.length_squared_wide().sqrt()
}
#[must_use]
pub fn distance(self, other: Self) -> Fixed {
(self - other).length()
}
#[must_use]
pub fn normalize(self) -> Option<Self> {
let largest = self
.x
.to_bits()
.unsigned_abs()
.max(self.y.to_bits().unsigned_abs());
if largest == 0 {
return None;
}
let shift = normalising_shift(largest);
let scaled = Self::new(
Fixed::from_bits(self.x.to_bits() << shift),
Fixed::from_bits(self.y.to_bits() << shift),
);
let length = scaled.length();
Some(Self::new(
scaled.x.saturating_div(length),
scaled.y.saturating_div(length),
))
}
#[must_use]
pub fn lerp(self, other: Self, t: Fixed) -> Self {
let t = t.clamp(Fixed::ZERO, Fixed::ONE);
self + (other - self) * t
}
#[must_use]
pub fn project_onto_unit(self, direction: Self) -> Self {
direction * self.dot(direction)
}
#[must_use]
pub fn slide_along(self, normal: Self) -> Self {
self - self.project_onto_unit(normal)
}
#[must_use]
pub fn rotate(self, angle: crate::Angle) -> Self {
let (sin, cos) = angle.sin_cos();
Self::new(
self.x.saturating_mul(cos) - self.y.saturating_mul(sin),
self.x.saturating_mul(sin) + self.y.saturating_mul(cos),
)
}
#[must_use]
pub fn perpendicular(self) -> Self {
Self::new(-self.y, self.x)
}
}
impl Vec3 {
pub const ZERO: Self = Self {
x: Fixed::ZERO,
y: Fixed::ZERO,
z: Fixed::ZERO,
};
#[must_use]
pub const fn new(x: Fixed, y: Fixed, z: Fixed) -> Self {
Self { x, y, z }
}
#[must_use]
pub const fn from_ints(x: i32, y: i32, z: i32) -> Self {
Self {
x: Fixed::from_int(x),
y: Fixed::from_int(y),
z: Fixed::from_int(z),
}
}
#[must_use]
pub fn dot(self, other: Self) -> Fixed {
self.x.saturating_mul(other.x)
+ self.y.saturating_mul(other.y)
+ self.z.saturating_mul(other.z)
}
#[must_use]
pub fn cross(self, other: Self) -> Self {
Self::new(
self.y.saturating_mul(other.z) - self.z.saturating_mul(other.y),
self.z.saturating_mul(other.x) - self.x.saturating_mul(other.z),
self.x.saturating_mul(other.y) - self.y.saturating_mul(other.x),
)
}
#[must_use]
pub fn length_squared(self) -> Fixed {
self.dot(self)
}
#[must_use]
pub fn length_squared_wide(self) -> crate::Wide {
self.x.wide_mul(self.x) + self.y.wide_mul(self.y) + self.z.wide_mul(self.z)
}
#[must_use]
pub fn length(self) -> Fixed {
self.length_squared_wide().sqrt()
}
#[must_use]
pub fn distance(self, other: Self) -> Fixed {
(self - other).length()
}
#[must_use]
pub fn normalize(self) -> Option<Self> {
let largest = self
.x
.to_bits()
.unsigned_abs()
.max(self.y.to_bits().unsigned_abs())
.max(self.z.to_bits().unsigned_abs());
if largest == 0 {
return None;
}
let shift = normalising_shift(largest);
let scaled = Self::new(
Fixed::from_bits(self.x.to_bits() << shift),
Fixed::from_bits(self.y.to_bits() << shift),
Fixed::from_bits(self.z.to_bits() << shift),
);
let length = scaled.length();
Some(Self::new(
scaled.x.saturating_div(length),
scaled.y.saturating_div(length),
scaled.z.saturating_div(length),
))
}
#[must_use]
pub fn lerp(self, other: Self, t: Fixed) -> Self {
let t = t.clamp(Fixed::ZERO, Fixed::ONE);
self + (other - self) * t
}
#[must_use]
pub fn slide_along(self, normal: Self) -> Self {
self - normal * self.dot(normal)
}
}
impl Add for Vec2 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self::new(self.x + other.x, self.y + other.y)
}
}
impl Sub for Vec2 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self::new(self.x - other.x, self.y - other.y)
}
}
impl Neg for Vec2 {
type Output = Self;
fn neg(self) -> Self {
Self::new(-self.x, -self.y)
}
}
impl Mul<Fixed> for Vec2 {
type Output = Self;
fn mul(self, factor: Fixed) -> Self {
Self::new(self.x.saturating_mul(factor), self.y.saturating_mul(factor))
}
}
impl Add for Vec3 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self::new(self.x + other.x, self.y + other.y, self.z + other.z)
}
}
impl Sub for Vec3 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self::new(self.x - other.x, self.y - other.y, self.z - other.z)
}
}
impl Neg for Vec3 {
type Output = Self;
fn neg(self) -> Self {
Self::new(-self.x, -self.y, -self.z)
}
}
impl Mul<Fixed> for Vec3 {
type Output = Self;
fn mul(self, factor: Fixed) -> Self {
Self::new(
self.x.saturating_mul(factor),
self.y.saturating_mul(factor),
self.z.saturating_mul(factor),
)
}
}