use math::{Vec3, Mat4};
struct Data {
parent: Option<Transform>,
dirty: bool,
position: Vec3,
scale: Vec3,
global: Mat4,
}
#[derive(Copy, Clone)]
pub struct Transform(usize);
pub struct TransformSystem {
transforms: Vec<Data>,
}
impl TransformSystem {
pub fn new() -> Self {
Self { transforms: Vec::new() }
}
pub fn add<V1, V2>(&mut self, position: V1, scale: V2) -> Transform
where Vec3: From<V1> + From<V2> {
self.add_inner(None, Vec3::from(position), Vec3::from(scale))
}
pub fn add_child<V1, V2>(&mut self, parent: Transform, position: V1, scale: V2) -> Transform
where Vec3: From<V1> + From<V2> {
self.add_inner(Some(parent), Vec3::from(position), Vec3::from(scale))
}
pub fn position(&self, transform: Transform) -> Vec3 {
self.transforms[transform.0].position
}
pub fn global(&self, transform: Transform) -> Mat4 {
self.transforms[transform.0].global
}
pub fn set_position<V>(&mut self, transform: Transform, position: V)
where Vec3: From<V> {
self.transforms[transform.0].position = Vec3::from(position);
}
pub fn update(&mut self) {
for transform in self.transforms.iter_mut() {
transform.dirty = true;
}
for index in 0 .. self.transforms.len() {
self.update_transform(index);
}
}
fn update_transform(&mut self, index: usize) {
if self.transforms[index].dirty {
self.transforms[index].dirty = false;
let local = Mat4::model(self.transforms[index].position, self.transforms[index].scale);
if let Some(parent) = self.transforms[index].parent {
self.update_transform(parent.0);
self.transforms[index].global = self.transforms[parent.0].global * local;
} else {
self.transforms[index].global = local;
}
}
}
fn add_inner(&mut self, parent: Option<Transform>, position: Vec3, scale: Vec3) -> Transform {
self.transforms.push(Data {
parent,
position,
scale,
dirty: false,
global: Mat4::identity(),
});
Transform(self.transforms.len() - 1)
}
}