use crate::layout::InstanceModel;
#[derive(Clone, Copy, Default)]
pub struct Position(pub [f32; 3]);
impl From<[f32; 3]> for Position {
fn from(v: [f32; 3]) -> Self {
Self(v)
}
}
#[derive(Clone, Copy)]
pub struct Transform<Q = Identity> {
pub pos: [f32; 3],
pub rot: Q,
pub scl: [f32; 3],
}
impl<Q> Transform<Q>
where
Q: IntoQuat,
{
pub(crate) fn into_model(self) -> InstanceModel {
let Self { pos, rot, scl } = self;
let transform = Transform {
pos,
rot: rot.into_quat(),
scl,
};
transform.into_model_quat()
}
}
impl Transform<Quat> {
fn into_model_quat(self) -> InstanceModel {
fn rotation(Quat([x, y, z, w]): Quat) -> [[f32; 3]; 3] {
let x2 = x + x;
let y2 = y + y;
let z2 = z + z;
let xx = x * x2;
let xy = x * y2;
let xz = x * z2;
let yy = y * y2;
let yz = y * z2;
let zz = z * z2;
let wx = w * x2;
let wy = w * y2;
let wz = w * z2;
[
[1. - yy - zz, xy + wz, xz - wy],
[xy - wz, 1. - xx - zz, yz + wx],
[xz + wy, yz - wx, 1. - xx - yy],
]
}
let [xt, yt, zt] = self.pos;
let [x_axis, y_axis, z_axis] = rotation(self.rot);
let [xs, ys, zs] = self.scl;
let [xx, xy, xz] = x_axis.map(|v| v * xs);
let [yx, yy, yz] = y_axis.map(|v| v * ys);
let [zx, zy, zz] = z_axis.map(|v| v * zs);
InstanceModel {
mat: [
[xx, xy, xz, 0.],
[yx, yy, yz, 0.],
[zx, zy, zz, 0.],
[xt, yt, zt, 1.],
],
}
}
}
impl Default for Transform<Identity> {
fn default() -> Self {
Self {
pos: [0., 0., 0.],
rot: Identity,
scl: [1., 1., 1.],
}
}
}
#[allow(clippy::module_name_repetitions)]
pub trait IntoTransform {
type IntoQuat;
fn into_transform(self) -> Transform<Self::IntoQuat>;
}
impl IntoTransform for Position {
type IntoQuat = Identity;
fn into_transform(self) -> Transform<Self::IntoQuat> {
Transform {
pos: self.0,
..Default::default()
}
}
}
impl<Q> IntoTransform for Transform<Q> {
type IntoQuat = Q;
fn into_transform(self) -> Transform<Self::IntoQuat> {
self
}
}
pub trait IntoQuat {
fn into_quat(self) -> Quat;
}
#[derive(Default)]
pub struct Identity;
impl IntoQuat for Identity {
fn into_quat(self) -> Quat {
Quat::default()
}
}
pub struct Quat(pub [f32; 4]);
impl Default for Quat {
fn default() -> Self {
Self([0., 0., 0., 1.])
}
}
impl IntoQuat for Quat {
fn into_quat(self) -> Self {
self
}
}
pub struct AxisAngle(pub [f32; 3], pub f32);
impl IntoQuat for AxisAngle {
fn into_quat(self) -> Quat {
let Self(axis, angle) = self;
let (sin, cos) = (angle * 0.5).sin_cos();
let [x, y, z] = axis.map(|v| v * sin);
Quat([x, y, z, cos])
}
}
#[derive(Default)]
pub struct ReverseRotation<Q>(pub Q);
impl<Q> IntoQuat for ReverseRotation<Q>
where
Q: IntoQuat,
{
fn into_quat(self) -> Quat {
let Quat([x, y, z, w]) = self.0.into_quat();
Quat([-x, -y, -z, w])
}
}