lyra-engine/lyra-math/src/transform.rs
2024-03-09 00:46:42 -05:00

134 lines
No EOL
3.7 KiB
Rust
Executable file

use glam::{Vec3, Mat4, Quat};
use super::Angle;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Transform {
pub translation: Vec3,
pub rotation: Quat,
pub scale: Vec3,
}
impl Default for Transform {
fn default() -> Self {
Self {
translation: Vec3::new(0.0, 0.0, 0.0),
rotation: Quat::IDENTITY,
scale: Vec3::new(1.0, 1.0, 1.0),
}
}
}
/* impl Into<glam::Mat4> for Transform {
fn into(self) -> glam::Mat4 {
self.matrix
}
} */
// TODO: https://www.brainvoyager.com/bv/doc/UsersGuide/CoordsAndTransforms/SpatialTransformationMatrices.html
#[allow(dead_code)]
const ZERO_V3: Vec3 = Vec3::new(0.0, 0.0, 0.0);
const ONE_V3: Vec3 = Vec3::new(1.0, 1.0, 1.0);
#[allow(dead_code)]
impl Transform {
pub fn new(translation: Vec3, rotation: Quat, scale: Vec3) -> Self {
Self {
translation,
rotation,
scale,
}
}
pub fn from_translation(translation: Vec3) -> Self {
Self::new(translation, Quat::IDENTITY, ONE_V3)
}
pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
Self::new(Vec3::new(x, y, z), Quat::IDENTITY, ONE_V3)
}
pub fn calculate_mat4(&self) -> Mat4 {
Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
}
/// Get the forward vector of the Transform.
pub fn forward(&self) -> Vec3 {
(self.rotation * -Vec3::Z).normalize()
}
/// Get the left vector of the Transform.
pub fn left(&self) -> Vec3 {
(self.rotation * Vec3::X).normalize()
}
/// Get the up vector of the Transform.
pub fn up(&self) -> Vec3 {
(self.rotation * Vec3::Y).normalize()
}
/// Rotate this transform using a Quaternion
pub fn rotate(&mut self, rotation: Quat) {
self.rotation = (rotation * self.rotation).normalize();
}
pub fn rotate_x(&mut self, angle: Angle) {
self.rotate(Quat::from_rotation_x(angle.to_radians()))
}
pub fn rotate_y(&mut self, angle: Angle) {
self.rotate(Quat::from_rotation_y(angle.to_radians()))
}
pub fn rotate_z(&mut self, angle: Angle) {
self.rotate(Quat::from_rotation_z(angle.to_radians()))
}
pub fn translate(&mut self, x: f32, y: f32, z: f32) {
let trans = &mut self.translation;
trans.x += x;
trans.y += y;
trans.z += z;
}
/// Combines a transform with another one.
///
/// The translations are added while the rotations and scales are multiplied.
pub fn combine(self, rhs: Transform) -> Transform {
self + rhs
}
/// Performs a linear interpolation between `self` and `rhs` based on the value `alpha`.
///
/// When `alpha` is `0.0`, the result will be equal to `self`. When `alpha` is `1.0`, the result
/// will be equal to `rhs`.
pub fn lerp(&self, rhs: Transform, alpha: f32) -> Self {
if alpha.is_finite() {
let mut res = *self;
res.translation = self.translation.lerp(rhs.translation, alpha);
// normalize rotation here to avoid panics
res.rotation = self.rotation.lerp(rhs.rotation.normalize(), alpha);
res.scale = self.scale.lerp(rhs.scale, alpha);
res
} else {
*self
}
}
}
/// Adds a transform to another one
///
/// The Translations of each transform is added and rotation and scale is multiplied.
impl std::ops::Add for Transform {
type Output = Transform;
fn add(mut self, rhs: Self) -> Self::Output {
self.translation += rhs.translation;
self.rotation *= rhs.rotation;
self.scale *= rhs.scale;
self
}
}