use crate::mesh::{Mesh, Primitive};
use crate::scene::mat4_affine_inverse;
fn transform_point(m: [[f32; 4]; 4], p: [f32; 3]) -> [f32; 3] {
let x = m[0][0] * p[0] + m[0][1] * p[1] + m[0][2] * p[2] + m[0][3];
let y = m[1][0] * p[0] + m[1][1] * p[1] + m[1][2] * p[2] + m[1][3];
let z = m[2][0] * p[0] + m[2][1] * p[1] + m[2][2] * p[2] + m[2][3];
let w = m[3][0] * p[0] + m[3][1] * p[1] + m[3][2] * p[2] + m[3][3];
if w != 0.0 && w != 1.0 && w.is_finite() {
[x / w, y / w, z / w]
} else {
[x, y, z]
}
}
fn transform_dir(l: [[f32; 3]; 3], v: [f32; 3]) -> [f32; 3] {
[
l[0][0] * v[0] + l[0][1] * v[1] + l[0][2] * v[2],
l[1][0] * v[0] + l[1][1] * v[1] + l[1][2] * v[2],
l[2][0] * v[0] + l[2][1] * v[1] + l[2][2] * v[2],
]
}
fn normalize3(v: [f32; 3]) -> Option<[f32; 3]> {
let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
if len.is_finite() && len > 0.0 {
Some([v[0] / len, v[1] / len, v[2] / len])
} else {
None
}
}
fn linear_det(m: [[f32; 4]; 4]) -> f32 {
let (a, b, c) = (m[0][0], m[0][1], m[0][2]);
let (d, e, f) = (m[1][0], m[1][1], m[1][2]);
let (g, h, i) = (m[2][0], m[2][1], m[2][2]);
a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g)
}
impl Primitive {
pub fn transformed(&self, m: [[f32; 4]; 4]) -> Primitive {
let mut out = self.clone();
for p in &mut out.positions {
*p = transform_point(m, *p);
}
let l = [
[m[0][0], m[0][1], m[0][2]],
[m[1][0], m[1][1], m[1][2]],
[m[2][0], m[2][1], m[2][2]],
];
let normal_mat = mat4_affine_inverse(m).map(|inv| {
[
[inv[0][0], inv[1][0], inv[2][0]],
[inv[0][1], inv[1][1], inv[2][1]],
[inv[0][2], inv[1][2], inv[2][2]],
]
});
if let (Some(nm), Some(normals)) = (normal_mat, out.normals.as_mut()) {
for n in normals.iter_mut() {
let t = transform_dir(nm, *n);
if let Some(u) = normalize3(t) {
*n = u;
}
}
}
let mirror = linear_det(m) < 0.0;
if let Some(tangents) = out.tangents.as_mut() {
for tg in tangents.iter_mut() {
let dir = transform_dir(l, [tg[0], tg[1], tg[2]]);
if let Some(u) = normalize3(dir) {
tg[0] = u[0];
tg[1] = u[1];
tg[2] = u[2];
}
if mirror {
tg[3] = -tg[3];
}
}
}
for target in &mut out.targets {
if let Some(dp) = target.position.as_mut() {
for d in dp.iter_mut() {
*d = transform_dir(l, *d);
}
}
if let (Some(nm), Some(dn)) = (normal_mat, target.normal.as_mut()) {
for d in dn.iter_mut() {
*d = transform_dir(nm, *d);
}
}
if let Some(dt) = target.tangent.as_mut() {
for d in dt.iter_mut() {
*d = transform_dir(l, *d);
}
}
for ib in &mut target.inbetweens {
if let Some(dp) = ib.position.as_mut() {
for d in dp.iter_mut() {
*d = transform_dir(l, *d);
}
}
if let (Some(nm), Some(dn)) = (normal_mat, ib.normal.as_mut()) {
for d in dn.iter_mut() {
*d = transform_dir(nm, *d);
}
}
}
}
out
}
pub fn reverse_winding(&self) -> Primitive {
let mut out = self.to_triangle_list();
if let Some(crate::mesh::Indices::U32(idx)) = &mut out.indices {
for tri in idx.chunks_exact_mut(3) {
tri.swap(1, 2);
}
}
if let Some(normals) = out.normals.as_mut() {
for n in normals.iter_mut() {
n[0] = -n[0];
n[1] = -n[1];
n[2] = -n[2];
}
}
if let Some(tangents) = out.tangents.as_mut() {
for t in tangents.iter_mut() {
t[3] = -t[3];
}
}
out
}
}
impl Mesh {
pub fn transformed(&self, m: [[f32; 4]; 4]) -> Mesh {
let mut out = self.clone();
for prim in &mut out.primitives {
*prim = prim.transformed(m);
}
out
}
}