#![allow(clippy::cast_possible_truncation, clippy::if_same_then_else)]
use glam::{Mat3, Quat, Vec3};
use half::f16;
#[must_use]
pub fn half_to_f32(bits: u16) -> f32 {
f16::from_bits(bits).to_f32()
}
#[must_use]
pub fn f32_to_half(value: f32) -> u16 {
f16::from_f32(value).to_bits()
}
#[must_use]
pub fn decode_qtangent(qt: [i16; 4]) -> ([f32; 3], [f32; 4]) {
let q: [f32; 4] = [
f32::from(qt[0]) / 32767.0,
f32::from(qt[1]) / 32767.0,
f32::from(qt[2]) / 32767.0,
f32::from(qt[3]) / 32767.0,
];
let handedness = if q[3] < 0.0 { -1.0 } else { 1.0 };
let (qx, qy, qz, qw) = if q[3] < 0.0 {
(-q[0], -q[1], -q[2], -q[3])
} else {
(q[0], q[1], q[2], q[3])
};
let normal = [
2.0 * (qx * qz + qw * qy),
2.0 * (qy * qz - qw * qx),
1.0 - 2.0 * (qx * qx + qy * qy),
];
let tangent = [
1.0 - 2.0 * (qy * qy + qz * qz),
2.0 * (qx * qy + qw * qz),
2.0 * (qx * qz - qw * qy),
handedness,
];
(normal, tangent)
}
#[must_use]
pub fn encode_qtangent(normal: &[f32; 3], tangent: &[f32; 4]) -> [i16; 4] {
let n = Vec3::from_array(*normal).normalize_or_zero();
let t = Vec3::new(tangent[0], tangent[1], tangent[2]).normalize_or_zero();
let handedness = tangent[3];
let b = n.cross(t);
let mat = Mat3::from_cols(t, b, n);
let mut quat = Quat::from_mat3(&mat);
quat = quat.normalize();
if quat.w < 0.0 {
quat = -quat;
}
if handedness < 0.0 {
quat = -quat;
}
let x = (quat.x * 32767.0).round().clamp(-32767.0, 32767.0) as i16;
let y = (quat.y * 32767.0).round().clamp(-32767.0, 32767.0) as i16;
let z = (quat.z * 32767.0).round().clamp(-32767.0, 32767.0) as i16;
let mut w = (quat.w * 32767.0).round().clamp(-32767.0, 32767.0) as i16;
if w == 0 {
w = if handedness < 0.0 { -1 } else { 1 };
}
[x, y, z, w]
}