Overte C++ Documentation
AnimStateMachine.h
1 //
2 // AnimStateMachine.h
3 //
4 // Created by Anthony J. Thibault on 9/2/15.
5 // Copyright (c) 2015 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_AnimStateMachine_h
12 #define hifi_AnimStateMachine_h
13 
14 #include <string>
15 #include <vector>
16 #include "AnimNode.h"
17 #include "AnimUtil.h"
18 
19 // State Machine for transitioning between children AnimNodes
20 //
21 // This is mechinisim for playing animations and smoothly interpolating/fading
22 // between them. A StateMachine has a set of States, which typically reference
23 // child AnimNodes. Each 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 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 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 // * SnapshotBoth: Stores two snapshots, the previous animation before interpolation begins and the target state at the
37 // interTarget frame. Then during the interpolation period the two snapshots are interpolated to produce smooth motion between them.
38 // * SnapshotPrev: Stores a snapshot of the previous animation before interpolation begins. However the target state is
39 // evaluated dynamically. During the interpolation period the previous snapshot is interpolated with the target pose
40 // to produce smooth motion between them. This mode is useful for interping into a blended animation where the actual
41 // blend factor is not known at the start of the interp or is might change dramatically during the interp.
42 
43 class AnimStateMachine : public AnimNode {
44 public:
45  friend class AnimNodeLoader;
46  friend bool processStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& nodeId, const QUrl& jsonUrl);
47 
48  enum class InterpType {
49  SnapshotBoth = 0,
50  SnapshotPrev,
51  EvaluateBoth,
52  NumTypes
53  };
54 
55 protected:
56 
57  class State {
58  public:
59  friend AnimStateMachine;
60  friend bool processStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& nodeId, const QUrl& jsonUrl);
61 
62  using Pointer = std::shared_ptr<State>;
63  using ConstPointer = std::shared_ptr<const State>;
64 
65  class Transition {
66  public:
67  friend AnimStateMachine;
68  Transition(const QString& var, State::Pointer state) : _var(var), _state(state) {}
69  protected:
70  QString _var;
71  State::Pointer _state;
72  };
73 
74  State(const QString& id, int childIndex, float interpTarget, float interpDuration, InterpType interpType, EasingType easingType) :
75  _id(id),
76  _childIndex(childIndex),
77  _interpTarget(interpTarget),
78  _interpDuration(interpDuration),
79  _interpType(interpType),
80  _easingType(easingType) {}
81 
82  void setInterpTargetVar(const QString& interpTargetVar) { _interpTargetVar = interpTargetVar; }
83  void setInterpDurationVar(const QString& interpDurationVar) { _interpDurationVar = interpDurationVar; }
84  void setInterpTypeVar(const QString& interpTypeVar) { _interpTypeVar = interpTypeVar; }
85 
86  int getChildIndex() const { return _childIndex; }
87  const QString& getID() const { return _id; }
88 
89  protected:
90 
91  void setInterpTarget(float interpTarget) { _interpTarget = interpTarget; }
92  void setInterpDuration(float interpDuration) { _interpDuration = interpDuration; }
93 
94  void addTransition(const Transition& transition) { _transitions.push_back(transition); }
95 
96  QString _id;
97  int _childIndex;
98  float _interpTarget; // frames
99  float _interpDuration; // frames
100  InterpType _interpType;
101  EasingType _easingType;
102 
103  QString _interpTargetVar;
104  QString _interpDurationVar;
105  QString _interpTypeVar;
106 
107  std::vector<Transition> _transitions;
108 
109  private:
110  Q_DISABLE_COPY(State)
111  };
112 
113 public:
114 
115  explicit AnimStateMachine(const QString& id);
116  virtual ~AnimStateMachine() override;
117 
118  virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
119 
120  void setCurrentStateVar(QString& currentStateVar) { _currentStateVar = currentStateVar; }
121  const QString& getCurrentStateID() const;
122 
123 protected:
124 
125  void setCurrentState(State::Pointer state);
126 
127  void addState(State::Pointer state);
128 
129  void switchState(const AnimVariantMap& animVars, const AnimContext& context, State::Pointer desiredState);
130  State::Pointer evaluateTransitions(const AnimVariantMap& animVars) const;
131 
132  // for AnimDebugDraw rendering
133  virtual const AnimPoseVec& getPosesInternal() const override;
134 
135  AnimPoseVec _poses;
136 
137  // interpolation state
138  bool _duringInterp = false;
139  InterpType _interpType { InterpType::SnapshotPrev };
140  EasingType _easingType { EasingType_Linear };
141  float _alphaVel = 0.0f;
142  float _alpha = 0.0f;
143  AnimPoseVec _prevPoses;
144  AnimPoseVec _nextPoses;
145 
146  State::Pointer _currentState;
147  State::Pointer _previousState;
148  std::vector<State::Pointer> _states;
149 
150  QString _currentStateVar;
151 
152 private:
153  Q_DISABLE_COPY(AnimStateMachine)
154 };
155 
156 #endif // hifi_AnimStateMachine_h