use crate::scene::node::constructor::NodeConstructor;
use crate::{
core::{
log::{Log, MessageKind},
math::aabb::AxisAlignedBoundingBox,
pool::Handle,
reflect::prelude::*,
type_traits::prelude::*,
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
},
generic_animation::value::{BoundValueCollection, TrackValue, ValueBinding},
scene::{
base::{Base, BaseBuilder},
graph::{Graph, NodePool},
node::{Node, NodeTrait, UpdateContext},
},
};
use fyrox_graph::constructor::ConstructorProvider;
use fyrox_graph::SceneGraph;
use std::ops::{Deref, DerefMut};
pub mod absm;
pub mod spritesheet;
pub type Animation = crate::generic_animation::Animation<Handle<Node>>;
pub type Track = crate::generic_animation::track::Track;
pub type AnimationContainer = crate::generic_animation::AnimationContainer<Handle<Node>>;
pub type AnimationPose = crate::generic_animation::AnimationPose<Handle<Node>>;
pub type NodePose = crate::generic_animation::NodePose<Handle<Node>>;
pub mod prelude {
pub use super::{
Animation, AnimationContainer, AnimationContainerExt, AnimationPlayer,
AnimationPlayerBuilder, AnimationPose, AnimationPoseExt, BoundValueCollectionExt, NodePose,
Track,
};
pub use crate::generic_animation::{
container::{TrackDataContainer, TrackValueKind},
signal::AnimationSignal,
value::{BoundValueCollection, TrackValue, ValueBinding, ValueType},
AnimationEvent,
};
}
pub trait AnimationContainerExt {
fn update_animations(&mut self, nodes: &mut NodePool, dt: f32);
}
impl AnimationContainerExt for AnimationContainer {
fn update_animations(&mut self, nodes: &mut NodePool, dt: f32) {
for animation in self.iter_mut().filter(|anim| anim.is_enabled()) {
animation.tick(dt);
animation.pose().apply_internal(nodes);
}
}
}
pub trait AnimationPoseExt {
fn apply_internal(&self, nodes: &mut NodePool);
fn apply(&self, graph: &mut Graph);
fn apply_with<C>(&self, graph: &mut Graph, callback: C)
where
C: FnMut(&mut Node, Handle<Node>, &NodePose);
}
impl AnimationPoseExt for AnimationPose {
fn apply_internal(&self, nodes: &mut NodePool) {
for (node, local_pose) in self.poses() {
if node.is_none() {
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
} else if let Ok(node) = nodes.try_borrow_mut(*node) {
local_pose.values.apply(node);
}
}
}
fn apply(&self, graph: &mut Graph) {
for (node, local_pose) in self.poses() {
if node.is_none() {
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
} else if let Ok(node) = graph.try_get_node_mut(*node) {
local_pose.values.apply(node);
}
}
}
fn apply_with<C>(&self, graph: &mut Graph, mut callback: C)
where
C: FnMut(&mut Node, Handle<Node>, &NodePose),
{
for (node, local_pose) in self.poses() {
if node.is_none() {
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
} else if let Ok(node_ref) = graph.try_get_node_mut(*node) {
callback(node_ref, *node, local_pose);
}
}
}
}
pub trait BoundValueCollectionExt {
fn apply(&self, node_ref: &mut Node);
}
impl BoundValueCollectionExt for BoundValueCollection {
fn apply(&self, node_ref: &mut Node) {
for bound_value in self.values.iter() {
match bound_value.binding {
ValueBinding::Position => {
if let TrackValue::Vector3(v) = bound_value.value {
node_ref.local_transform_mut().set_position(v);
} else {
Log::err(
"Unable to apply position, because underlying type is not Vector3!",
)
}
}
ValueBinding::Scale => {
if let TrackValue::Vector3(v) = bound_value.value {
node_ref.local_transform_mut().set_scale(v);
} else {
Log::err("Unable to apply scaling, because underlying type is not Vector3!")
}
}
ValueBinding::Rotation => {
if let TrackValue::UnitQuaternion(v) = bound_value.value {
node_ref.local_transform_mut().set_rotation(v);
} else {
Log::err("Unable to apply rotation, because underlying type is not UnitQuaternion!")
}
}
ValueBinding::Property {
name: ref property_name,
value_type,
} => bound_value.apply_to_object(node_ref, property_name, value_type),
}
}
}
}
#[derive(Visit, Reflect, Clone, Debug, ComponentProvider)]
#[reflect(derived_type = "Node")]
pub struct AnimationPlayer {
base: Base,
#[component(include)]
animations: InheritableVariable<AnimationContainer>,
#[component(include)]
auto_apply: bool,
}
impl Default for AnimationPlayer {
fn default() -> Self {
Self {
base: Default::default(),
animations: Default::default(),
auto_apply: true,
}
}
}
impl AnimationPlayer {
pub fn set_auto_apply(&mut self, auto_apply: bool) {
self.auto_apply = auto_apply;
}
pub fn is_auto_apply(&self) -> bool {
self.auto_apply
}
pub fn animations(&self) -> &InheritableVariable<AnimationContainer> {
&self.animations
}
pub fn animations_mut(&mut self) -> &mut InheritableVariable<AnimationContainer> {
&mut self.animations
}
pub fn set_animations(&mut self, animations: AnimationContainer) {
self.animations.set_value_and_mark_modified(animations);
}
}
impl TypeUuidProvider for AnimationPlayer {
fn type_uuid() -> Uuid {
uuid!("44d1c94e-354f-4f9a-b918-9d31c28aa16a")
}
}
impl Deref for AnimationPlayer {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for AnimationPlayer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl ConstructorProvider<Node, Graph> for AnimationPlayer {
fn constructor() -> NodeConstructor {
NodeConstructor::new::<Self>()
.with_variant("Animation Player", |_| {
AnimationPlayerBuilder::new(BaseBuilder::new().with_name("Animation Player"))
.build_node()
.into()
})
.with_group("Animation")
}
}
impl NodeTrait for AnimationPlayer {
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 self.auto_apply {
self.animations
.get_value_mut_silent()
.update_animations(context.nodes, context.dt);
}
}
}
pub struct AnimationPlayerBuilder {
base_builder: BaseBuilder,
animations: AnimationContainer,
auto_apply: bool,
}
impl AnimationPlayerBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
animations: AnimationContainer::new(),
auto_apply: true,
}
}
pub fn with_animations(mut self, animations: AnimationContainer) -> Self {
self.animations = animations;
self
}
pub fn with_auto_apply(mut self, auto_apply: bool) -> Self {
self.auto_apply = auto_apply;
self
}
pub fn build_node(self) -> Node {
Node::new(AnimationPlayer {
base: self.base_builder.build_base(),
animations: self.animations.into(),
auto_apply: self.auto_apply,
})
}
pub fn build(self, graph: &mut Graph) -> Handle<Node> {
graph.add_node(self.build_node())
}
}