Overte C++ Documentation
AnimRandomSwitch.h
1 //
2 // AnimRandomSwitch.h
3 //
4 // Created by Angus Antley on 4/8/19.
5 // Copyright (c) 2019 High Fidelity, Inc. All rights reserved.
6 //
7 // Distributed under the Apache License, Version 2.0.
8 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
9 //
10 
11 #ifndef hifi_AnimRandomSwitch_h
12 #define hifi_AnimRandomSwitch_h
13 
14 #include <string>
15 #include <vector>
16 #include "AnimNode.h"
17 #include "AnimUtil.h"
18 
19 // Random Switch State Machine for random transitioning between children AnimNodes
20 //
21 // This is mechanisim for choosing and playing a random animation and smoothly interpolating/fading
22 // between them. A RandomSwitch has a set of States, which typically reference
23 // child AnimNodes. Each Random Switch State has a list of Transitions, which are evaluated
24 // to determine when we should switch to a new State. Parameters for the smooth
25 // interpolation/fading are read from the Random Switch State that you are transitioning to.
26 //
27 // The currentState can be set directly via the setCurrentStateVar() and will override
28 // any State transitions.
29 //
30 // Each Random Switch State has two parameters that can be changed via AnimVars,
31 // * interpTarget - (frames) The destination frame of the interpolation. i.e. the first frame of the animation that will
32 // visible after interpolation is complete.
33 // * interpDuration - (frames) The total length of time it will take to interp between the current pose and the
34 // interpTarget frame.
35 // * interpType - How the interpolation is performed.
36 // * priority - this number represents how likely this Random Switch State will be chosen.
37 // the priority for each Random Switch State will be normalized, so their relative size is what is important
38 // * resume - if resume is false then if this state is chosen twice in a row it will remember what frame it was playing on.
39 // * SnapshotBoth: Stores two snapshots, the previous animation before interpolation begins and the target state at the
40 // interTarget frame. Then during the interpolation period the two snapshots are interpolated to produce smooth motion between them.
41 // * SnapshotPrev: Stores a snapshot of the previous animation before interpolation begins. However the target state is
42 // evaluated dynamically. During the interpolation period the previous snapshot is interpolated with the target pose
43 // to produce smooth motion between them. This mode is useful for interping into a blended animation where the actual
44 // blend factor is not known at the start of the interp or is might change dramatically during the interp.
45 //
46 
47 class AnimRandomSwitch : public AnimNode {
48 public:
49  friend class AnimNodeLoader;
50  friend bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& nodeId, const QUrl& jsonUrl);
51 
52  enum class InterpType {
53  SnapshotBoth = 0,
54  SnapshotPrev,
55  EvaluateBoth,
56  NumTypes
57  };
58 
59 protected:
60 
61  class RandomSwitchState {
62  public:
63  friend AnimRandomSwitch;
64  friend bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& nodeId, const QUrl& jsonUrl);
65 
66  using Pointer = std::shared_ptr<RandomSwitchState>;
67  using ConstPointer = std::shared_ptr<const RandomSwitchState>;
68 
69  class Transition {
70  public:
71  friend AnimRandomSwitch;
72  Transition(const QString& var, RandomSwitchState::Pointer randomState) : _var(var), _randomSwitchState(randomState) {}
73  protected:
74  QString _var;
75  RandomSwitchState::Pointer _randomSwitchState;
76  };
77 
78  RandomSwitchState(const QString& id, int childIndex, float interpTarget, float interpDuration, InterpType interpType, EasingType easingType, float priority, bool resume) :
79  _id(id),
80  _childIndex(childIndex),
81  _interpTarget(interpTarget),
82  _interpDuration(interpDuration),
83  _interpType(interpType),
84  _easingType(easingType),
85  _priority(priority),
86  _resume(resume){
87  }
88 
89  void setInterpTargetVar(const QString& interpTargetVar) { _interpTargetVar = interpTargetVar; }
90  void setInterpDurationVar(const QString& interpDurationVar) { _interpDurationVar = interpDurationVar; }
91  void setInterpTypeVar(const QString& interpTypeVar) { _interpTypeVar = interpTypeVar; }
92 
93  int getChildIndex() const { return _childIndex; }
94  float getPriority() const { return _priority; }
95  bool getResume() const { return _resume; }
96  const QString& getID() const { return _id; }
97 
98  protected:
99 
100  void setInterpTarget(float interpTarget) { _interpTarget = interpTarget; }
101  void setInterpDuration(float interpDuration) { _interpDuration = interpDuration; }
102  void setPriority(float priority) { _priority = priority; }
103  void setResumeFlag(bool resume) { _resume = resume; }
104 
105  void addTransition(const Transition& transition) { _transitions.push_back(transition); }
106 
107  QString _id;
108  int _childIndex;
109  float _interpTarget; // frames
110  float _interpDuration; // frames
111  InterpType _interpType;
112  EasingType _easingType;
113  float _priority {0.0f};
114  bool _resume {false};
115 
116  QString _interpTargetVar;
117  QString _interpDurationVar;
118  QString _interpTypeVar;
119 
120  std::vector<Transition> _transitions;
121 
122  private:
123  Q_DISABLE_COPY(RandomSwitchState)
124  };
125 
126 public:
127 
128  explicit AnimRandomSwitch(const QString& id);
129  virtual ~AnimRandomSwitch() override;
130 
131  virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
132 
133  void setCurrentStateVar(QString& currentStateVar) { _currentStateVar = currentStateVar; }
134 
135 protected:
136 
137  void setCurrentState(RandomSwitchState::Pointer randomState);
138  void setTriggerRandomSwitchVar(const QString& triggerRandomSwitchVar) { _triggerRandomSwitchVar = triggerRandomSwitchVar; }
139  void setRandomSwitchTimeMin(float randomSwitchTimeMin) { _randomSwitchTimeMin = randomSwitchTimeMin; }
140  void setRandomSwitchTimeMax(float randomSwitchTimeMax) { _randomSwitchTimeMax = randomSwitchTimeMax; }
141  void setTransitionVar(const QString& transitionVar) { _transitionVar = transitionVar; }
142  void setTriggerTimeMin(float triggerTimeMin) { _triggerTimeMin = triggerTimeMin; }
143  void setTriggerTimeMax(float triggerTimeMax) { _triggerTimeMax = triggerTimeMax; }
144 
145  void addState(RandomSwitchState::Pointer randomState);
146 
147  void switchRandomState(const AnimVariantMap& animVars, const AnimContext& context, RandomSwitchState::Pointer desiredState, bool shouldInterp);
148  RandomSwitchState::Pointer evaluateTransitions(const AnimVariantMap& animVars) const;
149 
150  // for AnimDebugDraw rendering
151  virtual const AnimPoseVec& getPosesInternal() const override;
152  virtual void setActiveInternal(bool active) override;
153 
154  AnimPoseVec _poses;
155 
156  bool _triggerNewRandomState = false;
157  // interpolation state
158  bool _duringInterp = false;
159  InterpType _interpType { InterpType::SnapshotPrev };
160  EasingType _easingType { EasingType_Linear };
161  float _alphaVel = 0.0f;
162  float _alpha = 0.0f;
163  AnimPoseVec _prevPoses;
164  AnimPoseVec _nextPoses;
165 
166  RandomSwitchState::Pointer _currentState;
167  RandomSwitchState::Pointer _previousState;
168  std::vector<RandomSwitchState::Pointer> _randomStates;
169 
170  QString _currentStateVar;
171  QString _triggerRandomSwitchVar;
172  QString _transitionVar;
173  float _triggerTimeMin { 10.0f };
174  float _triggerTimeMax { 20.0f };
175  float _triggerTime { 0.0f };
176  float _randomSwitchTimeMin { 10.0f };
177  float _randomSwitchTimeMax { 20.0f };
178  float _randomSwitchTime { 0.0f };
179  QString _lastPlayedState;
180 
181 private:
182  Q_DISABLE_COPY(AnimRandomSwitch)
183 };
184 
185 #endif // hifi_AnimRandomSwitch_h