use rin_math::{UnitQuat, Pnt3, Vec3, lerp, vec3, ToVec, ToPnt};
use rinecs::Component;
use rin_scene::time::Clock;
use hashbrown::HashMap;
use std::borrow::Borrow;
use std::fmt::{self, Debug};
use std::sync::mpsc;
use std::iter::FromIterator;
use std::sync::atomic::{AtomicBool, Ordering};
use serde_derive::{Deserialize, Serialize};
use rin_events as events;
use crate::components::{Rotation, RotOrder};
bitflags::bitflags!{
pub struct RootMotionRemove: u8 {
const TRANSLATION_X = 1 << 0;
const TRANSLATION_Y = 1 << 1;
const TRANSLATION_Z = 1 << 2;
const TRANSLATIONS = Self::TRANSLATION_X.bits |
Self::TRANSLATION_Y.bits |
Self::TRANSLATION_Z.bits;
const ROLL = 1 << 3;
const PITCH = 1 << 4;
const YAW = 1 << 5;
const ORIENTATIONS = Self::ROLL.bits |
Self::PITCH.bits |
Self::YAW.bits;
const FROM_ZERO = 1 << 6;
}
}
impl RootMotionRemove{
pub fn removes_orientations(self) -> bool {
self.intersects(RootMotionRemove::ORIENTATIONS)
}
pub fn removes_translations(self) -> bool {
self.intersects(RootMotionRemove::TRANSLATIONS)
}
}
pub trait ActionExt {
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>;
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>;
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>;
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>;
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>;
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> ;
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32>;
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool>;
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool>;
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>;
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>;
fn name(&self) -> &str;
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove;
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>);
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>);
fn min_time_s(&self) -> f32;
fn max_time_s(&self) -> f32;
fn duration(&self) -> f32;
fn needs_root_motion_reset(&self, t: f32) -> bool;
}
pub trait ActionNeedsUpdate {
const NEEDS_UPDATE: bool;
}
pub trait ActionUpdate {
fn update(&mut self);
}
pub trait ActionUpdateExt: ActionExt + ActionUpdate {}
impl<A: ActionExt + ActionUpdate> ActionUpdateExt for A {}
#[derive(Debug, Serialize, Deserialize)]
pub struct ActionBlend<A1, A2>{
action1: A1,
action2: A2,
weight1: f32,
name: String,
}
impl<A1: Clone, A2: Clone> Clone for ActionBlend<A1, A2>{
fn clone(&self) -> ActionBlend<A1, A2>{
ActionBlend{
action1: self.action1.clone(),
action2: self.action2.clone(),
weight1: self.weight1,
name: self.name.clone(),
}
}
}
impl<A1: ActionExt, A2: ActionExt> ActionBlend<A1, A2>{
pub fn new(action1: A1, action2: A2, weight: f32) -> ActionBlend<A1, A2>{
ActionBlend{
name: action1.name().to_owned() + "_x_" + action2.name(),
action1,
action2,
weight1: weight,
}
}
}
impl<A1, A2> ActionBlend<A1, A2>{
pub fn set_weight(&mut self, weight: f32){
self.weight1 = weight;
}
pub fn into_actions(self) -> (A1, A2){
(self.action1, self.action2)
}
pub fn action1(&self) -> &A1{
&self.action1
}
pub fn action2(&self) -> &A2{
&self.action2
}
}
impl<A1: ActionExt, A2: ActionExt> ActionExt for ActionBlend<A1, A2>{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
if self.weight1 == 0. {
self.action1.orientation_at(object, t, current_value)
}else if self.weight1 == 1.{
self.action2.orientation_at(object, t, current_value)
}else{
let q1 = self.action1.borrow().orientation_at(object, t, current_value);
let q2 = self.action2.borrow().orientation_at(object, t, current_value);
match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1.slerp(&q2, self.weight1))
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
}
}
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
if self.weight1 == 0. {
self.action1.orientation_from_axis_angle_at(object, t, current_value)
}else if self.weight1 == 1.{
self.action2.orientation_from_axis_angle_at(object, t, current_value)
}else{
let q1 = self.action1.borrow().orientation_from_axis_angle_at(object, t, current_value);
let q2 = self.action2.borrow().orientation_from_axis_angle_at(object, t, current_value);
match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1.slerp(&q2, self.weight1))
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
}
}
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
if self.weight1 == 0. {
self.action1.orientation_from_euler_at(object, t, current_value, rot_order)
}else if self.weight1 == 1.{
self.action2.orientation_from_euler_at(object, t, current_value, rot_order)
}else{
let q1 = self.action1.borrow().orientation_from_euler_at(object, t, current_value, rot_order);
let q2 = self.action2.borrow().orientation_from_euler_at(object, t, current_value, rot_order);
match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1.slerp(&q2, self.weight1))
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
}
}
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
if self.weight1 == 0. {
self.action1.location_at(object, t, current_value)
}else if self.weight1 == 1.{
self.action2.location_at(object, t, current_value)
}else{
let p1 = self.action1.borrow().location_at(object, t, current_value);
let p2 = self.action2.borrow().location_at(object, t, current_value);
match (p1, p2){
(Some(p1), Some(p2)) => {
Some(lerp(p1.to_vec(), p2.to_vec(), self.weight1).to_pnt())
}
(Some(p1), None) => {
Some(p1)
}
(None, Some(p2)) => {
Some(p2)
}
(None, None) => {
None
}
}
}
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
if self.weight1 == 0. {
self.action1.scale_at(object, t, current_value)
}else if self.weight1 == 1.{
self.action2.scale_at(object, t, current_value)
}else{
let s1 = self.action1.borrow().scale_at(object, t, current_value);
let s2 = self.action2.borrow().scale_at(object, t, current_value);
match (s1, s2){
(Some(s1), Some(s2)) => {
Some(lerp(s1, s2, self.weight1))
}
(Some(s1), None) => {
Some(s1)
}
(None, Some(s2)) => {
Some(s2)
}
(None, None) => {
None
}
}
}
}
fn rotation_at(&self, object: &str, _t: f32, _current_value: &Rotation) -> Option<Rotation> {
todo!()
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
if self.weight1 == 0. {
self.action1.keyblock_at(keyblock, t)
}else if self.weight1 == 1.{
self.action2.keyblock_at(keyblock, t)
}else{
let k1 = self.action1.borrow().keyblock_at(keyblock, t);
let k2 = self.action2.borrow().keyblock_at(keyblock, t);
match (k1, k2){
(Some(k1), Some(k2)) => {
Some(lerp(k1, k2, self.weight1))
}
(Some(k1), None) => {
Some(k1)
}
(None, Some(k2)) => {
Some(k2)
}
(None, None) => {
None
}
}
}
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
if self.weight1 == 0. {
self.action1.hide_view_at(object, t)
}else if self.weight1 == 1.{
self.action2.hide_view_at(object, t)
}else{
let h1 = self.action1.borrow().hide_view_at(object, t);
let h2 = self.action2.borrow().hide_view_at(object, t);
match (h1, h2){
(Some(h1), Some(h2)) => {
Some(if self.weight1 < 0.5 { h1 } else { h2 })
}
(Some(h1), None) => {
Some(h1)
}
(None, Some(h2)) => {
Some(h2)
}
(None, None) => {
None
}
}
}
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
if self.weight1 == 0. {
self.action1.hide_render_at(object, t)
}else if self.weight1 == 1.{
self.action2.hide_render_at(object, t)
}else{
let h1 = self.action1.borrow().hide_render_at(object, t);
let h2 = self.action2.borrow().hide_render_at(object, t);
match (h1, h2){
(Some(h1), Some(h2)) => {
Some(if self.weight1 < 0.5 { h1 } else { h2 })
}
(Some(h1), None) => {
Some(h1)
}
(None, Some(h2)) => {
Some(h2)
}
(None, None) => {
None
}
}
}
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
if self.action1.needs_root_motion_reset(t) {
self.action1.reset_root_motion_positions(object, self.action1.min_time_s(), current_value, prev_positions);
}
if self.action2.needs_root_motion_reset(t) {
self.action2.reset_root_motion_positions(object, self.action2.min_time_s(), current_value, prev_positions);
}
if self.weight1 == 0. {
self.action1.root_motion_location_at(object, t, current_value, prev_positions)
}else if self.weight1 == 1.{
self.action2.root_motion_location_at(object, t, current_value, prev_positions)
}else{
let p1 = self.action1.location_at(object, t, current_value);
let p2 = self.action2.location_at(object, t, current_value);
let p = match (p1, p2){
(Some(p1), Some(p2)) => {
Some(lerp(p1.to_vec(), p2.to_vec(), self.weight1).to_pnt())
}
(Some(p1), None) => {
Some(p1)
}
(None, Some(p2)) => {
Some(p2)
}
(None, None) => {
None
}
};
if let Some(p) = p {
let prev_p1 = prev_positions.get(self.action1.name()).and_then(|p| *p);
let prev_p2 = prev_positions.get(self.action2.name()).and_then(|p| *p);
let delta1 = match (p1, prev_p1){
(Some(p1), Some((prev_t1, prev_p1))) => if prev_t1 < t {
Some(p1 - prev_p1)
}else{
None
}
_ => None
};
let delta2 = match (p2, prev_p2){
(Some(p2), Some((prev_t2, prev_p2))) => if prev_t2 < t {
Some(p2 - prev_p2)
}else{
None
}
_ => None
};
let delta = match (delta1, delta2){
(Some(delta1), Some(delta2)) => {
Some(lerp(delta1, delta2, self.weight1))
}
(Some(delta1), None) => {
Some(delta1)
}
(None, Some(delta2)) => {
Some(delta2)
}
(None, None) => {
None
}
};
let delta = delta.unwrap_or_else(||{
vec3!(0.)
});
prev_positions.insert(self.action1.name().to_owned(), p1.map(|p1| (t, p1)));
prev_positions.insert(self.action2.name().to_owned(), p2.map(|p2| (t, p2)));
Some((p, delta))
}else{
None
}
}
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
if self.action1.needs_root_motion_reset(t) {
self.action1.reset_root_motion_orientations(object, self.action1.min_time_s(), current_value, prev_orientations);
}
if self.action2.needs_root_motion_reset(t) {
self.action2.reset_root_motion_orientations(object, self.action1.min_time_s(), current_value, prev_orientations);
}
if self.weight1 == 0. {
self.action1.root_motion_orientation_at(object, t, current_value, prev_orientations)
}else if self.weight1 == 1.{
self.action2.root_motion_orientation_at(object, t, current_value, prev_orientations)
}else{
if !self.action1.root_motion_remove(Some(t)).removes_orientations() ||
!self.action2.root_motion_remove(Some(t)).removes_orientations()
{
let p1 = self.action1.orientation_at(object, t, current_value);
let p2 = self.action2.orientation_at(object, t, current_value);
let p = match (p1, p2){
(Some(p1), Some(p2)) => {
Some(p1.slerp(&p2, self.weight1))
}
(Some(p1), None) => {
Some(p1)
}
(None, Some(p2)) => {
Some(p2)
}
(None, None) => {
None
}
};
if let Some(p) = p {
let prev_p1 = prev_orientations.get(self.action1.name()).and_then(|p| *p);
let prev_p2 = prev_orientations.get(self.action2.name()).and_then(|p| *p);
let delta1 = match (p1, prev_p1){
(Some(p1), Some((prev_t1, prev_p1))) => if prev_t1 < t {
Some(prev_p1.inverse() * p1)
}else{
None
}
_ => None
};
let delta2 = match (p2, prev_p2){
(Some(p2), Some((prev_t2, prev_p2))) => if prev_t2 < t {
Some(prev_p2.inverse() * p2)
}else{
None
}
_ => None
};
let delta = match (delta1, delta2){
(Some(delta1), Some(delta2)) => {
Some(delta1.slerp(&delta2, self.weight1))
}
(Some(delta1), None) => {
Some(delta1)
}
(None, Some(delta2)) => {
Some(delta2)
}
(None, None) => {
None
}
};
let delta = delta.unwrap_or_else(|| UnitQuat::identity());
prev_orientations.insert(self.action1.name().to_owned(), p1.map(|p1| (t, p1)));
prev_orientations.insert(self.action2.name().to_owned(), p2.map(|p2| (t, p2)));
Some((p, delta))
}else{
None
}
}else{
self.orientation_at(object, t, current_value).map(|p| (p, UnitQuat::identity()))
}
}
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
self.action1.needs_root_motion_reset(t) || self.action2.needs_root_motion_reset(t)
}
fn name(&self) -> &str{
&self.name
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
if self.weight1 == 0. {
self.action1.root_motion_remove(t)
}else if self.weight1 == 1.{
self.action2.root_motion_remove(t)
}else{
let r1 = self.action1.root_motion_remove(t);
let r2 = self.action2.root_motion_remove(t);
r1 | r2
}
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
self.action1.reset_root_motion_positions(object, t, current_value, prev_positions);
self.action2.reset_root_motion_positions(object, t, current_value, prev_positions);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
self.action1.reset_root_motion_orientations(object, t, current_value, prev_orientations);
self.action2.reset_root_motion_orientations(object, t, current_value, prev_orientations);
}
fn min_time_s(&self) -> f32{
self.action1().min_time_s().min(self.action2().min_time_s())
}
fn max_time_s(&self) -> f32{
self.action2().max_time_s().max(self.action2().max_time_s())
}
fn duration(&self) -> f32{
self.max_time_s() - self.min_time_s()
}
}
impl<A1: ActionNeedsUpdate, A2: ActionNeedsUpdate> ActionNeedsUpdate for ActionBlend<A1, A2> {
const NEEDS_UPDATE: bool = A1::NEEDS_UPDATE | A2::NEEDS_UPDATE;
}
impl<A1: ActionUpdate, A2: ActionUpdate> ActionUpdate for ActionBlend<A1, A2> {
fn update(&mut self){
self.action1.update();
self.action2.update();
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ActionMix<A1, A2>{
action1: A1,
action2: A2,
name: String,
}
impl<A1: Clone, A2: Clone> Clone for ActionMix<A1, A2>{
fn clone(&self) -> ActionMix<A1, A2>{
ActionMix{
action1: self.action1.clone(),
action2: self.action2.clone(),
name: self.name.clone(),
}
}
}
impl<A1: ActionExt, A2: ActionExt> ActionMix<A1, A2>{
pub fn new(action1: A1, action2: A2) -> ActionMix<A1, A2>{
ActionMix{
name: action1.name().to_owned() + "_+_" + action2.name(),
action1,
action2,
}
}
}
impl<A1: ActionExt, A2: ActionExt> ActionExt for ActionMix<A1, A2>{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
let q1 = self.action1.orientation_at(object, t, current_value);
let q2 = self.action2.orientation_at(object, t, current_value);
match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1 * q2)
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
}
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
let q1 = self.action1.orientation_from_axis_angle_at(object, t, current_value);
let q2 = self.action2.orientation_from_axis_angle_at(object, t, current_value);
match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1 * q2)
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
}
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
let q1 = self.action1.orientation_from_euler_at(object, t, current_value, rot_order);
let q2 = self.action2.orientation_from_euler_at(object, t, current_value, rot_order);
match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1 * q2)
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
}
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
let p1 = self.action1.location_at(object, t, current_value);
let p2 = self.action2.location_at(object, t, current_value);
match (p1, p2){
(Some(p1), Some(p2)) => {
Some(p1 + p2.to_vec())
}
(Some(p1), None) => {
Some(p1)
}
(None, Some(p2)) => {
Some(p2)
}
(None, None) => {
None
}
}
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
let s1 = self.action1.scale_at(object, t, current_value);
let s2 = self.action2.scale_at(object, t, current_value);
match (s1, s2){
(Some(s1), Some(s2)) => {
Some(s1.component_mul(&s2))
}
(Some(s1), None) => {
Some(s1)
}
(None, Some(s2)) => {
Some(s2)
}
(None, None) => {
None
}
}
}
fn rotation_at(&self, object: &str, _t: f32, _current_value: &Rotation) -> Option<Rotation> {
todo!()
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
let k1 = self.action1.keyblock_at(keyblock, t);
let k2 = self.action2.keyblock_at(keyblock, t);
match (k1, k2){
(Some(k1), Some(_k2)) => {
todo!()
}
(Some(k1), None) => {
Some(k1)
}
(None, Some(k2)) => {
Some(k2)
}
(None, None) => {
None
}
}
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
let h1 = self.action1.hide_view_at(object, t);
let h2 = self.action2.hide_view_at(object, t);
match (h1, h2){
(Some(h1), Some(h2)) => {
Some(h1 & h2)
}
(Some(h1), None) => {
Some(h1)
}
(None, Some(h2)) => {
Some(h2)
}
(None, None) => {
None
}
}
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
let h1 = self.action1.hide_render_at(object, t);
let h2 = self.action2.hide_render_at(object, t);
match (h1, h2){
(Some(h1), Some(h2)) => {
Some(h1 & h2)
}
(Some(h1), None) => {
Some(h1)
}
(None, Some(h2)) => {
Some(h2)
}
(None, None) => {
None
}
}
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
if self.action1.needs_root_motion_reset(t) {
self.action1.reset_root_motion_positions(object, self.action1.min_time_s(), current_value, prev_positions);
}
if self.action2.needs_root_motion_reset(t) {
self.action2.reset_root_motion_positions(object, self.action2.min_time_s(), current_value, prev_positions);
}
let p1 = self.action1.location_at(object, t, current_value);
let p2 = self.action2.location_at(object, t, current_value);
let p = match (p1, p2){
(Some(p1), Some(p2)) => {
Some(p1 + p2.to_vec())
}
(Some(p1), None) => {
Some(p1)
}
(None, Some(p2)) => {
Some(p2)
}
(None, None) => {
None
}
};
if let Some(p) = p{
let prev_p1 = prev_positions.get(self.action1.borrow().name()).and_then(|p| *p);
let prev_p2 = prev_positions.get(self.action2.borrow().name()).and_then(|p| *p);
let delta1 = match (p1, prev_p1) {
(Some(p1), Some((prev_t1, prev_p1))) => if prev_t1 < t {
Some(p1 - prev_p1)
}else{
None
}
_ => None
};
let delta2 = match (p2, prev_p2){
(Some(p2), Some((prev_t2, prev_p2))) => if prev_t2 < t {
Some(p2 - prev_p2)
}else{
None
}
_ => None
};
let delta = match (delta1, delta2){
(Some(delta1), Some(delta2)) => {
Some(delta1 + delta2)
}
(Some(delta1), None) => {
Some(delta1)
}
(None, Some(delta2)) => {
Some(delta2)
}
(None, None) => {
None
}
};
let delta = delta.unwrap_or(vec3!(0.));
prev_positions.insert(self.action1.borrow().name().to_owned(), p1.map(|p1| (t, p1)));
prev_positions.insert(self.action2.borrow().name().to_owned(), p2.map(|p2| (t, p2)));
Some((p, delta))
}else{
None
}
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
if self.action1.needs_root_motion_reset(t) {
self.action1.reset_root_motion_orientations(object, self.action1.min_time_s(), current_value, prev_orientations);
}
if self.action2.needs_root_motion_reset(t) {
self.action2.reset_root_motion_orientations(object, self.action1.min_time_s(), current_value, prev_orientations);
}
let q1 = self.action1.orientation_at(object, t, current_value);
let q2 = self.action2.orientation_at(object, t, current_value);
let q = match (q1, q2){
(Some(q1), Some(q2)) => {
Some(q1 * q2)
}
(Some(q1), None) => {
Some(q1)
}
(None, Some(q2)) => {
Some(q2)
}
(None, None) => {
None
}
};
if let Some(q) = q{
let prev_q1 = prev_orientations.get(self.action1.borrow().name()).and_then(|q| *q);
let prev_q2 = prev_orientations.get(self.action2.borrow().name()).and_then(|q| *q);
let delta1 = match (q1, prev_q1) {
(Some(q1), Some((prev_t1, prev_q1))) => if prev_t1 < t {
Some(prev_q1.inverse() * q1)
}else{
None
}
_ => None
};
let delta2 = match (q2, prev_q2){
(Some(q2), Some((prev_t2, prev_q2))) => if prev_t2 < t {
Some(prev_q2.inverse() * q2)
}else{
None
}
_ => None
};
let delta = match (delta1, delta2){
(Some(delta1), Some(delta2)) => {
Some(delta1 * delta2)
}
(Some(delta1), None) => {
Some(delta1)
}
(None, Some(delta2)) => {
Some(delta2)
}
(None, None) => {
None
}
};
let delta = delta.unwrap_or(UnitQuat::identity());
prev_orientations.insert(self.action1.borrow().name().to_owned(), q1.map(|q1| (t, q1)));
prev_orientations.insert(self.action2.borrow().name().to_owned(), q2.map(|q2| (t, q2)));
Some((q, delta))
}else{
None
}
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
self.action1.needs_root_motion_reset(t) || self.action2.needs_root_motion_reset(t)
}
fn name(&self) -> &str{
&self.name
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
let r1 = self.action1.root_motion_remove(t);
let r2 = self.action2.root_motion_remove(t);
r1 | r2
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
self.action1.reset_root_motion_positions(object, t, current_value, prev_positions);
self.action2.reset_root_motion_positions(object, t, current_value, prev_positions);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
self.action1.reset_root_motion_orientations(object, t, current_value, prev_orientations);
self.action2.reset_root_motion_orientations(object, t, current_value, prev_orientations);
}
fn min_time_s(&self) -> f32{
self.action1.min_time_s().min(self.action2.min_time_s())
}
fn max_time_s(&self) -> f32{
self.action2.max_time_s().max(self.action2.max_time_s())
}
fn duration(&self) -> f32{
self.max_time_s() - self.min_time_s()
}
}
impl<A1: ActionNeedsUpdate, A2: ActionNeedsUpdate> ActionNeedsUpdate for ActionMix<A1, A2> {
const NEEDS_UPDATE: bool = A1::NEEDS_UPDATE | A2::NEEDS_UPDATE;
}
impl<A1: ActionUpdate, A2: ActionUpdate> ActionUpdate for ActionMix<A1, A2> {
fn update(&mut self){
self.action1.update();
self.action2.update();
}
}
impl ActionExt for rinblender::Action{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.orientation_at(object, t, current_value, false)
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.orientation_from_axis_angle_at(object, t, current_value, false)
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
self.orientation_from_euler_at(object, t, current_value, rot_order.into(), false)
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
self.location_at(object, t, current_value, false)
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
self.scale_at(object, t, current_value, false)
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
self.rotation_at(object, t, current_value.as_ref(), false)
.map(|r| r.into())
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
self.keyblock_at(keyblock, t, false)
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
self.hide_view_at(object, t, false)
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
self.hide_render_at(object, t, false)
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
let p = self.location_at(object, t, current_value, false);
if let Some(p) = p{
let delta = prev_positions.get(self.borrow().name()).and_then(|p| *p)
.map(|(prev_t, prev_p)| if prev_t < t {
p - prev_p
}else{
vec3!(0.)
})
.unwrap_or(vec3!(0.));
prev_positions.insert(self.borrow().name().to_owned(), Some((t, p)));
Some((p, delta))
}else{
prev_positions.remove(self.borrow().name());
None
}
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
let q = self.orientation_at(object, t, current_value, false);
if let Some(q) = q {
let delta = prev_orientations.get(self.borrow().name())
.and_then(|q| *q)
.map(|(prev_t, prev_q)| if prev_t < t {
prev_q.inverse() * q
}else{
UnitQuat::identity()
})
.unwrap_or(UnitQuat::identity());
prev_orientations.insert(self.borrow().name().to_owned(), Some((t, q)));
Some((q, delta))
}else{
prev_orientations.remove(self.borrow().name());
None
}
}
fn needs_root_motion_reset(&self, _t: f32) -> bool{
false
}
fn name(&self) -> &str{
self.name()
}
fn root_motion_remove(&self, _t: Option<f32>) -> RootMotionRemove{
RootMotionRemove::empty()
}
fn reset_root_motion_positions(&self, _object: &str, _t: f32, _current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
prev_positions.remove(self.name());
}
fn reset_root_motion_orientations(&self, _object: &str, _t: f32, _current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
prev_orientations.remove(self.name());
}
fn min_time_s(&self) -> f32{
self.min_time_s()
}
fn max_time_s(&self) -> f32{
self.max_time_s()
}
fn duration(&self) -> f32{
self.duration()
}
}
impl ActionNeedsUpdate for rinblender::Action {
const NEEDS_UPDATE: bool = false;
}
impl ActionUpdate for rinblender::Action {
fn update(&mut self){}
}
#[derive(Debug)]
pub struct ActionOffset<A>{
action: A,
offset: f32,
name: String,
}
impl<A: Clone> Clone for ActionOffset<A>{
fn clone(&self) -> ActionOffset<A>{
ActionOffset{
action: self.action.clone(),
offset: self.offset,
name: self.name.clone(),
}
}
}
impl<A: ActionExt> ActionOffset<A>{
pub fn new(action: A, offset: f32) -> ActionOffset<A>{
ActionOffset{
offset,
name: format!("{}_-{}", action.name(), offset),
action,
}
}
pub fn offset(&self) -> f32{
self.offset
}
}
impl<A: ActionExt> ActionExt for ActionOffset<A>{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.action.orientation_at(object, t - self.offset, current_value)
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.action.orientation_from_axis_angle_at(object, t - self.offset, current_value)
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
self.action.orientation_from_euler_at(object, t - self.offset, current_value, rot_order)
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
self.action.location_at(object, t - self.offset, current_value)
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
self.action.scale_at(object, t - self.offset, current_value)
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
self.action.rotation_at(object, t - self.offset, current_value)
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
self.action.keyblock_at(keyblock, t - self.offset)
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
self.action.hide_view_at(object, t - self.offset)
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
self.action.hide_render_at(object, t - self.offset)
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
self.action.root_motion_location_at(object, t - self.offset, current_value, prev_positions)
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
self.action.root_motion_orientation_at(object, t - self.offset, current_value, prev_orientations)
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
self.action.needs_root_motion_reset(t - self.offset)
}
fn name(&self) -> &str{
&self.name
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
self.action.root_motion_remove(t.map(|t| t - self.offset))
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
self.action.reset_root_motion_positions(object, t - self.offset, current_value, prev_positions)
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
self.action.reset_root_motion_orientations(object, t - self.offset, current_value, prev_orientations)
}
fn min_time_s(&self) -> f32{
self.action.min_time_s() + self.offset
}
fn max_time_s(&self) -> f32{
self.action.max_time_s() + self.offset
}
fn duration(&self) -> f32{
self.action.duration()
}
}
impl<A: ActionNeedsUpdate> ActionNeedsUpdate for ActionOffset<A> {
const NEEDS_UPDATE: bool = A::NEEDS_UPDATE;
}
impl<A: ActionUpdate> ActionUpdate for ActionOffset<A> {
fn update(&mut self){
self.action.update();
}
}
impl<'a, A: ActionExt> ActionExt for &'a A{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
(*self).orientation_at(object, t, current_value)
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
(*self).orientation_from_axis_angle_at(object, t, current_value)
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
(*self).orientation_from_euler_at(object, t, current_value, rot_order)
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
(*self).location_at(object, t, current_value)
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
(*self).scale_at(object, t, current_value)
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
(*self).rotation_at(object, t, current_value)
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
(*self).keyblock_at(keyblock, t)
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
(*self).hide_view_at(object, t)
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
(*self).hide_render_at(object, t)
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
(*self).root_motion_location_at(object, t, current_value, prev_positions)
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
(*self).root_motion_orientation_at(object, t, current_value, prev_orientations)
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
(*self).needs_root_motion_reset(t)
}
fn name(&self) -> &str{
(*self).name()
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
(*self).root_motion_remove(t)
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
(*self).reset_root_motion_positions(object, t, current_value, prev_positions);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
(*self).reset_root_motion_orientations(object, t, current_value, prev_orientations)
}
fn min_time_s(&self) -> f32{
(*self).min_time_s()
}
fn max_time_s(&self) -> f32{
(*self).max_time_s()
}
fn duration(&self) -> f32{
(*self).duration()
}
}
impl<'a, A: ActionNeedsUpdate> ActionNeedsUpdate for &'a A {
const NEEDS_UPDATE: bool = A::NEEDS_UPDATE;
}
impl<'a, A: ActionUpdate + ActionNeedsUpdate> ActionUpdate for &'a A {
fn update(&mut self){
if Self::NEEDS_UPDATE {
panic!("A reference to this type of action can't be used since it needs to be updated")
}else{
}
}
}
impl<A: ActionExt> ActionExt for std::sync::Arc<A> {
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
(**self).orientation_at(object, t, current_value)
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
(**self).orientation_from_axis_angle_at(object, t, current_value)
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
(**self).orientation_from_euler_at(object, t, current_value, rot_order)
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
(**self).location_at(object, t, current_value)
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
(**self).scale_at(object, t, current_value)
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
(**self).rotation_at(object, t, current_value)
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
(**self).keyblock_at(keyblock, t)
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
(**self).hide_view_at(object, t)
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
(**self).hide_render_at(object, t)
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
(**self).root_motion_location_at(object, t, current_value, prev_positions)
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
(**self).root_motion_orientation_at(object, t, current_value, prev_orientations)
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
(**self).needs_root_motion_reset(t)
}
fn name(&self) -> &str{
(**self).name()
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
(**self).root_motion_remove(t)
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
(**self).reset_root_motion_positions(object, t, current_value, prev_positions);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
(**self).reset_root_motion_orientations(object, t, current_value, prev_orientations)
}
fn min_time_s(&self) -> f32{
(**self).min_time_s()
}
fn max_time_s(&self) -> f32{
(**self).max_time_s()
}
fn duration(&self) -> f32{
(**self).duration()
}
}
impl<A: ActionNeedsUpdate> ActionNeedsUpdate for std::sync::Arc<A> {
const NEEDS_UPDATE: bool = A::NEEDS_UPDATE;
}
impl<A: ActionUpdate + ActionNeedsUpdate> ActionUpdate for std::sync::Arc<A> {
fn update(&mut self){
if Self::NEEDS_UPDATE {
panic!("An Arc<Action> to this type of action can't be used since it needs to be updated")
}else{
}
}
}
impl ActionExt for Box<dyn ActionUpdateExt + Send + Sync>{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
(**self).orientation_at(object, t, current_value)
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
(**self).orientation_from_axis_angle_at(object, t, current_value)
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
(**self).orientation_from_euler_at(object, t, current_value, rot_order)
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
(**self).location_at(object, t, current_value)
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
(**self).scale_at(object, t, current_value)
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
(**self).rotation_at(object, t, current_value)
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
(**self).keyblock_at(keyblock, t)
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
(**self).hide_view_at(object, t)
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
(**self).hide_render_at(object, t)
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
(**self).root_motion_location_at(object, t, current_value, prev_positions)
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
(**self).root_motion_orientation_at(object, t, current_value, prev_orientations)
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
(**self).needs_root_motion_reset(t)
}
fn name(&self) -> &str{
(**self).name()
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
(**self).root_motion_remove(t)
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
(**self).reset_root_motion_positions(object, t, current_value, prev_positions);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
(**self).reset_root_motion_orientations(object, t, current_value, prev_orientations)
}
fn min_time_s(&self) -> f32{
(**self).min_time_s()
}
fn max_time_s(&self) -> f32{
(**self).max_time_s()
}
fn duration(&self) -> f32{
(**self).duration()
}
}
impl ActionNeedsUpdate for Box<dyn ActionUpdateExt + Send + Sync> {
const NEEDS_UPDATE: bool = true;
}
impl ActionUpdate for Box<dyn ActionUpdateExt + Send + Sync> {
fn update(&mut self){
(**self).update();
}
}
#[derive(Component)]
#[debug_as_string]
pub struct Action{
action: Box<dyn ActionUpdateExt + Send + Sync>,
enabled: bool,
}
impl Action{
pub fn new<A: ActionUpdateExt + Send + Sync + 'static>(action: A) -> Action{
Action{
action: Box::new(action),
enabled: true,
}
}
pub fn empty() -> Action {
Action::new(())
}
pub fn set<A: ActionUpdateExt + Send + Sync + 'static>(&mut self, action: A){
self.action = Box::new(action);
}
pub fn mute(&mut self){
self.enabled = false;
}
pub fn unmute(&mut self){
self.enabled = true;
}
}
impl Debug for Action{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("Action")
.field("action", &self.action.name())
.finish()
}
}
impl ActionExt for Action{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
if self.enabled {
self.action.orientation_at(object, t, current_value)
}else{
None
}
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
if self.enabled {
self.action.orientation_from_axis_angle_at(object, t, current_value)
}else{
None
}
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
if self.enabled {
self.action.orientation_from_euler_at(object, t, current_value, rot_order)
}else{
None
}
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
if self.enabled {
self.action.location_at(object, t, current_value)
}else{
None
}
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
if self.enabled {
self.action.scale_at(object, t, current_value)
}else{
None
}
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
if self.enabled {
self.action.rotation_at(object, t, current_value)
}else{
None
}
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
if self.enabled {
self.action.keyblock_at(keyblock, t)
}else{
None
}
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
if self.enabled {
self.action.hide_view_at(object, t)
}else{
None
}
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
if self.enabled {
self.action.hide_render_at(object, t)
}else{
None
}
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
if self.enabled {
self.action.root_motion_location_at(object, t , current_value, prev_positions)
}else{
None
}
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
if self.enabled {
self.action.root_motion_orientation_at(object, t, current_value, prev_orientations)
}else{
None
}
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
self.action.needs_root_motion_reset(t)
}
fn name(&self) -> &str{
self.action.name()
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
self.action.root_motion_remove(t)
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
self.action.reset_root_motion_positions(object, t, current_value, prev_positions);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
self.action.reset_root_motion_orientations(object, t, current_value, prev_orientations)
}
fn min_time_s(&self) -> f32{
self.action.min_time_s()
}
fn max_time_s(&self) -> f32{
self.action.max_time_s()
}
fn duration(&self) -> f32{
self.action.duration()
}
}
impl ActionNeedsUpdate for Action {
const NEEDS_UPDATE: bool = true;
}
impl ActionUpdate for Action {
fn update(&mut self){
self.action.update();
}
}
#[derive(Debug)]
pub struct ActionController<A = rinblender::Action>{
action: A,
loop_action: bool,
root_motion_remove: RootMotionRemove,
name: String,
needs_root_motion_reset: bool,
reset_reset_root_motion: AtomicBool,
}
pub type ActionControllerArc = ActionController<std::sync::Arc<rinblender::Action>>;
impl<A: Clone> Clone for ActionController<A> {
fn clone(&self) -> ActionController<A> {
ActionController {
action: self.action.clone(),
loop_action: self.loop_action,
root_motion_remove: self.root_motion_remove,
name: self.name.clone(),
needs_root_motion_reset: self.needs_root_motion_reset,
reset_reset_root_motion: AtomicBool::new(self.reset_reset_root_motion.load(Ordering::SeqCst)),
}
}
}
pub struct ActionControllerBuilder<A>{
action: A,
loop_action: bool,
root_motion_remove: RootMotionRemove,
}
impl<A: Borrow<rinblender::Action>> ActionControllerBuilder<A>{
pub fn new(action: A) -> ActionControllerBuilder<A>{
ActionControllerBuilder{
action,
loop_action: false,
root_motion_remove: RootMotionRemove::empty(),
}
}
pub fn loop_action(mut self) -> ActionControllerBuilder<A>{
self.loop_action = true;
self
}
pub fn root_motion(mut self, root_motion: RootMotionRemove) -> ActionControllerBuilder<A>{
self.root_motion_remove = root_motion;
self
}
pub fn build(self) -> ActionController<A>{
ActionController{
name: format!("{}_C{}{:?}", self.action.borrow().name(), if self.loop_action{"l"}else{""}, self.root_motion_remove),
action: self.action,
root_motion_remove: self.root_motion_remove,
loop_action: self.loop_action,
needs_root_motion_reset: true,
reset_reset_root_motion: AtomicBool::default(),
}
}
}
impl<A> ActionController<A>{
pub fn loop_action(&self) -> bool{
self.loop_action
}
pub fn action(&self) -> &A{
&self.action
}
pub fn into_action(self) -> A{
self.action
}
}
impl<A: Borrow<rinblender::Action>> ActionExt for ActionController<A>{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.action.borrow().orientation_at(object, t, current_value, self.loop_action)
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.action.borrow().orientation_from_axis_angle_at(object, t, current_value, self.loop_action)
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
self.action.borrow().orientation_from_euler_at(object, t, current_value, rot_order.into(), self.loop_action)
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
self.action.borrow().location_at(object, t, current_value, self.loop_action)
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
self.action.borrow().scale_at(object, t, current_value, self.loop_action)
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
self.action
.borrow()
.rotation_at(object, t, current_value.as_ref(), self.loop_action)
.map(|r| r.into())
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
self.action.borrow().keyblock_at(keyblock, t, self.loop_action)
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
self.action.borrow().hide_view_at(object, t, self.loop_action)
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
self.action.borrow().hide_render_at(object, t, self.loop_action)
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
if self.needs_root_motion_reset {
self.reset_root_motion_positions(object, t, current_value, prev_positions);
}
if let Some(p) = self.action.borrow().location_at(object, t, current_value, self.loop_action) {
let delta = prev_positions.get(self.name())
.and_then(|p| *p)
.map(|(prev_t, prev_p)| if prev_t < t {
p - prev_p
}else{
vec3!(0.)
})
.unwrap_or(vec3!(0.));
prev_positions.insert(self.name().to_owned(), Some((t, p)));
Some((p, delta))
}else{
prev_positions.remove(self.name());
None
}
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
if self.needs_root_motion_reset {
self.reset_root_motion_orientations(object, t, current_value, prev_orientations);
}
if let Some(q) = self.action.borrow().orientation_at(object, t, current_value, self.loop_action) {
let delta = prev_orientations.get(self.name())
.and_then(|q| *q)
.map(|(prev_t, prev_q)| if prev_t < t {
prev_q.inverse() * q
}else{
UnitQuat::identity()
}).unwrap_or(UnitQuat::identity());
prev_orientations.insert(self.name().to_owned(), Some((t, q)));
Some((q, delta))
}else{
prev_orientations.remove(self.name());
None
}
}
fn needs_root_motion_reset(&self, _t: f32) -> bool{
self.needs_root_motion_reset
}
fn name(&self) -> &str{
self.action.borrow().name()
}
fn root_motion_remove(&self, _t: Option<f32>) -> RootMotionRemove{
self.root_motion_remove
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
if self.root_motion_remove.contains(RootMotionRemove::FROM_ZERO) && t > self.min_time_s() {
let first_value = self.action.borrow().location_at(
object,
self.action.borrow().min_time_s(),
current_value,
self.loop_action,
);
let first_value = first_value
.map(|v| (self.action.borrow().min_time_s(), v));
prev_positions.insert(self.name().to_owned(), first_value);
}else{
prev_positions.remove(self.name());
}
self.reset_reset_root_motion.store(true, Ordering::SeqCst);
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
if self.root_motion_remove.contains(RootMotionRemove::FROM_ZERO) && t > self.min_time_s() {
let first_value = self.action.borrow().orientation_at(
object,
self.action.borrow().min_time_s(),
current_value,
self.loop_action,
);
let first_value = first_value
.map(|v| (self.action.borrow().min_time_s(), v));
prev_orientations.insert(self.name().to_owned(), first_value);
}else{
prev_orientations.remove(self.name());
}
self.reset_reset_root_motion.store(true, Ordering::SeqCst);
}
fn min_time_s(&self) -> f32{
self.action.borrow().min_time_s()
}
fn max_time_s(&self) -> f32{
self.action.borrow().max_time_s()
}
fn duration(&self) -> f32{
self.action.borrow().duration()
}
}
impl<A> ActionNeedsUpdate for ActionController<A> {
const NEEDS_UPDATE: bool = true;
}
impl<A: Borrow<rinblender::Action>> ActionUpdate for ActionController<A>{
fn update(&mut self){
let reset = self.reset_reset_root_motion.get_mut();
if *reset {
self.needs_root_motion_reset = false;
*reset = false;
}
}
}
#[derive(Default, Clone, Debug)]
pub struct ActionCollection<A>{
actions: Vec<ActionOffset<A>>,
name: String,
}
impl<A: ActionExt> ActionCollection<A>{
pub fn new() -> ActionCollection<A>{
ActionCollection{
actions: vec![],
name: String::new(),
}
}
pub fn push(&mut self, action: A){
let offset = self.actions.last().map(|a| a.max_time_s()).unwrap_or(0.);
self.name += action.name();
self.name += "_";
self.actions.push(ActionOffset::new(action, offset));
}
}
impl<A: ActionExt> ActionCollection<A> {
fn find_action_at(&self, t: f32) -> Option<&ActionOffset<A>> {
if self.actions.is_empty(){
None
}else{
let ti = (t * 10000.) as i32;
let pos = self.actions
.binary_search_by_key(&ti, |action| (action.min_time_s() * 10000.) as i32);
let action = match pos {
Ok(pos) => &self.actions[pos],
Err(pos) => if pos > 0 { &self.actions[pos - 1] } else { &self.actions[0] },
};
Some(action)
}
}
}
impl<A: ActionExt> FromIterator<A> for ActionCollection<A>{
fn from_iter<I>(iter: I) -> ActionCollection<A>
where I: IntoIterator<Item = A>
{
let mut offset = 0.;
let mut name = String::new();
ActionCollection{
actions: iter.into_iter().map(|action| {
name += action.name();
name += "_";
let action = ActionOffset::new(action, offset);
offset = action.max_time_s();
action
}).collect(),
name,
}
}
}
impl<A: ActionExt> ActionExt for ActionCollection<A>{
fn orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.find_action_at(t).and_then(|a| a.orientation_at(object, t, current_value))
}
fn orientation_from_axis_angle_at(&self, object: &str, t: f32, current_value: &UnitQuat) -> Option<UnitQuat>{
self.find_action_at(t).and_then(|a| a.orientation_from_axis_angle_at(object, t, current_value))
}
fn orientation_from_euler_at(&self, object: &str, t: f32, current_value: &UnitQuat, rot_order: RotOrder) -> Option<UnitQuat>{
self.find_action_at(t).and_then(|a| a.orientation_from_euler_at(object, t, current_value, rot_order))
}
fn location_at(&self, object: &str, t: f32, current_value: &Pnt3) -> Option<Pnt3>{
self.find_action_at(t).and_then(|a| a.location_at(object, t, current_value))
}
fn scale_at(&self, object: &str, t: f32, current_value: &Vec3) -> Option<Vec3>{
self.find_action_at(t).and_then(|a| a.scale_at(object, t, current_value))
}
fn rotation_at(&self, object: &str, t: f32, current_value: &Rotation) -> Option<Rotation> {
self.find_action_at(t).and_then(|a| a.rotation_at(object, t, current_value))
}
fn keyblock_at(&self, keyblock: &str, t: f32) -> Option<f32> {
self.find_action_at(t).and_then(|a| a.keyblock_at(keyblock, t))
}
fn hide_view_at(&self, object: &str, t: f32) -> Option<bool> {
self.find_action_at(t).and_then(|a| a.hide_view_at(object, t))
}
fn hide_render_at(&self, object: &str, t: f32) -> Option<bool> {
self.find_action_at(t).and_then(|a| a.hide_render_at(object, t))
}
fn root_motion_location_at(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
self.find_action_at(t)
.and_then(|a| a.root_motion_location_at(object, t, current_value, prev_positions))
}
fn root_motion_orientation_at(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
self.find_action_at(t)
.and_then(|a| a.root_motion_orientation_at(object, t, current_value, prev_orientations))
}
fn name(&self) -> &str{
&self.name
}
fn root_motion_remove(&self, t: Option<f32>) -> RootMotionRemove{
if let Some(t) = t {
self.find_action_at(t)
.map(|a| a.root_motion_remove(Some(t)))
.unwrap_or(RootMotionRemove::empty())
}else{
self.actions.iter()
.map(|a| a.root_motion_remove(None))
.filter(|r| !r.is_empty())
.next()
.unwrap_or(RootMotionRemove::empty())
}
}
fn reset_root_motion_positions(&self, object: &str, t: f32, current_value: &Pnt3, prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){
if let Some(action) = self.find_action_at(t) {
action.reset_root_motion_positions(object, t, current_value, prev_positions)
}
}
fn reset_root_motion_orientations(&self, object: &str, t: f32, current_value: &UnitQuat, prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){
if let Some(action) = self.find_action_at(t) {
action.reset_root_motion_orientations(object, t, current_value, prev_orientations)
}
}
fn needs_root_motion_reset(&self, t: f32) -> bool{
self.find_action_at(t)
.map(|action| action.needs_root_motion_reset(t))
.unwrap_or(false)
}
fn min_time_s(&self) -> f32{
self.actions.first().map(|a| a.min_time_s()).unwrap_or(0.)
}
fn max_time_s(&self) -> f32{
self.actions.last().map(|a| a.max_time_s()).unwrap_or(0.)
}
fn duration(&self) -> f32{
self.max_time_s() - self.min_time_s()
}
}
impl<A: ActionNeedsUpdate> ActionNeedsUpdate for ActionCollection<A> {
const NEEDS_UPDATE: bool = A::NEEDS_UPDATE;
}
impl<A: ActionUpdate> ActionUpdate for ActionCollection<A>{
fn update(&mut self){
for action in self.actions.iter_mut() {
action.update();
}
}
}
pub struct ActionSpacer{
duration: f32,
}
impl ActionSpacer {
pub fn new(duration: f32) -> ActionSpacer {
ActionSpacer{ duration }
}
pub fn from_frames(frames: u32, fps: f32) -> ActionSpacer {
ActionSpacer{ duration: frames as f32 / fps }
}
}
impl ActionExt for ActionSpacer {
fn orientation_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat) -> Option<UnitQuat>{
None
}
fn orientation_from_axis_angle_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat) -> Option<UnitQuat>{
None
}
fn orientation_from_euler_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat, _rot_order: RotOrder) -> Option<UnitQuat>{
None
}
fn location_at(&self, _object: &str, _t: f32, _current_value: &Pnt3) -> Option<Pnt3>{
None
}
fn scale_at(&self, _object: &str, _t: f32, _current_value: &Vec3) -> Option<Vec3>{
None
}
fn rotation_at(&self, _object: &str, _t: f32, _current_value: &Rotation) -> Option<Rotation> {
None
}
fn keyblock_at(&self, _keyblock: &str, _t: f32) -> Option<f32>{
None
}
fn hide_view_at(&self, _object: &str, _t: f32) -> Option<bool>{
None
}
fn hide_render_at(&self, _object: &str, _t: f32) -> Option<bool>{
None
}
fn root_motion_location_at(&self, _object: &str, _: f32, _current_value: &Pnt3, _prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
None
}
fn root_motion_orientation_at(&self, _bject: &str, _t: f32, _current_value: &UnitQuat, _prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
None
}
fn needs_root_motion_reset(&self, _t: f32) -> bool{
false
}
fn name(&self) -> &str{
"Spacer Action"
}
fn root_motion_remove(&self, _t: Option<f32>) -> RootMotionRemove{
RootMotionRemove::empty()
}
fn reset_root_motion_positions(&self, _object: &str, _t: f32, _current_value: &Pnt3, _prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){}
fn reset_root_motion_orientations(&self, _object: &str, _t: f32, _current_value: &UnitQuat, _prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){}
fn min_time_s(&self) -> f32{
0.
}
fn max_time_s(&self) -> f32{
self.duration
}
fn duration(&self) -> f32{
self.duration
}
}
impl ActionNeedsUpdate for ActionSpacer {
const NEEDS_UPDATE: bool = false;
}
impl ActionUpdate for ActionSpacer {
fn update(&mut self){}
}
impl ActionExt for () {
fn orientation_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat) -> Option<UnitQuat>{
None
}
fn orientation_from_axis_angle_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat) -> Option<UnitQuat>{
None
}
fn orientation_from_euler_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat, _rot_order: RotOrder) -> Option<UnitQuat>{
None
}
fn location_at(&self, _object: &str, _t: f32, _current_value: &Pnt3) -> Option<Pnt3>{
None
}
fn scale_at(&self, _object: &str, _t: f32, _current_value: &Vec3) -> Option<Vec3>{
None
}
fn rotation_at(&self, _object: &str, _t: f32, _current_value: &Rotation) -> Option<Rotation> {
None
}
fn keyblock_at(&self, _keyblock: &str, _t: f32) -> Option<f32>{
None
}
fn hide_view_at(&self, _object: &str, _t: f32) -> Option<bool>{
None
}
fn hide_render_at(&self, _object: &str, _t: f32) -> Option<bool>{
None
}
fn root_motion_location_at(&self, _bject: &str, _t: f32, _current_value: &Pnt3, _prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>) -> Option<(Pnt3, Vec3)>{
None
}
fn root_motion_orientation_at(&self, _object: &str, _t: f32, _current_value: &UnitQuat, _prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>) -> Option<(UnitQuat, UnitQuat)>{
None
}
fn needs_root_motion_reset(&self, _t: f32) -> bool{
false
}
fn name(&self) -> &str{
"Empty action"
}
fn root_motion_remove(&self, _t: Option<f32>) -> RootMotionRemove{
RootMotionRemove::empty()
}
fn reset_root_motion_positions(&self, _object: &str, _t: f32, _current_value: &Pnt3, _prev_positions: &mut HashMap<String, Option<(f32, Pnt3)>>){}
fn reset_root_motion_orientations(&self, _object: &str, _t: f32, _current_value: &UnitQuat, _prev_orientations: &mut HashMap<String, Option<(f32, UnitQuat)>>){}
fn min_time_s(&self) -> f32{
0.
}
fn max_time_s(&self) -> f32{
0.
}
fn duration(&self) -> f32{
0.
}
}
impl ActionNeedsUpdate for () {
const NEEDS_UPDATE: bool = false;
}
impl ActionUpdate for () {
fn update(&mut self){}
}
pub trait ActionClockExt{
fn update(&mut self, clock: &Clock);
fn try_recv_time(&mut self) -> Option<f64>;
}
pub struct GameClock{
fps: f64,
now: f64,
t: f64,
time_factor: f64,
}
impl GameClock{
pub fn new(fps: f64, time_factor: f64) -> GameClock{
GameClock{
fps,
now: 0.,
t: 0.,
time_factor,
}
}
pub fn with_initial_time(fps: f64, time_factor: f64, initial_t: f64) -> GameClock{
GameClock{
fps,
now: initial_t,
t: initial_t,
time_factor,
}
}
pub fn now(&self) -> f64{
self.t
}
}
impl ActionClockExt for GameClock{
fn update(&mut self, clock: &Clock){
let delta = clock
.game_time_delta()
.as_seconds();
self.now += delta * self.time_factor;
}
fn try_recv_time(&mut self) -> Option<f64>{
let fixed_step = 1. / self.fps as f64;
if self.now - self.t > fixed_step {
self.t += fixed_step;
Some(self.t)
}else{
None
}
}
}
pub struct GameClockNoFps{
now: f64,
time_factor: f64,
}
impl GameClockNoFps{
pub fn new(time_factor: f64) -> GameClockNoFps{
GameClockNoFps{
now: 0.,
time_factor,
}
}
pub fn with_initial_time(time_factor: f64, initial_t: f64) -> GameClockNoFps{
GameClockNoFps{
now: initial_t,
time_factor,
}
}
pub fn now(&self) -> f64{
self.now
}
}
impl ActionClockExt for GameClockNoFps{
fn update(&mut self, clock: &Clock){
let delta = clock
.game_time_delta()
.as_seconds();
self.now += delta * self.time_factor;
}
fn try_recv_time(&mut self) -> Option<f64>{
Some(self.now)
}
}
pub struct ConstantClock{
t: Option<f64>,
now: f64,
}
impl ConstantClock{
pub fn new(t: f64) -> ConstantClock{
ConstantClock{
t: Some(t),
now: t,
}
}
pub fn now(&self) -> f64{
self.now
}
}
impl ActionClockExt for ConstantClock{
fn update(&mut self, _clock: &Clock){
}
fn try_recv_time(&mut self) -> Option<f64>{
self.t.take()
}
}
pub struct LoopClock<C: ActionClockExt>{
start_t: f64,
end_t: f64,
clock: C,
}
impl<C:ActionClockExt> LoopClock<C>{
pub fn new(start_t: f64, end_t: f64, clock: C) -> LoopClock<C>{
LoopClock{
start_t,
end_t,
clock,
}
}
}
impl<C:ActionClockExt> ActionClockExt for LoopClock<C>{
fn update(&mut self, clock: &Clock){
self.clock.update(clock);
}
fn try_recv_time(&mut self) -> Option<f64>{
self.clock.try_recv_time().map(|t|{
let duration = self.end_t - self.start_t;
((t - self.start_t) % duration) + self.start_t
})
}
}
pub struct ClockOffset<C: ActionClockExt>{
clock: C,
offset: f64,
}
impl<C: ActionClockExt> ClockOffset<C>{
pub fn new(clock: C, offset: f64) -> ClockOffset<C>{
ClockOffset{
clock,
offset,
}
}
}
impl<C: ActionClockExt> ActionClockExt for ClockOffset<C> {
fn update(&mut self, clock: &Clock){
self.clock.update(clock);
}
fn try_recv_time(&mut self) -> Option<f64>{
self.clock.try_recv_time().map(|t| t + self.offset)
}
}
pub struct ReverseClock<C: ActionClockExt>{
clock: C,
offset: f64,
}
impl<C: ActionClockExt> ReverseClock<C>{
pub fn new(clock: C, offset: f64) -> ReverseClock<C>{
ReverseClock{
clock,
offset,
}
}
}
impl<C: ActionClockExt> ActionClockExt for ReverseClock<C> {
fn update(&mut self, clock: &Clock){
self.clock.update(clock);
}
fn try_recv_time(&mut self) -> Option<f64>{
self.clock.try_recv_time().map(|t| self.offset - t)
}
}
impl<'a> ActionClockExt for events::TryIter<'a, f64>{
fn update(&mut self, _clock: &Clock){
}
fn try_recv_time(&mut self) -> Option<f64>{
self.next()
}
}
impl ActionClockExt for mpsc::Receiver<f64>{
fn update(&mut self, _clock: &Clock){
}
fn try_recv_time(&mut self) -> Option<f64>{
self.try_recv().ok()
}
}
#[derive(Component, Serialize)]
pub struct ActionClock{
#[serde(skip)]
clock: Box<dyn ActionClockExt + Send>,
now: f64,
last_recv_time: Option<f64>,
}
unsafe impl Sync for ActionClock{}
impl ActionClock{
pub fn new<C: ActionClockExt + Send + 'static>(clock: C) -> ActionClock{
ActionClock{
clock: Box::new(clock),
now: 0.,
last_recv_time: None,
}
}
pub fn now(&self) -> f64{
self.now
}
pub fn last_recv_time(&self) -> Option<f64>{
self.last_recv_time
}
}
impl Debug for ActionClock{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("ActionClock")
.field("now", &self.now)
.finish()
}
}
impl ActionClockExt for ActionClock{
fn update(&mut self, clock: &Clock){
self.clock.update(clock);
self.last_recv_time = None;
}
fn try_recv_time(&mut self) -> Option<f64>{
if let Some(t) = self.clock.try_recv_time(){
self.now = t;
self.last_recv_time = Some(t);
Some(t)
}else{
None
}
}
}