pub use glam::{Quat, Vec3};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Transform {
pub translation: Vec3,
pub rotation: Quat,
pub scale: Vec3,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Angle {
radians: f32,
}
impl Transform {
pub const IDENTITY: Self = Self {
translation: Vec3::ZERO,
rotation: Quat::IDENTITY,
scale: Vec3::ONE,
};
pub const fn at(translation: Vec3) -> Self {
Self {
translation,
rotation: Quat::IDENTITY,
scale: Vec3::ONE,
}
}
pub const fn with_translation(mut self, translation: Vec3) -> Self {
self.translation = translation;
self
}
pub const fn scale_by(mut self, scale: f32) -> Self {
self.scale = Vec3::new(scale, scale, scale);
self
}
pub fn rotate_x_deg(mut self, degrees: f32) -> Self {
let added = Quat::from_axis_angle(
Vec3::new(1.0, 0.0, 0.0),
Angle::from_degrees(degrees).radians(),
);
self.rotation = compose_rotations(self.rotation, added);
self
}
pub fn rotate_y_deg(mut self, degrees: f32) -> Self {
let added = Quat::from_axis_angle(
Vec3::new(0.0, 1.0, 0.0),
Angle::from_degrees(degrees).radians(),
);
self.rotation = compose_rotations(self.rotation, added);
self
}
pub fn rotate_z_deg(mut self, degrees: f32) -> Self {
let added = Quat::from_axis_angle(
Vec3::new(0.0, 0.0, 1.0),
Angle::from_degrees(degrees).radians(),
);
self.rotation = compose_rotations(self.rotation, added);
self
}
}
fn compose_rotations(base: Quat, added: Quat) -> Quat {
let product = base * added;
let length_sq = product.length_squared();
if length_sq <= f32::EPSILON || !length_sq.is_finite() {
return Quat::IDENTITY;
}
product.normalize()
}
impl Default for Transform {
fn default() -> Self {
Self::IDENTITY
}
}
impl Angle {
pub fn from_degrees(degrees: f32) -> Self {
Self::from_radians(degrees.to_radians())
}
pub const fn from_radians(radians: f32) -> Self {
Self { radians }
}
pub const fn radians(self) -> f32 {
self.radians
}
}