use bytemuck::{Pod, Zeroable};
use serde::{Serialize, Deserialize};
use nalgebra_glm as glm;
use crate::render::{InstanceData, Transformation, TransformationType::{self, *}};
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct Transform {
pub transformation_type: TransformationType,
pub translation: glm::Vec3,
pub rotation: glm::Quat,
pub pivot: glm::Vec3,
}
impl Transformation for Transform {
fn from_transform(
transformation_type: TransformationType,
translation: nalgebra_glm::Vec3,
rotation: nalgebra_glm::Quat,
pivot: nalgebra_glm::Vec3,
) -> Self {
Transform::new(transformation_type, translation, rotation, pivot)
}
}
impl Transform {
pub fn new(
transformation_type: TransformationType,
translation: glm::Vec3,
rotation: glm::Quat,
pivot: glm::Vec3,
) -> Transform {
Transform { transformation_type, translation, rotation, pivot }
}
pub fn identity() -> Transform {
Transform::default()
}
pub fn new_from_translation(translation: glm::Vec3) -> Transform {
Transform { translation, ..Default::default() }
}
pub fn new_from_rotation(rotation: glm::Quat) -> Transform {
Transform { rotation, ..Default::default() }
}
pub fn local_x(&self) -> glm::Vec3 {
let m = TransformUniform::new(self).transform_matrix;
glm::vec3(
m[(0, 0)],
m[(0, 1)],
m[(0, 2)]
)
}
pub fn local_y(&self) -> glm::Vec3 {
let m = TransformUniform::new(self).transform_matrix;
glm::vec3(
m[(1, 0)],
m[(1, 1)],
m[(1, 2)]
)
}
pub fn local_z(&self) -> glm::Vec3 {
let m = TransformUniform::new(self).transform_matrix;
glm::vec3(
m[(2, 0)],
m[(2, 1)],
m[(2, 2)]
)
}
}
impl Default for Transform {
fn default() -> Self {
Transform {
transformation_type: TransformationType::LookAt,
translation: glm::vec3(0.0, 0.0, 0.0),
rotation: glm::Quat::identity(),
pivot: glm::vec3(0.0, 0.0, 0.0),
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
pub struct TransformUniform {
pub transform_matrix: glm::Mat4,
pub inverse_matrix: glm::Mat4,
}
impl Default for TransformUniform {
fn default() -> Self {
TransformUniform {
transform_matrix: glm::Mat4::identity(),
inverse_matrix: glm::Mat4::identity().try_inverse().unwrap(),
}
}
}
impl TransformUniform {
pub fn new(transform: &Transform) -> TransformUniform {
let transform_matrix = if transform.transformation_type == LookAt {
glm::Mat4::identity()
* glm::translation(&transform.translation)
* glm::quat_cast(&transform.rotation)
* glm::translation(&-transform.pivot)
} else {
glm::Mat4::identity()
* glm::quat_cast(&transform.rotation)
* glm::translation(&transform.translation)
* glm::translation(&-transform.pivot)
};
let inverse_matrix = transform_matrix.try_inverse().unwrap();
TransformUniform {
transform_matrix,
inverse_matrix,
}
}
}
impl InstanceData for Transform {
type UniformData = TransformUniform;
fn uniform_data(&self) -> Self::UniformData {
TransformUniform::new(self)
}
}