Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new version of modor_math #284

Merged
merged 2 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PUBLISHED-CRATES
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
modor_derive
modor_internal
modor
modor_math
3 changes: 3 additions & 0 deletions crates/modor_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ license.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
approx.workspace = true

[lints]
workspace = true
2 changes: 1 addition & 1 deletion crates/modor_internal/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# modor_internal

Internal module of [Modor](https://github.com/modor-engine/modor) for common utils.
Internal crate of [Modor](https://github.com/modor-engine/modor) for common utils.
2 changes: 2 additions & 0 deletions crates/modor_internal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(missing_docs)]

pub mod testing;

pub use approx;
8 changes: 4 additions & 4 deletions crates/modor_internal/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
macro_rules! retry {
($count:literal, $expr:expr) => {
for i in 0..$count {
let r = std::panic::catch_unwind(|| $expr);
let r = ::std::panic::catch_unwind(|| $expr);
if r.is_ok() {
break;
}
if i == $count - 1 {
std::panic::resume_unwind(r.unwrap_err());
::std::panic::resume_unwind(r.unwrap_err());
} else {
std::thread::sleep(std::time::Duration::from_secs(1));
::std::thread::sleep(std::time::Duration::from_secs(1));
}
}
};
Expand All @@ -18,6 +18,6 @@ macro_rules! retry {
#[macro_export]
macro_rules! assert_approx_eq {
($left:expr, $right:expr) => {
approx::assert_abs_diff_eq!($left, $right, epsilon = 0.000_01)
::approx::assert_abs_diff_eq!($left, $right, epsilon = 0.000_01)
};
}
26 changes: 26 additions & 0 deletions crates/modor_math/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "modor_math"
description = "Math module of Modor game engine"
readme = "./README.md"
keywords = ["modor", "math", "vector"]
categories = ["game-engines"]
exclude = [".github", "README.md"]
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
approx.workspace = true

[dev-dependencies]
modor_internal.workspace = true
modor.workspace = true

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test.workspace = true

[lints]
workspace = true
3 changes: 3 additions & 0 deletions crates/modor_math/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# modor_math

Math module of [Modor](https://github.com/modor-engine/modor).
11 changes: 11 additions & 0 deletions crates/modor_math/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Math module of Modor.

mod matrices_4d;
mod quaternion;
mod vectors_2d;
mod vectors_3d;

pub use matrices_4d::*;
pub use quaternion::*;
pub use vectors_2d::*;
pub use vectors_3d::*;
134 changes: 134 additions & 0 deletions crates/modor_math/src/matrices_4d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use crate::{Vec2, Vec3};
use std::ops::Mul;

/// A 4x4 matrix.
#[derive(Clone, Copy, Debug)]
pub struct Mat4 {
elements: [[f32; 4]; 4],
}

impl Mat4 {
/// The identity matrix.
pub const IDENTITY: Self = Self::from_array([
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
]);

/// Creates a new matrix from `elements` in an array of arrays.
///
/// Each array of `elements` corresponds to a line of the matrix.
#[inline]
pub const fn from_array(elements: [[f32; 4]; 4]) -> Self {
Self { elements }
}

/// Creates a new transform matrix from a `position`.
pub const fn from_position(position: Vec3) -> Self {
Self::from_array([
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[position.x, position.y, position.z, 1.],
])
}

/// Creates a new transform matrix from a `scale`.
pub const fn from_scale(scale: Vec3) -> Self {
Self::from_array([
[scale.x, 0., 0., 0.],
[0., scale.y, 0., 0.],
[0., 0., scale.z, 0.],
[0., 0., 0., 1.],
])
}

/// Returns the array of arrays containing the elements of the matrix.
///
/// Each array of the array corresponds to a line of the matrix.
pub const fn to_array(&self) -> [[f32; 4]; 4] {
self.elements
}

fn multiply_matrix_part(part: &[f32; 4], other_matrix: &[[f32; 4]; 4], j: usize) -> f32 {
(0..4)
.map(|k| part[k] * other_matrix[k][j])
.reduce(|a, b| a + b)
.expect("internal error: wrong matrix size")
}
}

impl Mul<Vec2> for Mat4 {
type Output = Vec2;

fn mul(self, rhs: Vec2) -> Self::Output {
let point = [rhs.x, rhs.y, 0., 1.];
Vec2::new(
Self::multiply_matrix_part(&point, &self.elements, 0),
Self::multiply_matrix_part(&point, &self.elements, 1),
)
}
}

impl Mul<Vec3> for Mat4 {
type Output = Vec3;

fn mul(self, rhs: Vec3) -> Self::Output {
let point = [rhs.x, rhs.y, rhs.z, 1.];
Vec3::new(
Self::multiply_matrix_part(&point, &self.elements, 0),
Self::multiply_matrix_part(&point, &self.elements, 1),
Self::multiply_matrix_part(&point, &self.elements, 2),
)
}
}

impl Mul<Self> for Mat4 {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
Self::from_array([
[
Self::multiply_matrix_part(&self.elements[0], &rhs.elements, 0),
Self::multiply_matrix_part(&self.elements[0], &rhs.elements, 1),
Self::multiply_matrix_part(&self.elements[0], &rhs.elements, 2),
Self::multiply_matrix_part(&self.elements[0], &rhs.elements, 3),
],
[
Self::multiply_matrix_part(&self.elements[1], &rhs.elements, 0),
Self::multiply_matrix_part(&self.elements[1], &rhs.elements, 1),
Self::multiply_matrix_part(&self.elements[1], &rhs.elements, 2),
Self::multiply_matrix_part(&self.elements[1], &rhs.elements, 3),
],
[
Self::multiply_matrix_part(&self.elements[2], &rhs.elements, 0),
Self::multiply_matrix_part(&self.elements[2], &rhs.elements, 1),
Self::multiply_matrix_part(&self.elements[2], &rhs.elements, 2),
Self::multiply_matrix_part(&self.elements[2], &rhs.elements, 3),
],
[
Self::multiply_matrix_part(&self.elements[3], &rhs.elements, 0),
Self::multiply_matrix_part(&self.elements[3], &rhs.elements, 1),
Self::multiply_matrix_part(&self.elements[3], &rhs.elements, 2),
Self::multiply_matrix_part(&self.elements[3], &rhs.elements, 3),
],
])
}
}

impl Mul<Mat4> for Vec2 {
type Output = Self;

fn mul(self, rhs: Mat4) -> Self::Output {
rhs * self
}
}

impl Mul<Mat4> for Vec3 {
type Output = Self;

fn mul(self, rhs: Mat4) -> Self::Output {
rhs * self
}
}
157 changes: 157 additions & 0 deletions crates/modor_math/src/quaternion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use crate::{Mat4, Vec3};
use std::f32::consts::PI;
use std::ops::{Mul, MulAssign};

/// A quaternion used to store a rotation.
#[derive(Clone, Copy, Debug)]
pub struct Quat {
pub(crate) x: f32,
pub(crate) y: f32,
pub(crate) z: f32,
pub(crate) w: f32,
}

impl Default for Quat {
fn default() -> Self {
Self::ZERO
}
}

impl Quat {
/// A quaternion corresponding to no rotation.
pub const ZERO: Self = Self {
x: 0.,
y: 0.,
z: 0.,
w: 1.,
};

/// Creates a new quaternion from an `axis` and an `angle` in radians.
pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
let axis = axis.with_magnitude(1.).unwrap_or(Vec3::ZERO);
let angle = Self::normalize_angle(angle);
Self {
x: axis.x * (angle / 2.).sin(),
y: axis.y * (angle / 2.).sin(),
z: axis.z * (angle / 2.).sin(),
w: (angle / 2.).cos(),
}
}

/// Creates a new quaternion from an `angle` in radians around the X axis.
#[inline]
pub fn from_x(angle: f32) -> Self {
Self::from_axis_angle(Vec3::X, angle)
}

/// Creates a new quaternion from an `angle` in radians around the Y axis.
#[inline]
pub fn from_y(angle: f32) -> Self {
Self::from_axis_angle(Vec3::Y, angle)
}

/// Creates a new quaternion from an `angle` in radians around the Z axis.
#[inline]
pub fn from_z(angle: f32) -> Self {
Self::from_axis_angle(Vec3::Z, angle)
}

/// Returns the normalized axis, or `None` if the angle is `0.0`.
#[allow(clippy::float_cmp)]
pub fn axis(self) -> Option<Vec3> {
(self.w.powi(2) != 1.).then(|| {
Vec3::new(
self.x / self.w.mul_add(-self.w, 1.).sqrt(),
self.y / self.w.mul_add(-self.w, 1.).sqrt(),
self.z / self.w.mul_add(-self.w, 1.).sqrt(),
)
})
}

/// Returns the angle in radians normalized between `0` and `2*π`.
#[inline]
pub fn angle(self) -> f32 {
2. * self.w.acos()
}

/// Returns the rotation matrix.
pub fn matrix(self) -> Mat4 {
Mat4::from_array([
[
1. - (2. * self.y).mul_add(self.y, 2. * self.z * self.z),
(2. * self.x).mul_add(self.y, 2. * self.w * self.z),
(2. * self.x).mul_add(self.z, -2. * self.w * self.y),
0.,
],
[
(2. * self.x).mul_add(self.y, -2. * self.w * self.z),
1. - (2. * self.x).mul_add(self.x, 2. * self.z * self.z),
(2. * self.y).mul_add(self.z, 2. * self.w * self.x),
0.,
],
[
(2. * self.x).mul_add(self.z, 2. * self.w * self.y),
(2. * self.y).mul_add(self.z, -2. * self.w * self.x),
1. - (2. * self.x).mul_add(self.x, 2. * self.y * self.y),
0.,
],
[0., 0., 0., 1.],
])
}

/// Returns the quaternion with a scaled angle.
///
/// Axis is unchanged.
pub fn with_scale(self, scale: f32) -> Self {
let axis = self.axis().unwrap_or(Vec3::ZERO);
let angle = self.angle();
Self::from_axis_angle(axis, angle * scale)
}

/// Returns the quaternion rotated with `other`.
///
/// The same operation can be done using multiplication of both quaternions.
pub fn with_rotation(self, other: Self) -> Self {
self * other
}

fn normalize_angle(mut angle: f32) -> f32 {
while angle > 2. * PI {
angle -= 2. * PI;
}
while angle < 0. {
angle += 2. * PI;
}
angle
}
}

impl Mul<Self> for Quat {
type Output = Self;

fn mul(self, rhs: Self) -> Self::Output {
Self {
x: self.y.mul_add(
rhs.z,
self.w
.mul_add(rhs.x, self.x.mul_add(rhs.w, -self.z * rhs.y)),
),
y: self.z.mul_add(
rhs.x,
self.y
.mul_add(rhs.w, self.w.mul_add(rhs.y, -self.x * rhs.z)),
),
z: self.z.mul_add(rhs.w, self.w.mul_add(rhs.z, self.x * rhs.y)),
w: self.w.mul_add(
rhs.w,
-self.x.mul_add(rhs.x, self.y.mul_add(rhs.y, self.z * rhs.z)),
),
}
}
}

impl MulAssign<Self> for Quat {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
Loading
Loading