mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
moved low level animation modules into fyrox-animation crate
This commit is contained in:
Generated
+1
@@ -31,6 +31,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/editor-standalone/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/template/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/fyrox-scripts/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/fyrox-animation/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/examples/wasm/target" />
|
||||
</content>
|
||||
|
||||
+2
-1
@@ -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"
|
||||
|
||||
@@ -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::<Node>::from(track.target()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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::<Vec<_>>();
|
||||
|
||||
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::<Vec<_>>();
|
||||
let selection =
|
||||
layer.mask().inner().iter().cloned().collect::<Vec<_>>();
|
||||
|
||||
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::<Node>::from(*h))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
let new_mask = LayerMask::from(mask_selection.clone());
|
||||
sender.do_scene_command(SetLayerMaskCommand {
|
||||
absm_node_handle: selection.absm_node_handle,
|
||||
layer_index,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ impl AnimationEditor {
|
||||
let animation_targets = animation
|
||||
.tracks()
|
||||
.iter()
|
||||
.map(|t| t.target())
|
||||
.map(|t| Handle::<Node>::from(t.target()))
|
||||
.collect::<FxHashSet<_>>();
|
||||
|
||||
self.enter_preview_mode(
|
||||
|
||||
@@ -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("<Unassigned>")),
|
||||
),
|
||||
|
||||
@@ -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::<TrackView>().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(
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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<Node>) -> 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<Node>,
|
||||
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<Node>, 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<Node>, 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<Node>, 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<Node>) -> impl Iterator<Item = &Track> {
|
||||
pub fn tracks_of(&self, handle: ErasedHandle) -> impl Iterator<Item = &Track> {
|
||||
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<Node>) -> impl Iterator<Item = &mut Track> {
|
||||
pub fn tracks_of_mut(&mut self, handle: ErasedHandle) -> impl Iterator<Item = &mut Track> {
|
||||
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>, &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<Animation>, &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
|
||||
@@ -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;
|
||||
|
||||
@@ -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>, &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<Transition>, &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>, &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<State>, &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.
|
||||
@@ -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<Handle<Node>>,
|
||||
excluded_bones: Vec<ErasedHandle>,
|
||||
}
|
||||
|
||||
impl From<Vec<Handle<Node>>> for LayerMask {
|
||||
fn from(mut excluded_bones: Vec<Handle<Node>>) -> Self {
|
||||
impl From<Vec<ErasedHandle>> for LayerMask {
|
||||
fn from(mut excluded_bones: Vec<ErasedHandle>) -> 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<Node>) -> Self {
|
||||
Self::from(graph.traverse_handle_iter(root).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
/// 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<Node>) {
|
||||
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<Node>) {
|
||||
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<Node>) -> Option<usize> {
|
||||
fn index_of(&self, node: ErasedHandle) -> Option<usize> {
|
||||
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<Node>) -> 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<Node>) -> 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<Handle<Node>> {
|
||||
pub fn inner(&self) -> &Vec<ErasedHandle> {
|
||||
&self.excluded_bones
|
||||
}
|
||||
|
||||
/// Converts the mask into inner container.
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> Vec<Handle<Node>> {
|
||||
pub fn into_inner(self) -> Vec<ErasedHandle> {
|
||||
self.excluded_bones
|
||||
}
|
||||
}
|
||||
@@ -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<S: AsRef<str>>(&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.
|
||||
@@ -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;
|
||||
+6
-9
@@ -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]
|
||||
@@ -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,
|
||||
@@ -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},
|
||||
@@ -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},
|
||||
@@ -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,
|
||||
/// };
|
||||
@@ -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<Node>,
|
||||
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<Handle<Node>, NodePose>,
|
||||
poses: FxHashMap<ErasedHandle, NodePose>,
|
||||
root_motion: Option<RootMotion>,
|
||||
}
|
||||
|
||||
@@ -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<Node>, 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<Handle<Node>, NodePose> {
|
||||
pub fn poses(&self) -> &FxHashMap<ErasedHandle, NodePose> {
|
||||
&self.poses
|
||||
}
|
||||
|
||||
/// Returns a reference to inner node pose map.
|
||||
pub fn poses_mut(&mut self) -> &mut FxHashMap<Handle<Node>, NodePose> {
|
||||
pub fn poses_mut(&mut self) -> &mut FxHashMap<ErasedHandle, NodePose> {
|
||||
&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<C>(&self, graph: &mut Graph, mut callback: C)
|
||||
where
|
||||
C: FnMut(&mut Node, Handle<Node>, &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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)]
|
||||
@@ -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<u32>,
|
||||
frames: Vec<Vector2<u32>>,
|
||||
#[visit(optional)]
|
||||
texture: Option<TextureResource>,
|
||||
texture: Option<UntypedResource>,
|
||||
}
|
||||
|
||||
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<TextureResource> {
|
||||
pub fn texture(&self) -> Option<UntypedResource> {
|
||||
self.texture.clone()
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ pub struct SpriteSheetAnimation {
|
||||
signals: Vec<Signal>,
|
||||
#[visit(optional)]
|
||||
#[reflect(setter = "set_texture")]
|
||||
texture: Option<TextureResource>,
|
||||
texture: Option<UntypedResource>,
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
events: VecDeque<Event>,
|
||||
@@ -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<TextureResource>) -> Option<TextureResource> {
|
||||
pub fn set_texture(&mut self, texture: Option<UntypedResource>) -> Option<UntypedResource> {
|
||||
self.frames_container.texture = texture.clone();
|
||||
std::mem::replace(&mut self.texture, texture)
|
||||
}
|
||||
|
||||
/// Returns current texture of the animation.
|
||||
pub fn texture(&self) -> Option<TextureResource> {
|
||||
pub fn texture(&self) -> Option<UntypedResource> {
|
||||
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;
|
||||
@@ -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<Node>,
|
||||
target: ErasedHandle,
|
||||
id: Uuid,
|
||||
}
|
||||
|
||||
@@ -88,7 +86,7 @@ impl Track {
|
||||
}
|
||||
|
||||
/// Sets target of the track.
|
||||
pub fn with_target(mut self, target: Handle<Node>) -> 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<Node>) {
|
||||
self.target = target;
|
||||
pub fn set_target<H: Into<ErasedHandle>>(&mut self, target: H) {
|
||||
self.target = target.into();
|
||||
}
|
||||
|
||||
/// Returns a handle of a node that will be animated.
|
||||
pub fn target(&self) -> Handle<Node> {
|
||||
pub fn target(&self) -> ErasedHandle {
|
||||
self.target
|
||||
}
|
||||
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,6 +455,32 @@ impl<T: ?Sized> Default for PhantomDataSendSync<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Item = (K, &'a T)>,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
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<Item = (K, &'a mut T)>,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
iter.find(|(_, value)| value.name() == name.as_ref())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::Path;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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::<Node>::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!(
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::{
|
||||
TypeUuidProvider,
|
||||
},
|
||||
scene::{
|
||||
animation::AnimationPlayer,
|
||||
animation::{AnimationPlayer, AnimationPoseExt},
|
||||
base::{Base, BaseBuilder},
|
||||
graph::Graph,
|
||||
node::{Node, NodeTrait, UpdateContext},
|
||||
|
||||
+165
-2
@@ -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<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 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<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 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::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
||||
@@ -782,32 +782,6 @@ pub fn into_any_arc<T: Any + Send + Sync>(
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Item = (K, &'a T)>,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
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<Item = (K, &'a mut T)>,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
iter.find(|(_, value)| value.name() == name.as_ref())
|
||||
}
|
||||
|
||||
/// Converts `Vector3<f32>` -> `Vector3<f16>`.
|
||||
pub fn vec3_f16_from_f32(v: Vector3<f32>) -> Vector3<f16> {
|
||||
v.map(f16::from_f32)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user