diff --git a/.idea/rg3d-core.iml b/.idea/rg3d-core.iml index a9ad7420a..19864a77b 100644 --- a/.idea/rg3d-core.iml +++ b/.idea/rg3d-core.iml @@ -31,6 +31,7 @@ + diff --git a/Cargo.toml b/Cargo.toml index c689867bb..f71adce6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ members = [ "fyrox-ui", "fyrox-resource", "fyrox-scripts", + "fyrox-animation", "editor", "editor-standalone", "template" @@ -41,6 +42,7 @@ fyrox-core = { path = "fyrox-core", version = "0.26.0", features = ["serde"] } fyrox-sound = { path = "fyrox-sound", version = "0.33.0" } fyrox-ui = { path = "fyrox-ui", version = "0.23.0" } fyrox-resource = { path = "fyrox-resource", version = "0.10.0" } +fyrox-animation = { path = "fyrox-animation", version = "0.1.0" } rapier2d = { version = "0.17", features = ["debug-render"] } rapier3d = { version = "0.17", features = ["debug-render"] } image = { version = "0.24.3", default-features = false, features = ["gif", "jpeg", "png", "tga", "tiff", "bmp"] } @@ -58,7 +60,6 @@ fxhash = "0.2.1" strum = "0.25.0" strum_macros = "0.25.0" clap = { version = "4", features = ["derive"] } -spade = "2.1.0" winit = { version = "0.29.2", features = ["serde"] } half = "2.2.1" fast_image_resize = "2.7.0" diff --git a/editor/src/absm/mod.rs b/editor/src/absm/mod.rs index 9ffed0d86..782a6510f 100644 --- a/editor/src/absm/mod.rs +++ b/editor/src/absm/mod.rs @@ -484,7 +484,7 @@ impl AbsmEditor { let mut animation_targets = FxHashSet::default(); for animation in animation_player.animations_mut().iter_mut() { for track in animation.tracks() { - animation_targets.insert(track.target()); + animation_targets.insert(Handle::::from(track.target())); } } diff --git a/editor/src/absm/toolbar.rs b/editor/src/absm/toolbar.rs index 287eca6eb..db11c8f63 100644 --- a/editor/src/absm/toolbar.rs +++ b/editor/src/absm/toolbar.rs @@ -1,4 +1,3 @@ -use crate::message::MessageSender; use crate::{ absm::{ command::{AddLayerCommand, RemoveLayerCommand, SetLayerMaskCommand, SetLayerNameCommand}, @@ -7,6 +6,7 @@ use crate::{ }, gui::make_dropdown_list_option, load_image, + message::MessageSender, scene::{ commands::{ChangeSelectionCommand, CommandGroup, GameSceneCommand}, selector::{HierarchyNode, NodeSelectorMessage, NodeSelectorWindowBuilder}, @@ -14,8 +14,6 @@ use crate::{ }, send_sync_message, }; -use fyrox::core::pool::ErasedHandle; -use fyrox::scene::node::Node; use fyrox::{ animation::machine::{LayerMask, MachineLayer}, core::pool::Handle, @@ -252,14 +250,14 @@ impl Toolbar { .cloned() .filter(|n| { graph - .try_get(*n) - .map_or(false, |n| !unique_nodes.contains(&n.parent())) + .try_get((*n).into()) + .map_or(false, |n| !unique_nodes.contains(&(n.parent().into()))) }) .collect::>(); for local_root in local_roots { root.children.push(HierarchyNode::from_scene_node( - local_root, + local_root.into(), game_scene.editor_objects_root, graph, )); @@ -283,12 +281,8 @@ impl Toolbar { if let Some(layer_index) = selection.layer { if let Some(layer) = absm_node.machine().layers().get(layer_index) { - let selection = layer - .mask() - .inner() - .iter() - .map(|h| ErasedHandle::from(*h)) - .collect::>(); + let selection = + layer.mask().inner().iter().cloned().collect::>(); ui.send_message(NodeSelectorMessage::selection( self.node_selector, @@ -332,12 +326,7 @@ impl Toolbar { && message.direction() == MessageDirection::FromWidget { if let Some(layer_index) = selection.layer { - let new_mask = LayerMask::from( - mask_selection - .iter() - .map(|h| Handle::::from(*h)) - .collect::>(), - ); + let new_mask = LayerMask::from(mask_selection.clone()); sender.do_scene_command(SetLayerMaskCommand { absm_node_handle: selection.absm_node_handle, layer_index, diff --git a/editor/src/animation/command/mod.rs b/editor/src/animation/command/mod.rs index 5020682b0..3f44d5ec0 100644 --- a/editor/src/animation/command/mod.rs +++ b/editor/src/animation/command/mod.rs @@ -603,7 +603,7 @@ impl SetTrackTargetCommand { .find(|t| t.id() == self.track) .unwrap(); - let old = track.target(); + let old = track.target().into(); track.set_target(self.target); self.target = old; } diff --git a/editor/src/animation/mod.rs b/editor/src/animation/mod.rs index 9e97a686e..f866e5324 100644 --- a/editor/src/animation/mod.rs +++ b/editor/src/animation/mod.rs @@ -353,7 +353,7 @@ impl AnimationEditor { let animation_targets = animation .tracks() .iter() - .map(|t| t.target()) + .map(|t| Handle::::from(t.target())) .collect::>(); self.enter_preview_mode( diff --git a/editor/src/animation/toolbar.rs b/editor/src/animation/toolbar.rs index b6181afee..0dad4bd7b 100644 --- a/editor/src/animation/toolbar.rs +++ b/editor/src/animation/toolbar.rs @@ -263,7 +263,7 @@ impl RootMotionDropdownArea { self.node_selector, MessageDirection::ToWidget, if settings.node.is_some() { - vec![settings.node.into()] + vec![settings.node] } else { vec![] }, @@ -285,7 +285,7 @@ impl RootMotionDropdownArea { node_handle: selection.animation_player, animation_handle: selection.animation, value: Some(RootMotionSettings { - node: node_selection.first().cloned().unwrap_or_default().into(), + node: node_selection.first().cloned().unwrap_or_default(), ..*settings }), }); @@ -346,7 +346,7 @@ impl RootMotionDropdownArea { MessageDirection::ToWidget, scene .graph - .try_get(settings.node) + .try_get(settings.node.into()) .map(|n| n.name().to_owned()) .unwrap_or_else(|| String::from("")), ), diff --git a/editor/src/animation/track.rs b/editor/src/animation/track.rs index db6bea6d6..97369d82f 100644 --- a/editor/src/animation/track.rs +++ b/editor/src/animation/track.rs @@ -852,21 +852,21 @@ impl TrackList { sender.do_scene_command(AddTrackCommand::new( animation_player, animation, - Track::new_position().with_target(self.selected_node), + Track::new_position().with_target(self.selected_node.into()), )); } PropertyBindingMode::Rotation => { sender.do_scene_command(AddTrackCommand::new( animation_player, animation, - Track::new_rotation().with_target(self.selected_node), + Track::new_rotation().with_target(self.selected_node.into()), )); } PropertyBindingMode::Scale => { sender.do_scene_command(AddTrackCommand::new( animation_player, animation, - Track::new_scale().with_target(self.selected_node), + Track::new_scale().with_target(self.selected_node.into()), )); } } @@ -1185,7 +1185,7 @@ impl TrackList { .find(|t| t.id() == first_selected_track) { self.context_menu.property_rebinding_selector = - Self::open_property_selector(graph, track.target(), ui); + Self::open_property_selector(graph, track.target().into(), ui); } } @@ -1223,7 +1223,7 @@ impl TrackList { return; }; - let Some(node) = graph.try_get(track.target()) else { + let Some(node) = graph.try_get(track.target().into()) else { Log::err("Invalid node handle!"); return; }; @@ -1348,7 +1348,8 @@ impl TrackList { .map(|v| ui.node(*v)) .all(|v| v.query_component::().unwrap().id != model_track.id()) { - let parent_group = match self.group_views.entry(model_track.target()) { + let parent_group = match self.group_views.entry(model_track.target().into()) + { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let ctx = &mut ui.build_ctx(); @@ -1361,7 +1362,7 @@ impl TrackList { .with_text(format!( "{} ({}:{})", graph - .try_get(model_track.target()) + .try_get(model_track.target().into()) .map(|n| n.name()) .unwrap_or_default(), model_track.target().index(), @@ -1420,7 +1421,7 @@ impl TrackList { ) .with_track_enabled(model_track.is_enabled()) .with_id(model_track.id()) - .with_target(model_track.target()) + .with_target(model_track.target().into()) .with_name(format!("{}", model_track.binding())) .build(ctx); @@ -1495,8 +1496,8 @@ impl TrackList { } let mut validation_result = Ok(()); - if let Some(target) = graph.try_get(track_model.target()) { - if let Some(parent_group) = self.group_views.get(&track_model.target()) { + if let Some(target) = graph.try_get(track_model.target().into()) { + if let Some(parent_group) = self.group_views.get(&track_model.target().into()) { send_sync_message( ui, TextMessage::text( diff --git a/fyrox-animation/Cargo.toml b/fyrox-animation/Cargo.toml new file mode 100644 index 000000000..afb2173e9 --- /dev/null +++ b/fyrox-animation/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "fyrox-animation" +version = "0.1.0" +edition = "2021" + +[dependencies] +fyrox-core = { version = "0.26.0", path = "../fyrox-core" } +fyrox-resource = { version = "0.10.0", path = "../fyrox-resource" } +strum = "0.25.0" +strum_macros = "0.25.0" +fxhash = "0.2.1" +spade = "2.1.0" \ No newline at end of file diff --git a/src/animation/container.rs b/fyrox-animation/src/container.rs similarity index 99% rename from src/animation/container.rs rename to fyrox-animation/src/container.rs index 6a5238ffb..7cc0ef5db 100644 --- a/src/animation/container.rs +++ b/fyrox-animation/src/container.rs @@ -2,7 +2,6 @@ //! of parametric curves. See [`TrackDataContainer`] docs for more info. use crate::{ - animation::value::TrackValue, core::{ algebra::{Vector2, Vector3, Vector4}, curve::Curve, @@ -10,6 +9,7 @@ use crate::{ reflect::prelude::*, visitor::prelude::*, }, + value::TrackValue, }; /// The kind of track output value, the animation system works only with numeric properties and the number diff --git a/src/animation/mod.rs b/fyrox-animation/src/lib.rs similarity index 91% rename from src/animation/mod.rs rename to fyrox-animation/src/lib.rs index bed93c8dd..ae4fcb14b 100644 --- a/src/animation/mod.rs +++ b/fyrox-animation/src/lib.rs @@ -4,7 +4,6 @@ #![warn(missing_docs)] use crate::{ - animation::track::Track, core::{ algebra::{UnitQuaternion, Vector3}, math::wrapf, @@ -13,22 +12,21 @@ use crate::{ uuid::Uuid, visitor::{Visit, VisitResult, Visitor}, }, - scene::{ - graph::{Graph, NodePool}, - node::Node, - }, - utils::{self, NameProvider}, + track::Track, }; -use fyrox_core::uuid_provider; +use fyrox_core::{uuid_provider, NameProvider}; use std::{ collections::VecDeque, fmt::Debug, ops::{Index, IndexMut, Range}, }; -use crate::animation::value::{TrackValue, ValueBinding}; +pub use fyrox_core as core; +use fyrox_core::pool::ErasedHandle; + pub use pose::{AnimationPose, NodePose}; pub use signal::{AnimationEvent, AnimationSignal}; +use value::{TrackValue, ValueBinding}; pub mod container; pub mod machine; @@ -117,26 +115,19 @@ pub mod value; /// Use the following example code as a guide **only** if you need to create procedural animations: /// /// ```rust -/// use fyrox::{ -/// animation::{ -/// container::{TrackDataContainer, TrackValueKind}, -/// track::Track, -/// value::ValueBinding, -/// Animation, -/// }, +/// use fyrox_animation::{ +/// container::{TrackDataContainer, TrackValueKind}, +/// track::Track, +/// value::ValueBinding, +/// Animation, /// core::{ /// curve::{Curve, CurveKey, CurveKeyKind}, /// pool::Handle, /// }, -/// scene::{ -/// node::Node, -/// base::BaseBuilder, -/// graph::Graph, -/// pivot::PivotBuilder -/// } /// }; +/// use fyrox_core::pool::ErasedHandle; /// -/// fn create_animation(node: Handle) -> Animation { +/// fn create_animation(target: ErasedHandle) -> Animation { /// let mut frames_container = TrackDataContainer::new(TrackValueKind::Vector3); /// /// // We'll animate only X coordinate (at index 0). @@ -148,7 +139,7 @@ pub mod value; /// /// // Create a track that will animated the node using the curve above. /// let mut track = Track::new(frames_container, ValueBinding::Position); -/// track.set_target(node); +/// track.set_target(target); /// /// // Finally create an animation and set its time slice and turn it on. /// let mut animation = Animation::default(); @@ -159,17 +150,12 @@ pub mod value; /// animation /// } /// -/// // Create a graph with a node. -/// let mut graph = Graph::new(); -/// let some_node = PivotBuilder::new(BaseBuilder::new()).build(&mut graph); -/// /// // Create the animation. -/// let mut animation = create_animation(some_node); +/// let mut animation = create_animation(Default::default()); /// /// // Emulate some ticks (like it was updated from the main loop of your game). /// for _ in 0..10 { /// animation.tick(1.0 / 60.0); -/// animation.pose().apply(&mut graph); /// } /// ``` /// @@ -215,7 +201,7 @@ uuid_provider!(Animation = "aade8e9d-e2cf-401d-a4d1-59c6943645f3"); pub struct RootMotionSettings { /// A handle to a node which movement will be extracted and put in root motion field of an animation /// to which these settings were set to. - pub node: Handle, + pub node: ErasedHandle, /// Keeps X part of the translational part of the motion. pub ignore_x_movement: bool, /// Keeps Y part of the translational part of the motion. @@ -683,39 +669,8 @@ impl Animation { self.tracks.retain(filter) } - /// Enables or disables animation tracks for nodes in hierarchy starting from given root. Could be useful to enable - /// or disable animation for skeleton parts, i.e. you don't want legs to be animated and you know that legs starts - /// from torso bone, then you could do this. - /// - /// ``` - /// use fyrox::scene::node::Node; - /// use fyrox::animation::Animation; - /// use fyrox::core::pool::Handle; - /// use fyrox::scene::graph::Graph; - /// - /// fn disable_legs(torso_bone: Handle, aim_animation: &mut Animation, graph: &Graph) { - /// aim_animation.set_tracks_enabled_from(torso_bone, false, graph) - /// } - /// ``` - /// - /// After this legs won't be animated and animation could be blended together with run animation so it will produce - /// new animation - run and aim. - pub fn set_tracks_enabled_from(&mut self, handle: Handle, enabled: bool, graph: &Graph) { - let mut stack = vec![handle]; - while let Some(node) = stack.pop() { - for track in self.tracks.iter_mut() { - if track.target() == node { - track.set_enabled(enabled); - } - } - for child in graph[node].children() { - stack.push(*child); - } - } - } - /// Tries to find all tracks that refer to a given node and enables or disables them. - pub fn set_node_track_enabled(&mut self, handle: Handle, enabled: bool) { + pub fn set_node_track_enabled(&mut self, handle: ErasedHandle, enabled: bool) { for track in self.tracks.iter_mut() { if track.target() == handle { track.set_enabled(enabled); @@ -724,14 +679,14 @@ impl Animation { } /// Returns an iterator that yields a number of references to tracks that refer to a given node. - pub fn tracks_of(&self, handle: Handle) -> impl Iterator { + pub fn tracks_of(&self, handle: ErasedHandle) -> impl Iterator { self.tracks .iter() .filter(move |track| track.target() == handle) } /// Returns an iterator that yields a number of references to tracks that refer to a given node. - pub fn tracks_of_mut(&mut self, handle: Handle) -> impl Iterator { + pub fn tracks_of_mut(&mut self, handle: ErasedHandle) -> impl Iterator { self.tracks .iter_mut() .filter(move |track| track.target() == handle) @@ -743,7 +698,7 @@ impl Animation { &self, name: S, ) -> Option<(usize, &AnimationSignal)> { - utils::find_by_name_ref(self.signals.iter().enumerate(), name) + core::find_by_name_ref(self.signals.iter().enumerate(), name) } /// Tries to find a signal by its name. Returns index of the signal and its reference. @@ -752,7 +707,7 @@ impl Animation { &mut self, name: S, ) -> Option<(usize, &mut AnimationSignal)> { - utils::find_by_name_mut(self.signals.iter_mut().enumerate(), name) + core::find_by_name_mut(self.signals.iter_mut().enumerate(), name) } /// Returns `true` if there's a signal with given name and id. @@ -920,7 +875,7 @@ impl AnimationContainer { &self, name: S, ) -> Option<(Handle, &Animation)> { - utils::find_by_name_ref(self.pool.pair_iter(), name) + core::find_by_name_ref(self.pool.pair_iter(), name) } /// Tries to find an animation by its name in the container. @@ -929,7 +884,7 @@ impl AnimationContainer { &mut self, name: S, ) -> Option<(Handle, &mut Animation)> { - utils::find_by_name_mut(self.pool.pair_iter_mut(), name) + core::find_by_name_mut(self.pool.pair_iter_mut(), name) } /// Removes every animation from the container that does not satisfy a particular condition represented by the given @@ -942,17 +897,6 @@ impl AnimationContainer { self.pool.retain(pred) } - /// Updates all animations in the container and applies their poses to respective nodes. This method is intended to - /// be used only by the internals of the engine! - pub fn update_animations(&mut self, nodes: &mut NodePool, apply: bool, dt: f32) { - for animation in self.pool.iter_mut().filter(|anim| anim.enabled) { - animation.tick(dt); - if apply { - animation.pose.apply_internal(nodes); - } - } - } - /// Removes queued animation events from every animation in the container. /// /// # Potential use cases diff --git a/src/animation/machine/event.rs b/fyrox-animation/src/machine/event.rs similarity index 97% rename from src/animation/machine/event.rs rename to fyrox-animation/src/machine/event.rs index 7849c8610..fdbf7acec 100644 --- a/src/animation/machine/event.rs +++ b/fyrox-animation/src/machine/event.rs @@ -2,8 +2,8 @@ //! needed to works with such events. use crate::{ - animation::machine::{State, Transition}, core::pool::Handle, + machine::{State, Transition}, }; use std::collections::VecDeque; diff --git a/src/animation/machine/layer.rs b/fyrox-animation/src/machine/layer.rs similarity index 96% rename from src/animation/machine/layer.rs rename to fyrox-animation/src/machine/layer.rs index 96b712632..3ff954e82 100644 --- a/src/animation/machine/layer.rs +++ b/fyrox-animation/src/machine/layer.rs @@ -1,25 +1,20 @@ //! Layer is a separate state graph that usually animates only a part of nodes from animations. See docs of [`MachineLayer`] //! for more info. -use crate::animation::machine::node::AnimationEventCollectionStrategy; -use crate::animation::machine::AnimationPoseSource; -use crate::animation::AnimationEvent; use crate::{ - animation::{ - machine::{ - event::FixedEventQueue, Event, LayerMask, ParameterContainer, PoseNode, State, - Transition, - }, - Animation, AnimationContainer, AnimationPose, - }, core::{ log::{Log, MessageKind}, pool::{Handle, Pool}, reflect::prelude::*, visitor::prelude::*, }, - utils::{self, NameProvider}, + machine::{ + event::FixedEventQueue, node::AnimationEventCollectionStrategy, AnimationPoseSource, Event, + LayerMask, ParameterContainer, PoseNode, State, Transition, + }, + Animation, AnimationContainer, AnimationEvent, AnimationPose, }; +use fyrox_core::{find_by_name_mut, find_by_name_ref, NameProvider}; /// Layer is a separate state graph. Layers mainly used to animate different parts of humanoid (but not only) characters. For /// example there could a layer for upper body and a layer for lower body. Upper body layer could contain animations for aiming, @@ -30,8 +25,8 @@ use crate::{ /// # Example /// /// ```rust -/// use fyrox::{ -/// animation::machine::{ +/// use fyrox_animation::{ +/// machine::{ /// State, Transition, PoseNode, MachineLayer, /// Parameter, PlayAnimation, PoseWeight, BlendAnimations, BlendPose /// }, @@ -241,7 +236,7 @@ impl MachineLayer { /// # Example /// /// ```rust - /// use fyrox::animation::machine::{Event, MachineLayer}; + /// use fyrox_animation::machine::{Event, MachineLayer}; /// /// let mut layer = MachineLayer::new(); /// @@ -451,7 +446,7 @@ impl MachineLayer { &self, name: S, ) -> Option<(Handle, &Transition)> { - utils::find_by_name_ref(self.transitions.pair_iter(), name) + find_by_name_ref(self.transitions.pair_iter(), name) } /// Tries to find a transition by its name. @@ -460,7 +455,7 @@ impl MachineLayer { &mut self, name: S, ) -> Option<(Handle, &mut Transition)> { - utils::find_by_name_mut(self.transitions.pair_iter_mut(), name) + find_by_name_mut(self.transitions.pair_iter_mut(), name) } /// Tries to borrow a state using its handle, panics if the handle is invalid. @@ -481,7 +476,7 @@ impl MachineLayer { &self, name: S, ) -> Option<(Handle, &State)> { - utils::find_by_name_ref(self.states.pair_iter(), name) + find_by_name_ref(self.states.pair_iter(), name) } /// Tries to find a state by its name. @@ -490,7 +485,7 @@ impl MachineLayer { &mut self, name: S, ) -> Option<(Handle, &mut State)> { - utils::find_by_name_mut(self.states.pair_iter_mut(), name) + find_by_name_mut(self.states.pair_iter_mut(), name) } /// Returns a reference to inner states container. diff --git a/src/animation/machine/mask.rs b/fyrox-animation/src/machine/mask.rs similarity index 76% rename from src/animation/machine/mask.rs rename to fyrox-animation/src/machine/mask.rs index 995d95034..0e5f20871 100644 --- a/src/animation/machine/mask.rs +++ b/fyrox-animation/src/machine/mask.rs @@ -1,34 +1,24 @@ //! Layer mask is a sort of blacklist that prevents layer from animating certain nodes. See [`LayerMask`] docs //! for more info. -use crate::{ - core::{pool::Handle, reflect::prelude::*, visitor::prelude::*}, - scene::{graph::Graph, node::Node}, -}; +use crate::core::{pool::ErasedHandle, reflect::prelude::*, visitor::prelude::*}; /// Layer mask is a sort of blacklist that prevents layer from animating certain nodes. Its main use case is to /// disable animation on animation layers for specific body parts of humanoid (but not only) characters. The /// mask holds handles of nodes that **will not** be animated. #[derive(Default, Debug, Visit, Reflect, Clone, PartialEq, Eq)] pub struct LayerMask { - excluded_bones: Vec>, + excluded_bones: Vec, } -impl From>> for LayerMask { - fn from(mut excluded_bones: Vec>) -> Self { +impl From> for LayerMask { + fn from(mut excluded_bones: Vec) -> Self { excluded_bones.sort_by_key(|h| h.index()); Self { excluded_bones } } } impl LayerMask { - /// Creates a layer mask for every descendant node starting from specified `root` (included). It could - /// be useful if you have an entire node hierarchy (for example, lower part of a body) that needs to - /// be filtered out. - pub fn from_hierarchy(graph: &Graph, root: Handle) -> Self { - Self::from(graph.traverse_handle_iter(root).collect::>()) - } - /// Merges a given layer mask in the current mask, handles will be automatically de-duplicated. pub fn merge(&mut self, other: LayerMask) { for handle in other.into_inner() { @@ -46,7 +36,7 @@ impl LayerMask { /// /// The method has O(log(n)) complexity, which means it is very fast for most use cases. #[inline] - pub fn add(&mut self, node: Handle) { + pub fn add(&mut self, node: ErasedHandle) { let index = self .excluded_bones .partition_point(|h| h.index() < node.index()); @@ -59,13 +49,13 @@ impl LayerMask { /// # Performance /// /// The method has O(log(n)) complexity, which means it is very fast for most use cases. - pub fn remove(&mut self, node: Handle) { + pub fn remove(&mut self, node: ErasedHandle) { if let Some(index) = self.index_of(node) { self.excluded_bones.remove(index); } } - fn index_of(&self, node: Handle) -> Option { + fn index_of(&self, node: ErasedHandle) -> Option { if let Ok(mut index) = self .excluded_bones .binary_search_by(|h| h.index().cmp(&node.index())) @@ -98,7 +88,7 @@ impl LayerMask { /// /// The method has O(log(n)) complexity, which means it is very fast for most use cases. #[inline] - pub fn contains(&self, node: Handle) -> bool { + pub fn contains(&self, node: ErasedHandle) -> bool { self.index_of(node).is_some() } @@ -108,20 +98,20 @@ impl LayerMask { /// /// The method has O(log(n)) complexity, which means it is very fast for most use cases. #[inline] - pub fn should_animate(&self, node: Handle) -> bool { + pub fn should_animate(&self, node: ErasedHandle) -> bool { !self.contains(node) } /// Return a reference to inner container. There's only non-mutable version because inner container must always /// be sorted. #[inline] - pub fn inner(&self) -> &Vec> { + pub fn inner(&self) -> &Vec { &self.excluded_bones } /// Converts the mask into inner container. #[inline] - pub fn into_inner(self) -> Vec> { + pub fn into_inner(self) -> Vec { self.excluded_bones } } diff --git a/src/animation/machine/mod.rs b/fyrox-animation/src/machine/mod.rs similarity index 97% rename from src/animation/machine/mod.rs rename to fyrox-animation/src/machine/mod.rs index ac782ab04..45b6f7e1d 100644 --- a/src/animation/machine/mod.rs +++ b/fyrox-animation/src/machine/mod.rs @@ -6,15 +6,15 @@ #![warn(missing_docs)] use crate::{ - animation::{AnimationContainer, AnimationPose}, core::{ reflect::prelude::*, visitor::{Visit, VisitResult, Visitor}, }, - utils, + AnimationContainer, AnimationPose, }; pub use event::Event; +use fyrox_core::{find_by_name_mut, find_by_name_ref}; pub use layer::MachineLayer; pub use mask::LayerMask; pub use node::{ @@ -122,8 +122,8 @@ pub mod transition; /// using code like so: /// /// ```no_run -/// use fyrox::{ -/// animation::machine::{ +/// use fyrox_animation::{ +/// machine::{ /// Machine, State, Transition, PoseNode, /// Parameter, PlayAnimation, PoseWeight, BlendAnimations, BlendPose /// }, @@ -193,7 +193,7 @@ impl Machine { /// The method returns a reference to the machine, so the calls could be chained: /// /// ```rust - /// use fyrox::animation::machine::{Machine, Parameter}; + /// use fyrox_animation::machine::{Machine, Parameter}; /// /// let mut machine = Machine::new(); /// @@ -266,7 +266,7 @@ impl Machine { /// Tries to find a layer by its name. Returns index of the layer and its reference. #[inline] pub fn find_layer_by_name_ref>(&self, name: S) -> Option<(usize, &MachineLayer)> { - utils::find_by_name_ref(self.layers.iter().enumerate(), name) + find_by_name_ref(self.layers.iter().enumerate(), name) } /// Tries to find a layer by its name. Returns index of the layer and its reference. @@ -275,7 +275,7 @@ impl Machine { &mut self, name: S, ) -> Option<(usize, &mut MachineLayer)> { - utils::find_by_name_mut(self.layers.iter_mut().enumerate(), name) + find_by_name_mut(self.layers.iter_mut().enumerate(), name) } /// Returns final pose of the machine. diff --git a/src/animation/machine/node/blend.rs b/fyrox-animation/src/machine/node/blend.rs similarity index 97% rename from src/animation/machine/node/blend.rs rename to fyrox-animation/src/machine/node/blend.rs index 954bfa760..9b38334aa 100644 --- a/src/animation/machine/node/blend.rs +++ b/fyrox-animation/src/machine/node/blend.rs @@ -1,20 +1,16 @@ //! Various animation blending nodes. -use crate::animation::machine::node::AnimationEventCollectionStrategy; -use crate::animation::{Animation, AnimationEvent}; use crate::{ - animation::{ - machine::{ - node::BasePoseNode, AnimationPoseSource, Parameter, ParameterContainer, PoseNode, - PoseWeight, - }, - AnimationContainer, AnimationPose, - }, core::{ pool::{Handle, Pool}, reflect::prelude::*, visitor::{Visit, VisitResult, Visitor}, }, + machine::{ + node::AnimationEventCollectionStrategy, node::BasePoseNode, AnimationPoseSource, Parameter, + ParameterContainer, PoseNode, PoseWeight, + }, + Animation, AnimationContainer, AnimationEvent, AnimationPose, }; use fyrox_core::uuid_provider; use std::cmp::Ordering; diff --git a/src/animation/machine/node/blendspace.rs b/fyrox-animation/src/machine/node/blendspace.rs similarity index 97% rename from src/animation/machine/node/blendspace.rs rename to fyrox-animation/src/machine/node/blendspace.rs index bf92552eb..47ed17ece 100644 --- a/src/animation/machine/node/blendspace.rs +++ b/fyrox-animation/src/machine/node/blendspace.rs @@ -1,14 +1,6 @@ #![allow(missing_docs)] // TODO -use crate::animation::machine::node::AnimationEventCollectionStrategy; -use crate::animation::{Animation, AnimationEvent}; use crate::{ - animation::{ - machine::{ - node::BasePoseNode, AnimationPoseSource, Parameter, ParameterContainer, PoseNode, - }, - AnimationContainer, AnimationPose, - }, core::{ algebra::Vector2, math::{self, TriangleDefinition}, @@ -16,6 +8,11 @@ use crate::{ reflect::prelude::*, visitor::prelude::*, }, + machine::{ + node::AnimationEventCollectionStrategy, node::BasePoseNode, AnimationPoseSource, Parameter, + ParameterContainer, PoseNode, + }, + Animation, AnimationContainer, AnimationEvent, AnimationPose, }; use fyrox_core::uuid_provider; use spade::{DelaunayTriangulation, Point2, Triangulation}; @@ -429,8 +426,8 @@ impl BlendSpace { #[cfg(test)] mod test { use crate::{ - animation::machine::node::blendspace::{BlendSpace, BlendSpacePoint}, core::{algebra::Vector2, math::TriangleDefinition}, + machine::node::blendspace::{BlendSpace, BlendSpacePoint}, }; #[test] diff --git a/src/animation/machine/node/mod.rs b/fyrox-animation/src/machine/node/mod.rs similarity index 94% rename from src/animation/machine/node/mod.rs rename to fyrox-animation/src/machine/node/mod.rs index 7c9adbaee..4e6dad56d 100644 --- a/src/animation/machine/node/mod.rs +++ b/fyrox-animation/src/machine/node/mod.rs @@ -1,21 +1,18 @@ //! Node is a part of animation blending tree, that backs a state with animation data. See [`PoseNode`] docs for //! more info. -use crate::animation::AnimationEvent; use crate::{ - animation::{ - machine::{ - node::{blend::BlendAnimations, blendspace::BlendSpace, play::PlayAnimation}, - BlendAnimationsByIndex, BlendPose, IndexedBlendInput, ParameterContainer, State, - }, - Animation, AnimationContainer, AnimationPose, - }, core::{ algebra::Vector2, pool::{Handle, Pool}, reflect::prelude::*, visitor::prelude::*, }, + machine::{ + node::{blend::BlendAnimations, blendspace::BlendSpace, play::PlayAnimation}, + BlendAnimationsByIndex, BlendPose, IndexedBlendInput, ParameterContainer, State, + }, + Animation, AnimationContainer, AnimationEvent, AnimationPose, }; use std::{ cell::Ref, diff --git a/src/animation/machine/node/play.rs b/fyrox-animation/src/machine/node/play.rs similarity index 90% rename from src/animation/machine/node/play.rs rename to fyrox-animation/src/machine/node/play.rs index e130eafe9..1f76312d6 100644 --- a/src/animation/machine/node/play.rs +++ b/fyrox-animation/src/machine/node/play.rs @@ -1,20 +1,17 @@ //! A simplest pose node that extracts pose from a specific animation and prepares it for further use. -use crate::animation::machine::node::AnimationEventCollectionStrategy; -use crate::animation::AnimationEvent; use crate::{ - animation::{ - machine::{ - node::{AnimationPoseSource, BasePoseNode}, - ParameterContainer, PoseNode, - }, - Animation, AnimationContainer, AnimationPose, - }, core::{ pool::{Handle, Pool}, reflect::prelude::*, visitor::prelude::*, }, + machine::{ + node::AnimationEventCollectionStrategy, + node::{AnimationPoseSource, BasePoseNode}, + ParameterContainer, PoseNode, + }, + Animation, AnimationContainer, AnimationEvent, AnimationPose, }; use std::{ cell::{Ref, RefCell}, diff --git a/src/animation/machine/parameter.rs b/fyrox-animation/src/machine/parameter.rs similarity index 100% rename from src/animation/machine/parameter.rs rename to fyrox-animation/src/machine/parameter.rs diff --git a/src/animation/machine/state.rs b/fyrox-animation/src/machine/state.rs similarity index 95% rename from src/animation/machine/state.rs rename to fyrox-animation/src/machine/state.rs index 8c440297f..a452be969 100644 --- a/src/animation/machine/state.rs +++ b/fyrox-animation/src/machine/state.rs @@ -1,20 +1,17 @@ //! State is a final "container" for animation pose. See [`State`] docs for more info. use crate::{ - animation::{ - machine::{AnimationPoseSource, ParameterContainer, PoseNode}, - Animation, AnimationContainer, AnimationPose, - }, core::{ algebra::Vector2, pool::{Handle, Pool}, + rand::{self, seq::IteratorRandom}, reflect::prelude::*, visitor::prelude::*, }, - rand::{self, seq::IteratorRandom}, - utils::NameProvider, + machine::{AnimationPoseSource, ParameterContainer, PoseNode}, + Animation, AnimationContainer, AnimationPose, }; -use fyrox_core::uuid_provider; +use fyrox_core::{uuid_provider, NameProvider}; use std::{ cell::Ref, ops::{Deref, DerefMut}, diff --git a/src/animation/machine/transition.rs b/fyrox-animation/src/machine/transition.rs similarity index 98% rename from src/animation/machine/transition.rs rename to fyrox-animation/src/machine/transition.rs index f0ea05b72..051d5eafe 100644 --- a/src/animation/machine/transition.rs +++ b/fyrox-animation/src/machine/transition.rs @@ -1,14 +1,11 @@ //! Transition is a connection between two states with a rule that defines possibility of actual transition with blending. use crate::{ - animation::{ - machine::{Parameter, ParameterContainer, State}, - Animation, AnimationContainer, - }, core::{pool::Handle, reflect::prelude::*, visitor::prelude::*}, - utils::NameProvider, + machine::{Parameter, ParameterContainer, State}, + Animation, AnimationContainer, }; -use fyrox_core::uuid_provider; +use fyrox_core::{uuid_provider, NameProvider}; use std::any::{type_name, Any, TypeId}; use strum_macros::{AsRefStr, EnumString, EnumVariantNames}; @@ -266,8 +263,8 @@ impl Reflect for NotNode { /// # Examples /// /// ```rust -/// use fyrox::animation::AnimationContainer; -/// use fyrox::animation::machine::{ +/// use fyrox_animation::AnimationContainer; +/// use fyrox_animation::machine::{ /// transition::{AndNode, LogicNode, NotNode}, /// Parameter, ParameterContainer, /// }; diff --git a/src/animation/pose.rs b/fyrox-animation/src/pose.rs similarity index 58% rename from src/animation/pose.rs rename to fyrox-animation/src/pose.rs index 266162a18..2c0c3286f 100644 --- a/src/animation/pose.rs +++ b/fyrox-animation/src/pose.rs @@ -1,36 +1,21 @@ //! Pose is a set of property values of a node ([`NodePose`]) or a set of nodes ([`AnimationPose`]). -use crate::{ - animation::{value::BoundValue, value::BoundValueCollection, RootMotion}, - core::{ - log::{Log, MessageKind}, - pool::Handle, - }, - scene::{graph::Graph, graph::NodePool, node::Node}, -}; +use crate::{value::BoundValue, value::BoundValueCollection, RootMotion}; use fxhash::FxHashMap; +use fyrox_core::pool::ErasedHandle; use std::collections::hash_map::Entry; /// A "captured" state of properties of some animated scene node. The pose can be considered as container of values of some /// properties. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Default)] pub struct NodePose { /// A handle of an animated node. - pub node: Handle, + pub node: ErasedHandle, /// A set of property values. pub values: BoundValueCollection, } -impl Default for NodePose { - fn default() -> Self { - Self { - node: Handle::NONE, - values: Default::default(), - } - } -} - impl NodePose { /// Performs a blending of the current with some other pose. See [`super::value::TrackValue::blend_with`] docs for more /// info. @@ -42,7 +27,7 @@ impl NodePose { /// Animations pose is a set of node poses. See [`NodePose`] docs for more info. #[derive(Default, Debug, Clone, PartialEq)] pub struct AnimationPose { - poses: FxHashMap, NodePose>, + poses: FxHashMap, root_motion: Option, } @@ -87,7 +72,7 @@ impl AnimationPose { self.poses.insert(local_pose.node, local_pose); } - pub(super) fn add_to_node_pose(&mut self, node: Handle, bound_value: BoundValue) { + pub(super) fn add_to_node_pose(&mut self, node: ErasedHandle, bound_value: BoundValue) { match self.poses.entry(node) { Entry::Occupied(entry) => { entry.into_mut().values.values.push(bound_value); @@ -109,48 +94,12 @@ impl AnimationPose { } /// Returns a reference to inner node pose map. - pub fn poses(&self) -> &FxHashMap, NodePose> { + pub fn poses(&self) -> &FxHashMap { &self.poses } /// Returns a reference to inner node pose map. - pub fn poses_mut(&mut self) -> &mut FxHashMap, NodePose> { + pub fn poses_mut(&mut self) -> &mut FxHashMap { &mut self.poses } - - pub(crate) fn apply_internal(&self, nodes: &mut NodePool) { - for (node, local_pose) in self.poses.iter() { - 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 Some(node) = nodes.try_borrow_mut(*node) { - local_pose.values.apply(node); - } - } - } - - /// Tries to set each value to the each property from the animation pose to respective scene nodes. - pub fn apply(&self, graph: &mut Graph) { - for (node, local_pose) in self.poses.iter() { - 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 Some(node) = graph.try_get_mut(*node) { - local_pose.values.apply(node); - } - } - } - - /// Calls given callback function for each node and allows you to apply pose with your own - /// rules. This could be useful if you need to ignore transform some part of pose for a node. - pub fn apply_with(&self, graph: &mut Graph, mut callback: C) - where - C: FnMut(&mut Node, Handle, &NodePose), - { - for (node, local_pose) in self.poses.iter() { - 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 Some(node_ref) = graph.try_get_mut(*node) { - callback(node_ref, *node, local_pose); - } - } - } } diff --git a/src/animation/signal.rs b/fyrox-animation/src/signal.rs similarity index 95% rename from src/animation/signal.rs rename to fyrox-animation/src/signal.rs index 41a669f98..0b0923c42 100644 --- a/src/animation/signal.rs +++ b/fyrox-animation/src/signal.rs @@ -1,9 +1,7 @@ //! Signal is a named marker on specific time position on the animation timeline. See [`AnimationSignal`] docs for more info. -use crate::{ - core::{reflect::prelude::*, uuid::Uuid, visitor::prelude::*}, - utils::NameProvider, -}; +use crate::core::{reflect::prelude::*, uuid::Uuid, visitor::prelude::*}; +use fyrox_core::NameProvider; /// An event happened in an animation. #[derive(Clone, PartialEq, Eq, Debug)] diff --git a/src/animation/spritesheet/mod.rs b/fyrox-animation/src/spritesheet/mod.rs similarity index 97% rename from src/animation/spritesheet/mod.rs rename to fyrox-animation/src/spritesheet/mod.rs index dd8360ad0..9677d4e99 100644 --- a/src/animation/spritesheet/mod.rs +++ b/fyrox-animation/src/spritesheet/mod.rs @@ -4,11 +4,11 @@ #![warn(missing_docs)] use crate::{ - animation::spritesheet::signal::Signal, core::{algebra::Vector2, math::Rect, reflect::prelude::*, visitor::prelude::*}, - resource::texture::TextureResource, + spritesheet::signal::Signal, }; use fyrox_core::uuid_provider; +use fyrox_resource::untyped::UntypedResource; use std::collections::vec_deque::VecDeque; use strum_macros::{AsRefStr, EnumString, EnumVariantNames}; @@ -58,7 +58,7 @@ pub struct SpriteSheetFramesContainer { size: Vector2, frames: Vec>, #[visit(optional)] - texture: Option, + texture: Option, } impl SpriteSheetFramesContainer { @@ -115,7 +115,7 @@ impl SpriteSheetFramesContainer { } /// Returns current texture of the container. To set a texture use sprite sheet animation methods. - pub fn texture(&self) -> Option { + pub fn texture(&self) -> Option { self.texture.clone() } } @@ -143,7 +143,7 @@ pub struct SpriteSheetAnimation { signals: Vec, #[visit(optional)] #[reflect(setter = "set_texture")] - texture: Option, + texture: Option, #[reflect(hidden)] #[visit(skip)] events: VecDeque, @@ -221,8 +221,8 @@ impl SpriteSheetAnimation { /// like this: /// /// ```rust - /// # use fyrox::{ - /// # animation::spritesheet::{ImageParameters, SpriteSheetAnimation}, + /// # use fyrox_animation::{ + /// # spritesheet::{ImageParameters, SpriteSheetAnimation}, /// # core::math::Rect, /// # }; /// fn extract_animations() { @@ -310,13 +310,13 @@ impl SpriteSheetAnimation { } /// Sets new texture for the animation. - pub fn set_texture(&mut self, texture: Option) -> Option { + pub fn set_texture(&mut self, texture: Option) -> Option { self.frames_container.texture = texture.clone(); std::mem::replace(&mut self.texture, texture) } /// Returns current texture of the animation. - pub fn texture(&self) -> Option { + pub fn texture(&self) -> Option { self.texture.clone() } @@ -510,7 +510,7 @@ impl SpriteSheetAnimation { #[cfg(test)] mod test { - use crate::animation::spritesheet::{ + use crate::spritesheet::{ signal::Signal, Event, ImageParameters, SpriteSheetAnimation, Status, }; use fyrox_core::algebra::Vector2; diff --git a/src/animation/spritesheet/signal.rs b/fyrox-animation/src/spritesheet/signal.rs similarity index 100% rename from src/animation/spritesheet/signal.rs rename to fyrox-animation/src/spritesheet/signal.rs diff --git a/src/animation/track.rs b/fyrox-animation/src/track.rs similarity index 91% rename from src/animation/track.rs rename to fyrox-animation/src/track.rs index 62648401c..13c504e8d 100644 --- a/src/animation/track.rs +++ b/fyrox-animation/src/track.rs @@ -1,13 +1,11 @@ //! Track is responsible in animating a property of a single scene node. See [`Track`] docs for more info. use crate::{ - animation::{ - container::{TrackDataContainer, TrackValueKind}, - value::{BoundValue, ValueBinding}, - }, - core::{pool::Handle, reflect::prelude::*, uuid::Uuid, visitor::prelude::*}, - scene::node::Node, + container::{TrackDataContainer, TrackValueKind}, + core::{reflect::prelude::*, uuid::Uuid, visitor::prelude::*}, + value::{BoundValue, ValueBinding}, }; +use fyrox_core::pool::ErasedHandle; use std::fmt::Debug; /// Track is responsible in animating a property of a single scene node. The track consists up to 4 parametric curves @@ -18,7 +16,7 @@ pub struct Track { binding: ValueBinding, frames: TrackDataContainer, enabled: bool, - target: Handle, + target: ErasedHandle, id: Uuid, } @@ -88,7 +86,7 @@ impl Track { } /// Sets target of the track. - pub fn with_target(mut self, target: Handle) -> Self { + pub fn with_target(mut self, target: ErasedHandle) -> Self { self.target = target; self } @@ -104,12 +102,12 @@ impl Track { } /// Sets a handle of a node that will be animated. - pub fn set_target(&mut self, target: Handle) { - self.target = target; + pub fn set_target>(&mut self, target: H) { + self.target = target.into(); } /// Returns a handle of a node that will be animated. - pub fn target(&self) -> Handle { + pub fn target(&self) -> ErasedHandle { self.target } diff --git a/src/animation/value.rs b/fyrox-animation/src/value.rs similarity index 77% rename from src/animation/value.rs rename to fyrox-animation/src/value.rs index 6ced615ae..d0c4de915 100644 --- a/src/animation/value.rs +++ b/fyrox-animation/src/value.rs @@ -1,16 +1,12 @@ //! A module that contains everything related to numeric values of animation tracks. See [`TrackValue`] docs //! for more info. -use crate::{ - core::{ - algebra::{UnitQuaternion, Vector2, Vector3, Vector4}, - log::Log, - math::lerpf, - num_traits::AsPrimitive, - reflect::{prelude::*, SetFieldByPathError}, - visitor::prelude::*, - }, - scene::node::Node, +use crate::core::{ + algebra::{UnitQuaternion, Vector2, Vector3, Vector4}, + math::lerpf, + num_traits::AsPrimitive, + reflect::prelude::*, + visitor::prelude::*, }; use std::fmt::{Debug, Display, Formatter}; @@ -327,67 +323,4 @@ impl BoundValueCollection { } } } - - /// Tries to set each value from the collection to the respective property (by binding) of the given scene node. - pub 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, - } => { - if let Some(casted) = bound_value.value.numeric_type_cast(value_type) { - let mut casted = Some(casted); - node_ref.as_reflect_mut(&mut |node_ref| { - node_ref.set_field_by_path( - property_name, - casted.take().unwrap(), - &mut |result| { - if let Err(err) = result { - match err { - SetFieldByPathError::InvalidPath { reason, .. } => { - Log::err(format!( - "Failed to set property {}! Invalid path: {}", - property_name, reason - )); - } - SetFieldByPathError::InvalidValue(_) => { - Log::err(format!( - "Failed to set property {}! Types mismatch!", - property_name - )); - } - } - } - }, - ) - }) - } - } - } - } - } } diff --git a/fyrox-core/src/lib.rs b/fyrox-core/src/lib.rs index 561dc134c..15724590d 100644 --- a/fyrox-core/src/lib.rs +++ b/fyrox-core/src/lib.rs @@ -455,6 +455,32 @@ impl Default for PhantomDataSendSync { } } +/// A trait for entities that have name. +pub trait NameProvider { + /// Returns a reference to the name of the entity. + fn name(&self) -> &str; +} + +/// Tries to find an entity by its name in a series of entities produced by an iterator. +pub fn find_by_name_ref<'a, T, I, S, K>(mut iter: I, name: S) -> Option<(K, &'a T)> +where + T: NameProvider, + I: Iterator, + S: AsRef, +{ + iter.find(|(_, value)| value.name() == name.as_ref()) +} + +/// Tries to find an entity by its name in a series of entities produced by an iterator. +pub fn find_by_name_mut<'a, T, I, S, K>(mut iter: I, name: S) -> Option<(K, &'a mut T)> +where + T: NameProvider, + I: Iterator, + S: AsRef, +{ + iter.find(|(_, value)| value.name() == name.as_ref()) +} + #[cfg(test)] mod test { use std::path::Path; diff --git a/src/lib.rs b/src/lib.rs index 8ba3f2a60..38c021295 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ #![allow(clippy::from_over_into)] #![allow(clippy::approx_constant)] -pub mod animation; +pub use fyrox_animation as animation; pub mod engine; pub mod material; pub mod plugin; diff --git a/src/resource/model/mod.rs b/src/resource/model/mod.rs index 899058098..e2826f1cf 100644 --- a/src/resource/model/mod.rs +++ b/src/resource/model/mod.rs @@ -42,6 +42,7 @@ use crate::{ Scene, SceneLoader, }, }; +use fyrox_core::pool::ErasedHandle; use fyrox_core::uuid_provider; use fyrox_resource::io::ResourceIo; use serde::{Deserialize, Serialize}; @@ -223,7 +224,8 @@ impl ModelResourceExtension for ModelResource { // because we've made a plain copy and it has tracks with node handles mapped // to nodes of internal scene. for (i, ref_track) in src_anim.tracks().iter().enumerate() { - let ref_node = &model.scene.graph[ref_track.target()]; + let ref_node = + &model.scene.graph[Handle::::from(ref_track.target())]; let track = &mut anim_copy.tracks_mut()[i]; // Find instantiated node that corresponds to node in resource match graph.find_by_name(root, ref_node.name()) { @@ -232,7 +234,7 @@ impl ModelResourceExtension for ModelResource { track.set_target(instance_node); } None => { - track.set_target(Handle::NONE); + track.set_target(ErasedHandle::default()); Log::writeln( MessageKind::Error, format!( diff --git a/src/scene/animation/absm.rs b/src/scene/animation/absm.rs index d7675105f..4b2f9cfa8 100644 --- a/src/scene/animation/absm.rs +++ b/src/scene/animation/absm.rs @@ -13,7 +13,7 @@ use crate::{ TypeUuidProvider, }, scene::{ - animation::AnimationPlayer, + animation::{AnimationPlayer, AnimationPoseExt}, base::{Base, BaseBuilder}, graph::Graph, node::{Node, NodeTrait, UpdateContext}, diff --git a/src/scene/animation/mod.rs b/src/scene/animation/mod.rs index 5f77e0199..0f1602299 100644 --- a/src/scene/animation/mod.rs +++ b/src/scene/animation/mod.rs @@ -2,8 +2,12 @@ //! See [`AnimationPlayer`] docs for more info. use crate::{ - animation::AnimationContainer, + animation::{ + value::{BoundValueCollection, TrackValue, ValueBinding}, + AnimationContainer, AnimationPose, NodePose, + }, core::{ + log::{Log, MessageKind}, math::aabb::AxisAlignedBoundingBox, pool::Handle, reflect::prelude::*, @@ -14,14 +18,173 @@ use crate::{ }, scene::{ base::{Base, BaseBuilder}, - graph::Graph, + graph::{Graph, NodePool}, node::{Node, NodeTrait, UpdateContext}, }, }; +use fyrox_animation::machine::LayerMask; +use fyrox_core::pool::ErasedHandle; use std::ops::{Deref, DerefMut}; pub mod absm; +/// Extension trait for [`AnimationContainer`]. +pub trait AnimationContainerExt { + /// Updates all animations in the container and applies their poses to respective nodes. This method is intended to + /// be used only by the internals of the engine! + fn update_animations(&mut self, nodes: &mut NodePool, apply: bool, dt: f32); +} + +impl AnimationContainerExt for AnimationContainer { + fn update_animations(&mut self, nodes: &mut NodePool, apply: bool, dt: f32) { + for animation in self.iter_mut().filter(|anim| anim.is_enabled()) { + animation.tick(dt); + if apply { + animation.pose().apply_internal(nodes); + } + } + } +} + +/// Extension trait for [`AnimationPose`]. +pub trait AnimationPoseExt { + /// Tries to set each value to the each property from the animation pose to respective scene nodes. + fn apply_internal(&self, nodes: &mut NodePool); + + /// Tries to set each value to the each property from the animation pose to respective scene nodes. + fn apply(&self, graph: &mut Graph); + + /// Calls given callback function for each node and allows you to apply pose with your own + /// rules. This could be useful if you need to ignore transform some part of pose for a node. + fn apply_with(&self, graph: &mut Graph, callback: C) + where + C: FnMut(&mut Node, Handle, &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 Some(node) = nodes.try_borrow_mut(Handle::from(*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 Some(node) = graph.try_get_mut(Handle::from(*node)) { + local_pose.values.apply(node); + } + } + } + + fn apply_with(&self, graph: &mut Graph, mut callback: C) + where + C: FnMut(&mut Node, Handle, &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 Some(node_ref) = graph.try_get_mut(Handle::from(*node)) { + callback(node_ref, Handle::from(*node), local_pose); + } + } + } +} + +/// Extension trait for [`BoundValueCollection`]. +pub trait BoundValueCollectionExt { + /// Tries to set each value from the collection to the respective property (by binding) of the given scene node. + 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, + } => { + if let Some(casted) = bound_value.value.numeric_type_cast(value_type) { + let mut casted = Some(casted); + node_ref.as_reflect_mut(&mut |node_ref| { + node_ref.set_field_by_path( + property_name, + casted.take().unwrap(), + &mut |result| { + if let Err(err) = result { + match err { + SetFieldByPathError::InvalidPath { reason, .. } => { + Log::err(format!( + "Failed to set property {}! Invalid path: {}", + property_name, reason + )); + } + SetFieldByPathError::InvalidValue(_) => { + Log::err(format!( + "Failed to set property {}! Types mismatch!", + property_name + )); + } + } + } + }, + ) + }) + } + } + } + } + } +} + +/// Extension trait for [`LayerMask`]. +pub trait LayerMaskExt { + /// Creates a layer mask for every descendant node starting from specified `root` (included). It could + /// be useful if you have an entire node hierarchy (for example, lower part of a body) that needs to + /// be filtered out. + fn from_hierarchy(graph: &Graph, root: ErasedHandle) -> Self; +} + +impl LayerMaskExt for LayerMask { + fn from_hierarchy(graph: &Graph, root: ErasedHandle) -> Self { + Self::from( + graph + .traverse_handle_iter(root.into()) + .map(ErasedHandle::from) + .collect::>(), + ) + } +} + /// Animation player is a node that contains multiple animations. It updates and plays all the animations. /// The node could be a source of animations for animation blending state machines. To learn more about /// animations, see [`crate::animation::Animation`] docs. diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 629fa3fa1..5d3f1f160 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -782,32 +782,6 @@ pub fn into_any_arc( } } -/// A trait for entities that have name. -pub trait NameProvider { - /// Returns a reference to the name of the entity. - fn name(&self) -> &str; -} - -/// Tries to find an entity by its name in a series of entities produced by an iterator. -pub fn find_by_name_ref<'a, T, I, S, K>(mut iter: I, name: S) -> Option<(K, &'a T)> -where - T: NameProvider, - I: Iterator, - S: AsRef, -{ - iter.find(|(_, value)| value.name() == name.as_ref()) -} - -/// Tries to find an entity by its name in a series of entities produced by an iterator. -pub fn find_by_name_mut<'a, T, I, S, K>(mut iter: I, name: S) -> Option<(K, &'a mut T)> -where - T: NameProvider, - I: Iterator, - S: AsRef, -{ - iter.find(|(_, value)| value.name() == name.as_ref()) -} - /// Converts `Vector3` -> `Vector3`. pub fn vec3_f16_from_f32(v: Vector3) -> Vector3 { v.map(f16::from_f32) diff --git a/src/utils/navmesh.rs b/src/utils/navmesh.rs index a472e4030..bacc089e2 100644 --- a/src/utils/navmesh.rs +++ b/src/utils/navmesh.rs @@ -965,7 +965,7 @@ mod test { #[test] fn test_navmesh() { - let mut navmesh = Navmesh::new( + let navmesh = Navmesh::new( vec![ TriangleDefinition([0, 1, 3]), TriangleDefinition([1, 2, 3]), @@ -989,7 +989,7 @@ mod test { let mut agent = NavmeshAgent::new(); agent.set_target(Vector3::new(3.0, 0.0, 1.0)); - agent.update(1.0 / 60.0, &mut navmesh).unwrap(); + agent.update(1.0 / 60.0, &navmesh).unwrap(); let graph = &navmesh.graph;