#[macro_use]
extern crate approx;
mod matrix1x3 {
use ezcgmath::matrix::Matrix1x3;
const A: Matrix1x3 = Matrix1x3 {
c00: 1.0,
c01: 2.0,
c02: 3.0,
};
const B: Matrix1x3 = Matrix1x3 {
c00: 4.0,
c01: 5.0,
c02: 6.0,
};
#[test]
fn add() {
let result = Matrix1x3 {
c00: 5.0,
c01: 7.0,
c02: 9.0,
};
assert_ulps_eq!(A + B, result);
let mut mat = A.clone();
mat += B;
assert_ulps_eq!(mat, result);
}
#[test]
fn subtract() {
let result = Matrix1x3 {
c00: -3.0,
c01: -3.0,
c02: -3.0,
};
assert_ulps_eq!(A - B, result);
let mut mat = A.clone();
mat -= B;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_scalar() {
let scalar = 2.0;
let result = Matrix1x3 {
c00: 2.0,
c01: 4.0,
c02: 6.0,
};
assert_ulps_eq!(A * scalar, result);
let mut mat = A.clone();
mat *= scalar;
assert_ulps_eq!(mat, result);
}
}
mod matrix2x2 {
use ezcgmath::matrix::Matrix2x2;
const A: Matrix2x2 = Matrix2x2 {
c00: 1.0, c10: 2.0,
c01: 3.0, c11: 4.0,
};
const B: Matrix2x2 = Matrix2x2 {
c00: 5.0, c10: 6.0,
c01: 7.0, c11: 8.0,
};
#[test]
fn add() {
let result = Matrix2x2 {
c00: 6.0, c10: 8.0,
c01: 10.0, c11: 12.0,
};
assert_ulps_eq!(A + B, result);
let mut mat = A.clone();
mat += B;
assert_ulps_eq!(mat, result);
}
#[test]
fn subtract() {
let result = Matrix2x2 {
c00: -4.0, c10: -4.0,
c01: -4.0, c11: -4.0,
};
assert_ulps_eq!(A - B, result);
let mut mat = A.clone();
mat -= B;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_scalar() {
let scalar = 2.0;
let result = Matrix2x2 {
c00: 2.0, c10: 4.0,
c01: 6.0, c11: 8.0,
};
assert_ulps_eq!(A * scalar, result);
let mut mat = A.clone();
mat *= scalar;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_matrix() {
let result = Matrix2x2 {
c00: 19.0, c10: 22.0,
c01: 43.0, c11: 50.0,
};
assert_ulps_eq!(A * B, result);
}
#[test]
fn determinant() {
assert_ulps_eq!(A.determinant(), -2.0);
assert_ulps_eq!(B.determinant(), -2.0);
}
}
mod matrix3x3 {
use ezcgmath::matrix::Matrix3x3;
const A: Matrix3x3 = Matrix3x3 {
c00: 1.0, c10: 2.0, c20: 3.0,
c01: 4.0, c11: 5.0, c21: 6.0,
c02: 7.0, c12: 8.0, c22: 9.0,
};
const B: Matrix3x3 = Matrix3x3 {
c00: 10.0, c10: 11.0, c20: 12.0,
c01: 13.0, c11: 14.0, c21: 15.0,
c02: 16.0, c12: 17.0, c22: 18.0,
};
#[test]
fn add() {
let result = Matrix3x3 {
c00: 11.0, c10: 13.0, c20: 15.0,
c01: 17.0, c11: 19.0, c21: 21.0,
c02: 23.0, c12: 25.0, c22: 27.0,
};
assert_ulps_eq!(A + B, result);
let mut mat = A.clone();
mat += B;
assert_ulps_eq!(mat, result);
}
#[test]
fn subtract() {
let result = Matrix3x3 {
c00: -9.0, c10: -9.0, c20: -9.0,
c01: -9.0, c11: -9.0, c21: -9.0,
c02: -9.0, c12: -9.0, c22: -9.0,
};
assert_ulps_eq!(A - B, result);
let mut mat = A.clone();
mat -= B;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_scalar() {
let scalar = 2.0;
let result = Matrix3x3 {
c00: 2.0, c10: 4.0, c20: 6.0,
c01: 8.0, c11: 10.0, c21: 12.0,
c02: 14.0, c12: 16.0, c22: 18.0,
};
assert_ulps_eq!(A * scalar, result);
let mut mat = A.clone();
mat *= scalar;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_matrix() {
let result = Matrix3x3 {
c00: 84.0, c10: 90.0, c20: 96.0,
c01: 201.0, c11: 216.0, c21: 231.0,
c02: 318.0, c12: 342.0, c22: 366.0,
};
assert_ulps_eq!(A * B, result);
}
#[test]
fn matrix_of_minors() {
assert_ulps_eq!(
Matrix3x3 {
c00: 1.0, c10: 2.0, c20: 1.0,
c01: 6.0, c11: -1.0, c21: 0.0,
c02: -1.0, c12: -2.0, c22: -1.0,
}.matrix_of_minors(),
Matrix3x3 {
c00: 1.0, c10: -6.0, c20: -13.0,
c01: 0.0, c11: 0.0, c21: 0.0,
c02: 1.0, c12: -6.0, c22: -13.0,
}
);
}
#[test]
fn matrix_of_cofactors() {
assert_ulps_eq!(A.matrix_of_cofactors(), Matrix3x3 {
c00: A.c00, c10: -A.c10, c20: A.c20,
c01: -A.c01, c11: A.c11, c21: -A.c21,
c02: A.c02, c12: -A.c12, c22: A.c22,
});
assert_ulps_eq!(B.matrix_of_cofactors(), Matrix3x3 {
c00: B.c00, c10: -B.c10, c20: B.c20,
c01: -B.c01, c11: B.c11, c21: -B.c21,
c02: B.c02, c12: -B.c12, c22: B.c22,
});
}
#[test]
fn transpose() {
assert_ulps_eq!(A.transpose(), Matrix3x3 {
c00: A.c00, c10: A.c01, c20: A.c02,
c01: A.c10, c11: A.c11, c21: A.c12,
c02: A.c20, c12: A.c21, c22: A.c22,
});
assert_ulps_eq!(B.transpose(), Matrix3x3 {
c00: B.c00, c10: B.c01, c20: B.c02,
c01: B.c10, c11: B.c11, c21: B.c12,
c02: B.c20, c12: B.c21, c22: B.c22,
});
}
#[test]
fn determinant() {
assert_ulps_eq!(A.determinant(), 0.0);
assert_ulps_eq!(B.determinant(), 0.0);
}
#[test]
fn inverse() {
assert_ulps_eq!(
Matrix3x3 {
c00: 12.0, c10: 68.0, c20: 8.0,
c01: 68.0, c11: 98.0, c21: 6.0,
c02: 7.0, c12: 59.0, c22: 86.0,
}.inverse(),
Matrix3x3 {
c00: -0.02975909654, c10: 0.01981482574, c20: 0.001385858348,
c01: 0.02139971693, c11: -0.003597334434, c21: -0.001739694521,
c02: -0.01225894911, c12: 0.0008551040868, c22: 0.01270861591,
}
);
}
}
mod matrix4x4 {
use ezcgmath::{Degrees, Radians};
use ezcgmath::matrix::Matrix4x4;
use ezcgmath::quaternion::Quaternion;
const A: Matrix4x4 = Matrix4x4 {
c00: 1.0, c10: 2.0, c20: 3.0, c30: 4.0,
c01: 5.0, c11: 6.0, c21: 7.0, c31: 8.0,
c02: 9.0, c12: 10.0, c22: 11.0, c32: 12.0,
c03: 13.0, c13: 14.0, c23: 15.0, c33: 16.0,
};
const B: Matrix4x4 = Matrix4x4 {
c00: 17.0, c10: 18.0, c20: 19.0, c30: 20.0,
c01: 21.0, c11: 22.0, c21: 23.0, c31: 24.0,
c02: 25.0, c12: 26.0, c22: 27.0, c32: 28.0,
c03: 29.0, c13: 30.0, c23: 31.0, c33: 32.0,
};
#[test]
fn add() {
let result = Matrix4x4 {
c00: 18.0, c10: 20.0, c20: 22.0, c30: 24.0,
c01: 26.0, c11: 28.0, c21: 30.0, c31: 32.0,
c02: 34.0, c12: 36.0, c22: 38.0, c32: 40.0,
c03: 42.0, c13: 44.0, c23: 46.0, c33: 48.0,
};
assert_ulps_eq!(A + B, result);
let mut mat = A.clone();
mat += B;
assert_ulps_eq!(mat, result);
}
#[test]
fn subtract() {
let result = Matrix4x4 {
c00: -16.0, c10: -16.0, c20: -16.0, c30: -16.0,
c01: -16.0, c11: -16.0, c21: -16.0, c31: -16.0,
c02: -16.0, c12: -16.0, c22: -16.0, c32: -16.0,
c03: -16.0, c13: -16.0, c23: -16.0, c33: -16.0,
};
assert_ulps_eq!(A - B, result);
let mut mat = A.clone();
mat -= B;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_scalar() {
let scalar = 2.0;
let result = Matrix4x4 {
c00: 2.0, c10: 4.0, c20: 6.0, c30: 8.0,
c01: 10.0, c11: 12.0, c21: 14.0, c31: 16.0,
c02: 18.0, c12: 20.0, c22: 22.0, c32: 24.0,
c03: 26.0, c13: 28.0, c23: 30.0, c33: 32.0,
};
assert_ulps_eq!(A * scalar, result);
let mut mat = A.clone();
mat *= scalar;
assert_ulps_eq!(mat, result);
}
#[test]
fn multiply_matrix() {
let result = Matrix4x4 {
c00: 250.0, c10: 260.0, c20: 270.0, c30: 280.0,
c01: 618.0, c11: 644.0, c21: 670.0, c31: 696.0,
c02: 986.0, c12: 1028.0, c22: 1070.0, c32: 1112.0,
c03: 1354.0, c13: 1412.0, c23: 1470.0, c33: 1528.0,
};
assert_ulps_eq!(A * B, result);
}
fn verify_proj(matrix: Matrix4x4, fov: Degrees, aspect_ratio: f32, near: f32, far: f32) {
let x_scale = 2.0 / Radians::from(fov).0.tan();
let y_scale = x_scale / aspect_ratio;
let z_scale = far / (far-near);
let z_translation = -near * far / (far-near);
assert_ulps_eq!(matrix.c00, x_scale);
assert_ulps_eq!(matrix.c11, y_scale);
assert_ulps_eq!(matrix.c22, z_scale);
assert_ulps_eq!(matrix.c32, 1.0);
assert_ulps_eq!(matrix.c33, z_translation);
}
#[test]
fn projection_matrix_math_normal() {
let normal_matrix = Matrix4x4::new_perspective_projection(Degrees(90.0), 2560.0/1440.0, 0.1, 1000.0);
verify_proj(normal_matrix, Degrees(90.0), 2560.0/1440.0, 0.1, 1000.0);
}
#[test]
fn projection_matrix_math_zeroed_fov() {
let zeroed_fov = Matrix4x4::new_perspective_projection(Degrees(0.0), 0.1, 0.1, 1000.0);
verify_proj(zeroed_fov, Degrees(0.0), 2560.0/1440.0, 0.1, 1000.0);
}
#[test]
fn projection_matrix_math_negated_aspect() {
let negated_aspect = Matrix4x4::new_perspective_projection(Degrees(90.0), -2560.0/1440.0, 0.1, 1000.0);
verify_proj(negated_aspect, Degrees(90.0), -2560.0/1440.0, 0.1, 1000.0);
}
#[test]
fn projection_matrix_math_negated_far_plane() {
let negated_far_plane = Matrix4x4::new_perspective_projection(Degrees(90.0), 2560.0/1440.0, 0.1, -1000.0);
verify_proj(negated_far_plane, Degrees(90.0), 2560.0/1440.0, 0.1, -1000.0);
}
#[test]
fn projection_matrix_math_negated_near_plane() {
let negated_near_plane = Matrix4x4::new_perspective_projection(Degrees(90.0), 2560.0/1440.0, -0.1, 1000.0);
verify_proj(negated_near_plane, Degrees(90.0), 2560.0/1440.0, -0.1, 1000.0);
}
#[test]
fn projection_matrix_math_negated_fov() {
let negated_fov = Matrix4x4::new_perspective_projection(Degrees(-90.0), 2560.0/1440.0, 0.1, 1000.0);
verify_proj(negated_fov, Degrees(-90.0), 2560.0/1440.0, 0.1, 1000.0);
}
#[test]
fn projection_matrix_panic_on_zereod() {
let zeroed_fov = std::panic::catch_unwind(|| Matrix4x4::new_perspective_projection(Degrees(90.0), 0.0, 0.1, 1000.0));
assert!(zeroed_fov.is_err());
let zeroed_planes = std::panic::catch_unwind(|| Matrix4x4::new_perspective_projection(Degrees(90.0), 0.1, 0.0, 0.0));
assert!(zeroed_planes.is_err());
}
fn verify_ortho(matrix: Matrix4x4, top: f32, bottom: f32, left: f32, right: f32, near: f32, far: f32) {
let c00 = 2.0 / (right - left);
let c11 = 2.0 / (top - bottom);
let c22 = 1.0 / (far - near);
let c23 = -near / (far - near);
let c33 = 1.0;
assert_ulps_eq!(matrix.c00, c00);
assert_ulps_eq!(matrix.c11, c11);
assert_ulps_eq!(matrix.c22, c22);
assert_ulps_eq!(matrix.c23, c23);
assert_ulps_eq!(matrix.c33, c33);
}
#[test]
fn orthographic_matrix_math() {
let normal_matrix = Matrix4x4::new_orthographic_projection(-5.0, 5.0, -5.0, 5.0, 0.1, 1000.0);
verify_ortho(normal_matrix, -5.0, 5.0, -5.0, 5.0, 0.1, 1000.0);
}
#[test]
fn orthographic_matrix_math_negated_height() {
let negated_height = Matrix4x4::new_orthographic_projection(5.0, -5.0, -5.0, 5.0, 0.1, 1000.0);
verify_ortho(negated_height, 5.0, -5.0, -5.0, 5.0, 0.1, 1000.0);
}
#[test]
fn orthographic_matrix_math_negated_width() {
let negated_width = Matrix4x4::new_orthographic_projection(-5.0, 5.0, 5.0, -5.0, 0.1, 1000.0);
verify_ortho(negated_width, -5.0, 5.0, 5.0, -5.0, 0.1, 1000.0);
}
#[test]
fn orthographic_matrix_math_negated_planes() {
let negated_planes = Matrix4x4::new_orthographic_projection(-5.0, 5.0, -5.0, 5.0, 0.1, -1000.0);
verify_ortho(negated_planes, -5.0, 5.0, -5.0, 5.0, 0.1, -1000.0);
}
#[test]
fn orthographic_matrix_panic_on_zereod() {
let zeroed_planes = std::panic::catch_unwind(|| Matrix4x4::new_orthographic_projection(5.0, 5.0, 5.0, 5.0, 0.0, 0.0));
assert!(zeroed_planes.is_err());
let zeroed_width = std::panic::catch_unwind(|| Matrix4x4::new_orthographic_projection(-5.0, 5.0, 0.0, 0.0, 0.1, 1000.0));
assert!(zeroed_width.is_err());
let zeroed_height = std::panic::catch_unwind(|| Matrix4x4::new_orthographic_projection(0.0, 0.0, -5.0, 5.0, 0.1, 1000.0));
assert!(zeroed_height.is_err());
}
#[test]
fn from_quaternion() {
let matrix_from_quaternion = Matrix4x4::from(Quaternion { x: 0.18257418583505536, y: 0.3651483716701107, z: 0.5477225575051661, w: 0.7302967433402214 });
let result = Matrix4x4 {
c00: 0.13333333333333353, c10: -0.6666666666666666, c20: 0.7333333333333332, c30: 0.0,
c01: 0.9333333333333332, c11: 0.3333333333333335, c21: 0.13333333333333336, c31: 0.0,
c02: -0.33333333333333326, c12: 0.6666666666666665, c22: 0.6666666666666667, c32: 0.0,
c03: 0.0, c13: 0.0, c23: 0.0, c33: 1.0,
};
assert_ulps_eq!(matrix_from_quaternion, result);
}
#[test]
fn matrix_of_minors() {
assert_ulps_eq!(
Matrix4x4 {
c00: 13.0, c10: 72.0, c20: 43.0, c30: 34.0,
c01: 3.0, c11: 56.0, c21: 17.0, c31: 38.0,
c02: 9.0, c12: 10.0, c22: 13.0, c32: 2.0,
c03: 1.0, c13: 4.0, c23: 15.0, c33: 36.0,
}.matrix_of_minors(),
Matrix4x4 {
c00: 22268.0, c10: 476.0, c20: -15988.0, c30: -6096.0,
c01: 19732.0, c11: -4004.0, c21: -17724.0, c31: -6392.0,
c02: -50880.0, c12: -1512.0, c22: 17696.0, c32: 6128.0,
c03: -2624.0, c13: 4592.0, c23: 4592.0, c33: -4920.0,
}
);
}
#[test]
fn matrix_of_cofactors() {
assert_ulps_eq!(A.matrix_of_cofactors(), Matrix4x4 {
c00: A.c00, c10: -A.c10, c20: A.c20, c30: -A.c30,
c01: -A.c01, c11: A.c11, c21: -A.c21, c31: A.c31,
c02: A.c02, c12: -A.c12, c22: A.c22, c32: -A.c32,
c03: -A.c03, c13: A.c13, c23: -A.c23, c33: A.c33,
});
assert_ulps_eq!(B.matrix_of_cofactors(), Matrix4x4 {
c00: B.c00, c10: -B.c10, c20: B.c20, c30: -B.c30,
c01: -B.c01, c11: B.c11, c21: -B.c21, c31: B.c31,
c02: B.c02, c12: -B.c12, c22: B.c22, c32: -B.c32,
c03: -B.c03, c13: B.c13, c23: -B.c23, c33: B.c33,
});
}
#[test]
fn transpose() {
assert_ulps_eq!(A.transpose(), Matrix4x4 {
c00: A.c00, c10: A.c01, c20: A.c02, c30: A.c03,
c01: A.c10, c11: A.c11, c21: A.c12, c31: A.c13,
c02: A.c20, c12: A.c21, c22: A.c22, c32: A.c23,
c03: A.c30, c13: A.c31, c23: A.c32, c33: A.c33,
});
assert_ulps_eq!(B.transpose(), Matrix4x4 {
c00: B.c00, c10: B.c01, c20: B.c02, c30: B.c03,
c01: B.c10, c11: B.c11, c21: B.c12, c31: B.c13,
c02: B.c20, c12: B.c21, c22: B.c22, c32: B.c23,
c03: B.c30, c13: B.c31, c23: B.c32, c33: B.c33,
});
}
#[test]
fn determinant() {
assert_ulps_eq!(A.determinant(), 0.0);
assert_ulps_eq!(B.determinant(), 0.0);
}
#[test]
fn inverse() {
assert_ulps_eq!(
Matrix4x4 {
c00: 42.0, c10: 5.0, c20: 16.0, c30: 53.0,
c01: -21.0, c11: 125.0, c21: 6.0, c31: -65.0,
c02: -6.0, c12: 53.0, c22: 23.0, c32: -32.0,
c03: 63.0, c13: -3.0, c23: -23.0, c33: 51.0,
}.inverse(),
Matrix4x4 {
c00: -0.02144504449, c10: -0.01894554558, c20: 0.04831673192, c30: 0.02845612386,
c01: 0.01240283943, c11: 0.0147995753, c21: -0.01748989292, c31: -0.005001071941,
c02: 0.00992408168, c12: -0.01415471363, c22: 0.03197835075, c32: -0.008288735115,
c03: 0.03169608235, c13: 0.01789038596, c23: -0.04629258279, c33: -0.01957607699,
}
);
}
}