use crate::core::{
storage::{Vector3x3, XYZ},
traits::matrix::{FloatMatrix3x3, Matrix3x3, MatrixConst},
};
use crate::{DQuat, DVec2, DVec3, Quat, Vec2, Vec3, Vec3A, Vec3Swizzles};
#[cfg(not(target_arch = "spirv"))]
use core::fmt;
use core::{
cmp::Ordering,
ops::{Add, Deref, DerefMut, Mul, Sub},
};
#[cfg(feature = "std")]
use std::iter::{Product, Sum};
macro_rules! impl_mat3_methods {
($t:ty, $vec3: ident, $vec2:ident, $quat:ident, $inner:ident) => {
#[inline(always)]
pub const fn zero() -> Self {
Self($inner::ZERO)
}
#[inline(always)]
pub const fn identity() -> Self {
Self($inner::IDENTITY)
}
#[inline(always)]
pub fn from_cols(x_axis: $vec3, y_axis: $vec3, z_axis: $vec3) -> Self {
Self(Matrix3x3::from_cols(x_axis.0, y_axis.0, z_axis.0))
}
#[inline(always)]
pub fn from_cols_array(m: &[$t; 9]) -> Self {
Self(Matrix3x3::from_cols_array(m))
}
#[inline(always)]
pub fn to_cols_array(&self) -> [$t; 9] {
self.0.to_cols_array()
}
#[inline(always)]
pub fn from_cols_array_2d(m: &[[$t; 3]; 3]) -> Self {
Self(Matrix3x3::from_cols_array_2d(m))
}
#[inline(always)]
pub fn to_cols_array_2d(&self) -> [[$t; 3]; 3] {
self.0.to_cols_array_2d()
}
#[inline(always)]
pub fn from_scale_angle_translation(scale: $vec2, angle: $t, translation: $vec2) -> Self {
Self(FloatMatrix3x3::from_scale_angle_translation(
scale.0,
angle,
translation.0,
))
}
#[inline(always)]
pub fn from_quat(rotation: $quat) -> Self {
Self($inner::from_quaternion(rotation.0.into()))
}
#[inline(always)]
pub fn from_axis_angle(axis: $vec3, angle: $t) -> Self {
Self(FloatMatrix3x3::from_axis_angle(axis.0, angle))
}
#[inline(always)]
pub fn from_rotation_ypr(yaw: $t, pitch: $t, roll: $t) -> Self {
let quat = $quat::from_rotation_ypr(yaw, pitch, roll);
Self::from_quat(quat)
}
#[inline(always)]
pub fn from_rotation_x(angle: $t) -> Self {
Self($inner::from_rotation_x(angle))
}
#[inline(always)]
pub fn from_rotation_y(angle: $t) -> Self {
Self($inner::from_rotation_y(angle))
}
#[inline(always)]
pub fn from_rotation_z(angle: $t) -> Self {
Self($inner::from_rotation_z(angle))
}
#[inline(always)]
pub fn from_scale(scale: $vec3) -> Self {
Self(Matrix3x3::from_scale(scale.0))
}
#[inline]
pub fn is_finite(&self) -> bool {
self.x_axis.is_finite() && self.y_axis.is_finite() && self.z_axis.is_finite()
}
#[inline]
pub fn is_nan(&self) -> bool {
self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan()
}
#[inline(always)]
pub fn transpose(&self) -> Self {
Self(self.0.transpose())
}
#[inline(always)]
pub fn determinant(&self) -> $t {
self.0.determinant()
}
#[inline(always)]
pub fn inverse(&self) -> Self {
Self(self.0.inverse())
}
#[inline(always)]
pub fn mul_vec3(&self, other: $vec3) -> $vec3 {
self.mul_vec3_as_vec3a(other)
}
#[inline]
pub fn mul_mat3(&self, other: &Self) -> Self {
Self::from_cols(
self.mul_vec3(other.x_axis),
self.mul_vec3(other.y_axis),
self.mul_vec3(other.z_axis),
)
}
#[inline(always)]
pub fn add_mat3(&self, other: &Self) -> Self {
Self(self.0.add_matrix(&other.0))
}
#[inline(always)]
pub fn sub_mat3(&self, other: &Self) -> Self {
Self(self.0.sub_matrix(&other.0))
}
#[inline(always)]
pub fn mul_scalar(&self, other: $t) -> Self {
Self(self.0.mul_scalar(other))
}
#[inline(always)]
pub fn transform_point2(&self, other: $vec2) -> $vec2 {
self.transform_point2_as_vec3a(other)
}
#[inline(always)]
pub fn transform_vector2(&self, other: $vec2) -> $vec2 {
self.transform_vector2_as_vec3a(other)
}
#[inline(always)]
pub fn abs_diff_eq(&self, other: Self, max_abs_diff: $t) -> bool {
self.0.abs_diff_eq(&other.0, max_abs_diff)
}
};
}
macro_rules! impl_mat3_traits {
($t:ty, $new:ident, $mat3:ident, $vec3: ident) => {
#[inline(always)]
pub fn $new(x_axis: $vec3, y_axis: $vec3, z_axis: $vec3) -> $mat3 {
$mat3::from_cols(x_axis, y_axis, z_axis)
}
impl Default for $mat3 {
#[inline(always)]
fn default() -> Self {
Self::identity()
}
}
impl PartialEq for $mat3 {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.x_axis.eq(&other.x_axis)
&& self.y_axis.eq(&other.y_axis)
&& self.z_axis.eq(&other.z_axis)
}
}
impl PartialOrd for $mat3 {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_ref().partial_cmp(other.as_ref())
}
}
impl Deref for $mat3 {
type Target = Vector3x3<$vec3>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self as *const Self::Target) }
}
}
impl DerefMut for $mat3 {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self as *mut Self as *mut Self::Target) }
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Display for $mat3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}, {}, {}]", self.x_axis, self.y_axis, self.z_axis)
}
}
#[cfg(not(target_arch = "spirv"))]
impl fmt::Debug for $mat3 {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("$mat3")
.field("x_axis", &self.x_axis)
.field("y_axis", &self.y_axis)
.field("z_axis", &self.z_axis)
.finish()
}
}
impl AsRef<[$t; 9]> for $mat3 {
#[inline(always)]
fn as_ref(&self) -> &[$t; 9] {
unsafe { &*(self as *const Self as *const [$t; 9]) }
}
}
impl AsMut<[$t; 9]> for $mat3 {
#[inline(always)]
fn as_mut(&mut self) -> &mut [$t; 9] {
unsafe { &mut *(self as *mut Self as *mut [$t; 9]) }
}
}
impl Add<$mat3> for $mat3 {
type Output = Self;
#[inline(always)]
fn add(self, other: Self) -> Self {
self.add_mat3(&other)
}
}
impl Sub<$mat3> for $mat3 {
type Output = Self;
#[inline(always)]
fn sub(self, other: Self) -> Self {
self.sub_mat3(&other)
}
}
impl Mul<$mat3> for $mat3 {
type Output = Self;
#[inline(always)]
fn mul(self, other: Self) -> Self {
self.mul_mat3(&other)
}
}
impl Mul<$vec3> for $mat3 {
type Output = $vec3;
#[inline(always)]
fn mul(self, other: $vec3) -> $vec3 {
self.mul_vec3(other)
}
}
impl Mul<$mat3> for $t {
type Output = $mat3;
#[inline(always)]
fn mul(self, other: $mat3) -> $mat3 {
other.mul_scalar(self)
}
}
impl Mul<$t> for $mat3 {
type Output = Self;
#[inline(always)]
fn mul(self, other: $t) -> Self {
self.mul_scalar(other)
}
}
#[cfg(feature = "std")]
impl<'a> Sum<&'a Self> for $mat3 {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
iter.fold($mat3::zero(), |a, &b| Self::add(a, b))
}
}
#[cfg(feature = "std")]
impl<'a> Product<&'a Self> for $mat3 {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
iter.fold($mat3::identity(), |a, &b| Self::mul(a, b))
}
}
};
}
type InnerF32 = Vector3x3<XYZ<f32>>;
#[derive(Clone, Copy)]
#[cfg_attr(not(target_arch = "spirv"), repr(C))]
pub struct Mat3(pub(crate) InnerF32);
impl Mat3 {
impl_mat3_methods!(f32, Vec3, Vec2, Quat, InnerF32);
#[inline]
pub fn mul_vec3a(&self, other: Vec3A) -> Vec3A {
let mut res = Vec3A::from(self.x_axis) * other.xxx();
res = Vec3A::from(self.y_axis).mul_add(other.yyy(), res);
res = Vec3A::from(self.z_axis).mul_add(other.zzz(), res);
res
}
#[inline(always)]
fn mul_vec3_as_vec3a(&self, other: Vec3) -> Vec3 {
Vec3::from(self.mul_vec3a(Vec3A::from(other)))
}
#[inline]
pub fn transform_point2_as_vec3a(&self, other: Vec2) -> Vec2 {
let mut res = Vec3A::from(self.x_axis).mul(Vec3A::splat(other.x));
res = Vec3A::from(self.y_axis).mul_add(Vec3A::splat(other.y), res);
res = Vec3A::from(self.z_axis).add(res);
res = res.mul(res.zzz().recip());
res.xy()
}
#[inline]
pub fn transform_vector2_as_vec3a(&self, other: Vec2) -> Vec2 {
let mut res = Vec3A::from(self.x_axis).mul(Vec3A::splat(other.x));
res = Vec3A::from(self.y_axis).mul_add(Vec3A::splat(other.y), res);
res.xy()
}
#[inline(always)]
pub fn as_f64(&self) -> DMat3 {
DMat3::from_cols(
self.x_axis.as_f64(),
self.y_axis.as_f64(),
self.z_axis.as_f64(),
)
}
}
impl_mat3_traits!(f32, mat3, Mat3, Vec3);
impl Mul<Vec3A> for Mat3 {
type Output = Vec3A;
#[inline(always)]
fn mul(self, other: Vec3A) -> Vec3A {
self.mul_vec3a(other)
}
}
type InnerF64 = Vector3x3<XYZ<f64>>;
#[derive(Clone, Copy)]
#[cfg_attr(not(target_arch = "spirv"), repr(C))]
pub struct DMat3(pub(crate) InnerF64);
impl DMat3 {
impl_mat3_methods!(f64, DVec3, DVec2, DQuat, InnerF64);
#[inline(always)]
pub fn mul_vec3_as_vec3a(&self, other: DVec3) -> DVec3 {
DVec3(self.0.mul_vector(other.0))
}
#[inline(always)]
pub fn transform_point2_as_vec3a(&self, other: DVec2) -> DVec2 {
DVec2(self.0.transform_point2(other.0))
}
#[inline(always)]
pub fn transform_vector2_as_vec3a(&self, other: DVec2) -> DVec2 {
DVec2(self.0.transform_vector2(other.0))
}
#[inline(always)]
pub fn as_f32(&self) -> Mat3 {
Mat3::from_cols(
self.x_axis.as_f32(),
self.y_axis.as_f32(),
self.z_axis.as_f32(),
)
}
}
impl_mat3_traits!(f64, dmat3, DMat3, DVec3);