use crate::scene::node::constructor::NodeConstructor;
use crate::{
core::{
math::aabb::AxisAlignedBoundingBox,
pool::Handle,
reflect::prelude::*,
type_traits::prelude::*,
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
},
scene::{
animation::prelude::*,
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, UpdateContext},
Scene,
},
};
use fyrox_graph::constructor::ConstructorProvider;
use fyrox_graph::SceneGraph;
use std::any::{Any, TypeId};
use std::ops::{Deref, DerefMut};
pub type RootMotionSettings = crate::generic_animation::RootMotionSettings<Handle<Node>>;
pub type PoseNode = crate::generic_animation::machine::PoseNode<Handle<Node>>;
pub type PlayAnimation = crate::generic_animation::machine::node::play::PlayAnimation<Handle<Node>>;
pub type BlendAnimations =
crate::generic_animation::machine::node::blend::BlendAnimations<Handle<Node>>;
pub type BlendAnimationsByIndex =
crate::generic_animation::machine::node::blend::BlendAnimationsByIndex<Handle<Node>>;
pub type BlendPose = crate::generic_animation::machine::node::blend::BlendPose<Handle<Node>>;
pub type IndexedBlendInput =
crate::generic_animation::machine::node::blend::IndexedBlendInput<Handle<Node>>;
pub type BlendSpace = crate::generic_animation::machine::node::blendspace::BlendSpace<Handle<Node>>;
pub type BlendSpacePoint =
crate::generic_animation::machine::node::blendspace::BlendSpacePoint<Handle<Node>>;
pub type LayerMask = crate::generic_animation::machine::mask::LayerMask<Handle<Node>>;
pub type Event = crate::generic_animation::machine::event::Event<Handle<Node>>;
pub type Machine = crate::generic_animation::machine::Machine<Handle<Node>>;
pub type MachineLayer = crate::generic_animation::machine::MachineLayer<Handle<Node>>;
pub type Transition = crate::generic_animation::machine::transition::Transition<Handle<Node>>;
pub type State = crate::generic_animation::machine::state::State<Handle<Node>>;
pub type BasePoseNode = crate::generic_animation::machine::node::BasePoseNode<Handle<Node>>;
pub type StateAction = crate::generic_animation::machine::state::StateAction<Handle<Node>>;
pub type StateActionWrapper =
crate::generic_animation::machine::state::StateActionWrapper<Handle<Node>>;
pub type LogicNode = crate::generic_animation::machine::transition::LogicNode<Handle<Node>>;
pub type AndNode = crate::generic_animation::machine::transition::AndNode<Handle<Node>>;
pub type XorNode = crate::generic_animation::machine::transition::XorNode<Handle<Node>>;
pub type OrNode = crate::generic_animation::machine::transition::OrNode<Handle<Node>>;
pub type NotNode = crate::generic_animation::machine::transition::NotNode<Handle<Node>>;
pub type LayerAnimationEventsCollection =
crate::generic_animation::machine::layer::LayerAnimationEventsCollection<Handle<Node>>;
pub type AnimationEventsSource =
crate::generic_animation::machine::layer::AnimationEventsSource<Handle<Node>>;
pub mod prelude {
pub use super::{
AndNode, AnimationBlendingStateMachine, AnimationBlendingStateMachineBuilder,
AnimationEventsSource, BasePoseNode, BlendAnimations, BlendAnimationsByIndex, BlendPose,
BlendSpace, BlendSpacePoint, Event, IndexedBlendInput, LayerAnimationEventsCollection,
LayerMask, LogicNode, Machine, MachineLayer, NotNode, OrNode, PlayAnimation, PoseNode,
RootMotionSettings, State, StateAction, StateActionWrapper, Transition, XorNode,
};
pub use crate::generic_animation::machine::{
node::AnimationEventCollectionStrategy,
parameter::{Parameter, ParameterContainer, ParameterDefinition, PoseWeight},
};
}
pub trait LayerMaskExt {
fn from_hierarchy(graph: &Graph, root: Handle<Node>) -> Self;
}
impl LayerMaskExt for LayerMask {
fn from_hierarchy(graph: &Graph, root: Handle<Node>) -> Self {
Self::from(
graph
.traverse_iter(root)
.map(|(handle, _)| handle)
.collect::<Vec<_>>(),
)
}
}
type MachineType = InheritableVariable<Machine>;
type AnimationPlayerHandle = InheritableVariable<Handle<AnimationPlayer>>;
type AnimationPlayerUntypedHandle = InheritableVariable<Handle<Node>>;
#[derive(Visit, Reflect, Clone, Debug, Default)]
#[reflect(derived_type = "Node")]
pub struct AnimationBlendingStateMachine {
base: Base,
machine: MachineType,
animation_player: AnimationPlayerHandle,
}
impl ComponentProvider for AnimationBlendingStateMachine {
fn query_component_ref(&self, type_id: TypeId) -> Option<&dyn Any> {
if type_id == TypeId::of::<Self>() {
Some(self)
} else if type_id == TypeId::of::<MachineType>() {
Some(&self.machine)
} else if type_id == TypeId::of::<AnimationPlayerUntypedHandle>() {
Some(unsafe {
std::mem::transmute::<&AnimationPlayerHandle, &AnimationPlayerUntypedHandle>(
&self.animation_player,
)
})
} else {
None
}
}
fn query_component_mut(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
if type_id == TypeId::of::<Self>() {
Some(self)
} else if type_id == TypeId::of::<MachineType>() {
Some(&mut self.machine)
} else if type_id == TypeId::of::<AnimationPlayerUntypedHandle>() {
Some(unsafe {
std::mem::transmute::<&mut AnimationPlayerHandle, &mut AnimationPlayerUntypedHandle>(
&mut self.animation_player,
)
})
} else {
None
}
}
}
impl AnimationBlendingStateMachine {
pub fn set_machine(&mut self, machine: Machine) {
self.machine.set_value_and_mark_modified(machine);
}
pub fn machine(&self) -> &InheritableVariable<Machine> {
&self.machine
}
pub fn machine_mut(&mut self) -> &mut InheritableVariable<Machine> {
&mut self.machine
}
pub fn set_animation_player(&mut self, animation_player: Handle<AnimationPlayer>) {
self.animation_player
.set_value_and_mark_modified(animation_player);
}
pub fn animation_player(&self) -> Handle<AnimationPlayer> {
*self.animation_player
}
}
impl TypeUuidProvider for AnimationBlendingStateMachine {
fn type_uuid() -> Uuid {
uuid!("4b08c753-2a10-41e3-8fb2-4fd0517e86bc")
}
}
impl Deref for AnimationBlendingStateMachine {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for AnimationBlendingStateMachine {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl ConstructorProvider<Node, Graph> for AnimationBlendingStateMachine {
fn constructor() -> NodeConstructor {
NodeConstructor::new::<Self>()
.with_variant("Animation Blending State Machine", |_| {
let mut machine = Machine::default();
let mut layer = MachineLayer::new();
layer.set_name("Base Layer");
machine.add_layer(layer);
AnimationBlendingStateMachineBuilder::new(
BaseBuilder::new().with_name("Animation Blending State Machine"),
)
.with_machine(machine)
.build_node()
.into()
})
.with_group("Animation")
}
}
impl NodeTrait for AnimationBlendingStateMachine {
fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
self.base.local_bounding_box()
}
fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
self.base.world_bounding_box()
}
fn id(&self) -> Uuid {
Self::type_uuid()
}
fn update(&mut self, context: &mut UpdateContext) {
if let Ok(animation_player) = context.nodes.try_get_mut(*self.animation_player) {
animation_player.set_auto_apply(false);
let pose = self.machine.get_value_mut_silent().evaluate_pose(
animation_player.animations.get_value_mut_silent(),
context.dt,
);
pose.apply_internal(context.nodes);
}
}
fn validate(&self, scene: &Scene) -> Result<(), String> {
if scene.graph.try_get(*self.animation_player).is_err() {
Err(
"Animation player is not set or invalid! Animation blending state \
machine won't operate! Set the animation player handle in the Inspector."
.to_string(),
)
} else {
Ok(())
}
}
}
pub struct AnimationBlendingStateMachineBuilder {
base_builder: BaseBuilder,
machine: Machine,
animation_player: Handle<AnimationPlayer>,
}
impl AnimationBlendingStateMachineBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
machine: Default::default(),
animation_player: Default::default(),
}
}
pub fn with_machine(mut self, machine: Machine) -> Self {
self.machine = machine;
self
}
pub fn with_animation_player(mut self, animation_player: Handle<AnimationPlayer>) -> Self {
self.animation_player = animation_player;
self
}
pub fn build_node(self) -> Node {
Node::new(AnimationBlendingStateMachine {
base: self.base_builder.build_base(),
machine: self.machine.into(),
animation_player: self.animation_player.into(),
})
}
pub fn build(self, graph: &mut Graph) -> Handle<AnimationBlendingStateMachine> {
graph.add_node(self.build_node()).to_variant()
}
}