fyrox_animation/machine/
transition.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Transition is a connection between two states with a rule that defines possibility of actual transition with blending.
22
23use crate::{
24    core::{pool::Handle, reflect::prelude::*, visitor::prelude::*},
25    machine::{Parameter, ParameterContainer, State},
26    Animation, AnimationContainer, EntityId,
27};
28use fyrox_core::uuid::{uuid, Uuid};
29use fyrox_core::{NameProvider, TypeUuidProvider};
30use std::any::{type_name, Any, TypeId};
31use strum_macros::{AsRefStr, EnumString, VariantNames};
32
33macro_rules! define_two_args_node {
34    ($(#[$meta:meta])* $name:ident) => {
35        $(#[$meta])*
36        #[derive(Debug, Clone, PartialEq)]
37        pub struct $name <T:EntityId> {
38            /// Left argument.
39            pub lhs: Box<LogicNode<T>>,
40            /// Right argument.
41            pub rhs: Box<LogicNode<T>>,
42        }
43
44        impl<T:EntityId> Default for $name<T> {
45            fn default() -> Self {
46                Self {
47                    lhs: Box::new(LogicNode::Parameter(Default::default())),
48                    rhs: Box::new(LogicNode::Parameter(Default::default())),
49                }
50            }
51        }
52
53        impl<T:EntityId> Visit for $name<T> {
54            fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
55                let mut guard = visitor.enter_region(name)?;
56
57                self.lhs.visit("Lhs", &mut guard)?;
58                self.rhs.visit("Rhs", &mut guard)?;
59
60                Ok(())
61            }
62        }
63
64        impl<T:EntityId> Reflect for $name<T> {
65            fn source_path() -> &'static str {
66                file!()
67            }
68
69            fn type_name(&self) -> &'static str {
70                type_name::<Self>()
71            }
72
73            fn doc(&self) -> &'static str {
74                ""
75            }
76
77            fn assembly_name(&self) -> &'static str {
78                env!("CARGO_PKG_NAME")
79            }
80
81            fn type_assembly_name() -> &'static str {
82                env!("CARGO_PKG_NAME")
83            }
84
85            fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) {
86                func(&[
87                    FieldInfo {
88                        owner_type_id: TypeId::of::<Self>(),
89                        name: "Lhs",
90                        display_name: "Lhs",
91                        description: "",
92                        tag: "",
93                        type_name: type_name::<Self>(),
94                        value: &*self.lhs,
95                        reflect_value: &*self.lhs,
96                        read_only: false,
97                        immutable_collection: false,
98                        min_value: None,
99                        max_value: None,
100                        step: None,
101                        precision: None,
102                        doc: "",
103                    },
104                    FieldInfo {
105                        owner_type_id: TypeId::of::<Self>(),
106                        name: "Rhs",
107                        display_name: "Rhs",
108                        description: "",
109                        tag: "",
110                        type_name: type_name::<Self>(),
111                        value: &*self.rhs,
112                        reflect_value: &*self.rhs,
113                        read_only: false,
114                        immutable_collection: false,
115                        min_value: None,
116                        max_value: None,
117                        step: None,
118                        precision: None,doc: "",
119                    },
120                ])
121            }
122
123            fn into_any(self: Box<Self>) -> Box<dyn Any> {
124                self
125            }
126
127            fn as_any(&self, func: &mut dyn FnMut(&dyn ::core::any::Any)) {
128                func(self)
129            }
130
131            fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn ::core::any::Any)) {
132                func(self)
133            }
134
135            fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
136                func(self)
137            }
138
139            fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
140                func(self)
141            }
142
143            fn set(
144                &mut self,
145                value: Box<dyn Reflect>,
146            ) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
147                let this = std::mem::replace(self, value.take()?);
148                Ok(Box::new(this))
149            }
150
151            fn fields(&self, func: &mut dyn FnMut(&[&dyn Reflect])) {
152                func(&[&self.lhs, &self.rhs])
153            }
154
155           fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [&mut dyn Reflect])) {
156                func(&mut [&mut self.lhs, &mut self.rhs])
157            }
158
159            fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
160                func(match name {
161                    "Lhs" => Some(&self.lhs),
162                    "Rhs" => Some(&self.rhs),
163                    _ => None,
164                })
165            }
166
167            fn field_mut(
168                &mut self,
169                name: &str,
170                func: &mut dyn FnMut(Option<&mut dyn Reflect>),
171            ) {
172                func(match name {
173                    "Lhs" => Some(&mut self.lhs),
174                    "Rhs" => Some(&mut self.rhs),
175                    _ => None,
176                })
177            }
178        }
179    };
180}
181
182define_two_args_node!(
183    /// Calculates logical AND between two arguments. Output value will be `true` iff both of the arguments is `true`.
184    AndNode
185);
186define_two_args_node!(
187    /// Calculates logical OR between two arguments. Output value will be `true` iff any of the arguments is `true`.
188    OrNode
189);
190define_two_args_node!(
191    /// Calculates logical XOR (excluding OR) between two arguments. Output value will be `true` iff the arguments differ.
192    XorNode
193);
194
195/// Calculates logical NOT of an argument. Output value will be `true` if the value of the argument is `false`.
196#[derive(Debug, Clone, PartialEq)]
197pub struct NotNode<T: EntityId> {
198    /// Argument to be negated.
199    pub lhs: Box<LogicNode<T>>,
200}
201
202impl<T: EntityId> Default for NotNode<T> {
203    fn default() -> Self {
204        Self {
205            lhs: Box::new(LogicNode::Parameter(Default::default())),
206        }
207    }
208}
209
210impl<T: EntityId> Visit for NotNode<T> {
211    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
212        let mut guard = visitor.enter_region(name)?;
213
214        self.lhs.visit("Lhs", &mut guard)?;
215
216        Ok(())
217    }
218}
219
220impl<T: EntityId> Reflect for NotNode<T> {
221    fn source_path() -> &'static str {
222        file!()
223    }
224
225    fn type_name(&self) -> &'static str {
226        type_name::<Self>()
227    }
228
229    fn doc(&self) -> &'static str {
230        ""
231    }
232
233    fn assembly_name(&self) -> &'static str {
234        env!("CARGO_PKG_NAME")
235    }
236
237    fn type_assembly_name() -> &'static str {
238        env!("CARGO_PKG_NAME")
239    }
240
241    fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) {
242        func(&[FieldInfo {
243            owner_type_id: TypeId::of::<Self>(),
244            name: "Lhs",
245            display_name: "Lhs",
246            description: "",
247            tag: "",
248            type_name: type_name::<Self>(),
249            value: &*self.lhs,
250            reflect_value: &*self.lhs,
251            read_only: false,
252            immutable_collection: false,
253            min_value: None,
254            max_value: None,
255            step: None,
256            precision: None,
257            doc: "",
258        }])
259    }
260
261    fn into_any(self: Box<Self>) -> Box<dyn Any> {
262        self
263    }
264
265    fn as_any(&self, func: &mut dyn FnMut(&dyn ::core::any::Any)) {
266        func(self)
267    }
268
269    fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn ::core::any::Any)) {
270        func(self)
271    }
272
273    fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
274        func(self)
275    }
276
277    fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
278        func(self)
279    }
280
281    fn set(&mut self, value: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
282        let this = std::mem::replace(self, value.take()?);
283        Ok(Box::new(this))
284    }
285
286    fn fields(&self, func: &mut dyn FnMut(&[&dyn Reflect])) {
287        func(&[&self.lhs])
288    }
289
290    fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [&mut dyn Reflect])) {
291        func(&mut [&mut self.lhs])
292    }
293
294    fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
295        func(match name {
296            "Lhs" => Some(&self.lhs),
297            _ => None,
298        })
299    }
300
301    fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) {
302        func(match name {
303            "Lhs" => Some(&mut self.lhs),
304            _ => None,
305        })
306    }
307}
308
309/// A node responsible for logical operations evaluation. It can have any number of descendant nodes.
310///
311/// # Examples
312///
313/// ```rust
314/// use fyrox_animation::AnimationContainer;
315/// use fyrox_animation::machine::{
316///     transition::{AndNode, LogicNode, NotNode},
317///     Parameter, ParameterContainer,
318/// };
319/// use fyrox_core::pool::ErasedHandle;
320///
321/// let mut parameters = ParameterContainer::default();
322/// parameters.add("Run", Parameter::Rule(false));
323/// parameters.add("Jump", Parameter::Rule(true));
324///
325/// // !Run && Jump
326/// let transition_logic = LogicNode::<ErasedHandle>::And(AndNode {
327///     lhs: Box::new(LogicNode::Not(NotNode {
328///         lhs: Box::new(LogicNode::Parameter("Run".to_string())),
329///     })),
330///     rhs: Box::new(LogicNode::Parameter("Jump".to_string())),
331/// });
332///
333/// assert_eq!(transition_logic.calculate_value(&parameters, &AnimationContainer::default()), true);
334/// ```
335#[derive(Debug, Visit, Clone, Reflect, PartialEq, AsRefStr, EnumString, VariantNames)]
336pub enum LogicNode<T: EntityId> {
337    /// Fetches a value of `Rule` parameter and returns its value. `false` if the parameter is not found.
338    Parameter(String),
339    /// Calculates logical AND between two arguments. Output value will be `true` iff both of the arguments is `true`.
340    And(AndNode<T>),
341    /// Calculates logical OR between two arguments. Output value will be `true` iff any of the arguments is `true`.
342    Or(OrNode<T>),
343    /// Calculates logical XOR (excluding OR) between two arguments. Output value will be `true` iff the arguments differ.
344    Xor(XorNode<T>),
345    /// Calculates logical NOT of an argument. Output value will be `true` if the value of the argument is `false`.
346    Not(NotNode<T>),
347    /// Returns `true` if the animation has ended, `false` - otherwise.
348    IsAnimationEnded(Handle<Animation<T>>),
349}
350
351impl<T: EntityId> TypeUuidProvider for LogicNode<T> {
352    fn type_uuid() -> Uuid {
353        uuid!("98a5b767-5560-4ed7-ad40-1625a8868e39")
354    }
355}
356
357impl<T: EntityId> Default for LogicNode<T> {
358    fn default() -> Self {
359        Self::Parameter(Default::default())
360    }
361}
362
363impl<T: EntityId> LogicNode<T> {
364    /// Calculates final value of the logic node.
365    pub fn calculate_value(
366        &self,
367        parameters: &ParameterContainer,
368        animations: &AnimationContainer<T>,
369    ) -> bool {
370        match self {
371            LogicNode::Parameter(rule_name) => parameters.get(rule_name).is_some_and(|p| {
372                if let Parameter::Rule(rule_value) = p {
373                    *rule_value
374                } else {
375                    false
376                }
377            }),
378            LogicNode::And(and) => {
379                let lhs_value = and.lhs.calculate_value(parameters, animations);
380                let rhs_value = and.rhs.calculate_value(parameters, animations);
381                lhs_value & rhs_value
382            }
383            LogicNode::Or(or) => {
384                let lhs_value = or.lhs.calculate_value(parameters, animations);
385                let rhs_value = or.rhs.calculate_value(parameters, animations);
386                lhs_value | rhs_value
387            }
388            LogicNode::Xor(or) => {
389                let lhs_value = or.lhs.calculate_value(parameters, animations);
390                let rhs_value = or.rhs.calculate_value(parameters, animations);
391                lhs_value ^ rhs_value
392            }
393            LogicNode::Not(node) => !node.lhs.calculate_value(parameters, animations),
394            LogicNode::IsAnimationEnded(animation) => animations
395                .try_get(*animation)
396                .map_or(true, |a| a.has_ended()),
397        }
398    }
399}
400
401/// Transition is a connection between two states with a rule that defines possibility of actual transition with blending.
402#[derive(Default, Debug, Clone, Reflect, PartialEq)]
403pub struct Transition<T: EntityId> {
404    /// The name of the transition, it is used for debug output.
405    #[reflect(description = "The name of the transition, it is used for debug output.")]
406    pub(crate) name: String,
407
408    /// Total amount of time to transition from `src` to `dst` state.
409    #[reflect(description = "Total amount of time (in seconds) to transition \
410        from source to destination state")]
411    pub(crate) transition_time: f32,
412
413    pub(crate) elapsed_time: f32,
414
415    #[reflect(read_only)]
416    pub(crate) source: Handle<State<T>>,
417
418    #[reflect(read_only)]
419    pub(crate) dest: Handle<State<T>>,
420
421    #[reflect(
422        description = "Computational graph that can use any amount of Rule parameters to calculate transition value."
423    )]
424    pub(crate) condition: LogicNode<T>,
425
426    /// 0 - evaluates `src` pose, 1 - `dest`, 0..1 - blends `src` and `dest`
427    pub(crate) blend_factor: f32,
428}
429
430impl<T: EntityId> Visit for Transition<T> {
431    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
432        let mut guard = visitor.enter_region(name)?;
433
434        self.name.visit("Name", &mut guard)?;
435        self.transition_time.visit("TransitionTime", &mut guard)?;
436        self.source.visit("Source", &mut guard)?;
437        self.dest.visit("Dest", &mut guard)?;
438        self.blend_factor.visit("BlendFactor", &mut guard)?;
439
440        if guard.is_reading() {
441            if self.condition.visit("Condition", &mut guard).is_err() {
442                // Try to convert the old version.
443                let mut invert_rule = false;
444                let mut rule: String = Default::default();
445
446                invert_rule.visit("InvertRule", &mut guard)?;
447                rule.visit("Rule", &mut guard)?;
448
449                if invert_rule {
450                    self.condition = LogicNode::Not(NotNode {
451                        lhs: Box::new(LogicNode::Parameter(rule)),
452                    });
453                } else {
454                    self.condition = LogicNode::Parameter(rule);
455                }
456            }
457        } else {
458            self.condition.visit("Condition", &mut guard)?;
459        }
460
461        Ok(())
462    }
463}
464
465impl<T: EntityId> NameProvider for Transition<T> {
466    fn name(&self) -> &str {
467        &self.name
468    }
469}
470
471impl<T: EntityId> Transition<T> {
472    /// Creates a new named transition between two states with a given time and a name of a parameter that
473    /// will be used to check if it is possible to activate the transition.
474    pub fn new(
475        name: &str,
476        src: Handle<State<T>>,
477        dest: Handle<State<T>>,
478        time: f32,
479        rule: &str,
480    ) -> Transition<T> {
481        Self {
482            name: name.to_owned(),
483            transition_time: time,
484            elapsed_time: 0.0,
485            source: src,
486            dest,
487            blend_factor: 0.0,
488            condition: LogicNode::Parameter(rule.to_owned()),
489        }
490    }
491
492    /// Returns a reference to the name of the transition.
493    #[inline]
494    pub fn name(&self) -> &str {
495        self.name.as_str()
496    }
497
498    /// Returns the amount of time required to perform a transition from source to destination state, in seconds.
499    #[inline]
500    pub fn transition_time(&self) -> f32 {
501        self.transition_time
502    }
503
504    /// Returns a handle to source state.
505    #[inline]
506    pub fn source(&self) -> Handle<State<T>> {
507        self.source
508    }
509
510    /// Returns a handle to destination state.
511    #[inline]
512    pub fn dest(&self) -> Handle<State<T>> {
513        self.dest
514    }
515
516    /// Sets new condition for the transition.
517    pub fn set_condition(&mut self, condition: LogicNode<T>) {
518        self.condition = condition;
519    }
520
521    /// Returns a reference to the current condition of the transition.
522    pub fn condition(&self) -> &LogicNode<T> {
523        &self.condition
524    }
525
526    /// Returns true if the transition from the source to the destination state was finished.
527    #[inline]
528    pub fn is_done(&self) -> bool {
529        (self.transition_time - self.elapsed_time).abs() <= f32::EPSILON
530    }
531
532    /// Returns current blend factor. 0 - evaluates `source` pose, 1 - `destination`, 0..1 - blends `source` and `destination`.
533    #[inline]
534    pub fn blend_factor(&self) -> f32 {
535        self.blend_factor
536    }
537
538    pub(super) fn reset(&mut self) {
539        self.elapsed_time = 0.0;
540        self.blend_factor = 0.0;
541    }
542
543    pub(super) fn update(&mut self, dt: f32) {
544        self.elapsed_time += dt;
545        if self.elapsed_time > self.transition_time {
546            self.elapsed_time = self.transition_time;
547        }
548        self.blend_factor = self.elapsed_time / self.transition_time;
549    }
550}