use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct GlobalTransform(pub [f32; 16]);
impl GlobalTransform {
pub fn identity() -> Self {
#[rustfmt::skip]
let m = [
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
];
Self(m)
}
pub fn mul(&self, rhs: &GlobalTransform) -> GlobalTransform {
let a = &self.0;
let b = &rhs.0;
let mut out = [0.0f32; 16];
for col in 0..4 {
for row in 0..4 {
out[col * 4 + row] = a[row] * b[col * 4]
+ a[4 + row] * b[col * 4 + 1]
+ a[8 + row] * b[col * 4 + 2]
+ a[12 + row] * b[col * 4 + 3];
}
}
GlobalTransform(out)
}
pub fn translation(&self) -> [f32; 3] {
[self.0[12], self.0[13], self.0[14]]
}
}
impl Default for GlobalTransform {
fn default() -> Self {
Self::identity()
}
}
pub fn mat4_mul(a: &[f32; 16], b: &[f32; 16]) -> [f32; 16] {
let mut out = [0.0f32; 16];
for col in 0..4 {
for row in 0..4 {
out[col * 4 + row] = a[row] * b[col * 4]
+ a[4 + row] * b[col * 4 + 1]
+ a[8 + row] * b[col * 4 + 2]
+ a[12 + row] * b[col * 4 + 3];
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identity_default() {
let g = GlobalTransform::default();
assert_eq!(g, GlobalTransform::identity());
}
#[test]
fn identity_mul_identity() {
let id = GlobalTransform::identity();
let result = id.mul(&id);
for i in 0..16 {
assert!((result.0[i] - id.0[i]).abs() < 1e-6);
}
}
#[test]
fn translation_extraction() {
let mut g = GlobalTransform::identity();
g.0[12] = 5.0;
g.0[13] = 10.0;
g.0[14] = -3.0;
assert_eq!(g.translation(), [5.0, 10.0, -3.0]);
}
#[test]
fn mul_with_translation() {
let mut a = GlobalTransform::identity();
a.0[12] = 1.0; let mut b = GlobalTransform::identity();
b.0[12] = 2.0; let c = a.mul(&b);
assert!((c.0[12] - 3.0).abs() < 1e-6); }
#[test]
fn mat4_mul_identity() {
#[rustfmt::skip]
let id = [
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
];
let result = mat4_mul(&id, &id);
for i in 0..16 {
assert!((result[i] - id[i]).abs() < 1e-6);
}
}
#[test]
fn mat4_mul_translation_compose() {
#[rustfmt::skip]
let a = [
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 0.0, 0.0, 1.0,
];
#[rustfmt::skip]
let b = [
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
5.0, 0.0, 0.0, 1.0,
];
let c = mat4_mul(&a, &b);
assert!((c[12] - 15.0).abs() < 1e-6);
}
}