134 lines
No EOL
3.7 KiB
Rust
Executable file
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
|
|
}
|
|
} |