use std::marker;
use amethyst_core::cgmath::{
Array, Basis2, EuclideanSpace, Matrix3, Point2, Point3, Quaternion, Rotation, Vector3,
};
use amethyst_core::specs::prelude::{Join, ReadStorage, System, World, WriteStorage};
use amethyst_core::timing::Time;
use amethyst_core::Transform;
use rhusics_core::{BodyPose, Pose};
use rhusics_ecs::DeltaTime;
pub trait AsTransform {
fn as_transform(&self) -> Transform;
}
pub trait Convert {
type Output;
fn convert(&self) -> Self::Output;
}
impl Convert for Point2<f32> {
type Output = Vector3<f32>;
fn convert(&self) -> Self::Output {
Vector3::new(self.x, self.y, 0.)
}
}
impl Convert for Point3<f32> {
type Output = Vector3<f32>;
fn convert(&self) -> Self::Output {
self.to_vec()
}
}
impl Convert for Basis2<f32> {
type Output = Quaternion<f32>;
fn convert(&self) -> Self::Output {
Matrix3::new(
self.as_ref()[0][0],
self.as_ref()[0][1],
0.,
self.as_ref()[1][0],
self.as_ref()[1][1],
0.,
0.,
0.,
1.,
).into()
}
}
impl Convert for Quaternion<f32> {
type Output = Quaternion<f32>;
fn convert(&self) -> Self::Output {
*self
}
}
impl<P, R> AsTransform for BodyPose<P, R>
where
P: EuclideanSpace<Scalar = f32> + Convert<Output = Vector3<f32>>,
R: Rotation<P> + Convert<Output = Quaternion<f32>>,
{
fn as_transform(&self) -> Transform {
Transform {
translation: self.position().convert(),
rotation: self.rotation().convert(),
scale: Vector3::from_value(1.),
}
}
}
pub fn time_sync(world: &World) {
let mut delta = world.write_resource::<DeltaTime<f32>>();
let time = world.read_resource::<Time>();
delta.delta_seconds = time.delta_seconds();
}
pub struct PoseTransformSyncSystem<P, R> {
m: marker::PhantomData<(P, R)>,
translation: bool,
rotation: bool,
}
impl<P, R> PoseTransformSyncSystem<P, R> {
pub fn new() -> Self {
Self {
m: marker::PhantomData,
translation: true,
rotation: true,
}
}
pub fn without_rotation(mut self) -> Self {
self.rotation = false;
self
}
pub fn without_translation(mut self) -> Self {
self.translation = false;
self
}
}
impl<'a, P, R> System<'a> for PoseTransformSyncSystem<P, R>
where
P: EuclideanSpace<Scalar = f32> + Convert<Output = Vector3<f32>> + Send + Sync + 'static,
R: Rotation<P> + Convert<Output = Quaternion<f32>> + Send + Sync + 'static,
{
type SystemData = (ReadStorage<'a, BodyPose<P, R>>, WriteStorage<'a, Transform>);
fn run(&mut self, data: Self::SystemData) {
let (poses, mut transforms) = data;
for (pose, transform) in (&poses, &mut transforms).join() {
if self.translation {
transform.translation = pose.position().convert();
}
if self.rotation {
transform.rotation = pose.rotation().convert();
}
}
}
}