1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
#pragma once
#include <vector>
#include "Runtime/BaseClasses/BaseObject.h"
#include "Runtime/BaseClasses/RefCounted.h"
#include "Runtime/Utilities/LinkedList.h"
#include "Runtime/Geometry/AABB.h"
#include "Runtime/Math/AnimationCurve.h"
template<class T> class AnimationCurveTpl; typedef AnimationCurveTpl<float> AnimationCurve;
template<class T> class AnimationCurveTpl; typedef AnimationCurveTpl<float> AnimationCurveBase;
class AnimationClip;
class Transform;
class AABB;
namespace Unity { class Component; }
#define GET_SET_REF(a,b,c) void Set##b (a& val) { c = val; } a& Get##b () const {return c; }
#define kReallySmallWeight 0.0001F
#define kReallySmallFadeTime 0.001F
enum {
kRebindDirtyMask = 1 << 0,
kLayersDirtyMask = 1 << 1
};
class AnimationState : public TrackedReferenceBase
{
private:
// Indicates state of m_AnimationEventIndex
enum {
// m_AnimationEventIndex is valid
kAnimationEventState_HasEvent = 0,
// m_AnimationEventIndex need to be researched
kAnimationEventState_Search,
// m_AnimationEventIndex there are no more keys available, no need to search
kAnimationEventState_NotFound,
// This is very special case:
// m_AnimationEventIndex points to a valid index and AnimationState is paused,
// but this event has been triggered already, so when AnimationState state is unpaused
// we have to continue triggering event on left or right side of this event
// (depending on the sign of AnimationState speed)
kAnimationEventState_PausedOnEvent,
// Used for assert
kAnimationEventState__Count
};
public:
enum { kBlend = 0, kAdditive };
AnimationState ();
~AnimationState ();
static void InitializeClass ();
static void CleanupClass ();
/// Makes the animation state reach a /target/ blend weight in length seconds.
/// If the animation is already fading towards target and it would reach the target
/// faster, then the weight speed will not be modified.
/// if stopWhenFaded is enabled, the animation will stop when the target is reached.
void SetWeightTarget (float target, float length, bool stopWhenFaded);
void SetWeightTargetImmediate (float target, bool stopWhenFaded);
void Stop ();
// This automatically sets m_LastGlobalTime from globa
void SetEnabled (bool enabled);
bool GetEnabled () const { return m_Enabled; }
void SetTime (float time);
const float GetTime() const { return m_Time; }
int GetWrapMode () const { return m_WrapMode; }
void SetWrapMode (int mode);
GET_SET_REF(const UnityStr, Name, m_Name)
GET_SET_REF(const UnityStr, ParentName, m_ParentName)
void SetLayer (int layer) { m_Layer = layer; m_DirtyMask |= kLayersDirtyMask; }
int GetLayer () const { return m_Layer; }
void SetWeight (float val) { m_Weight = val; }
float GetWeight () const { return m_Weight; }
void SetNormalizedSpeed (float speed) { m_SyncedSpeed = m_Speed = speed * GetLength(); }
float GetNormalizedSpeed () const { return m_Speed / GetLength(); }
void SetSpeed (float speed);
float GetSpeed () const { return m_Speed; }
float GetSyncedSpeed () const { return m_SyncedSpeed; }
void SetNormalizedTime (float time) { SetTime( time * GetLength()); }
float GetNormalizedTime () const { return m_Time / GetLength(); }
float GetLength () const { return m_CachedRange.second; }
/// Sets the fadeout length and stop time based on the used wrapmode.
void SetupFadeout (float length);
int GetBlendMode() const { return m_BlendMode; }
void SetBlendMode(int mode) { m_BlendMode = mode; }
AnimationClip* GetClip() { return m_Clip; }
void ClearDirtyMask() { m_DirtyMask = 0; }
UInt32 GetDirtyMask () const { return m_DirtyMask; }
// Returns true if the state is enabled and has a reasonably high weight
inline bool ShouldUse() const;
// Used for layer syncing
void SetNormalizedSyncedSpeed (float speed) { m_SyncedSpeed = speed * GetLength(); }
bool UpdateAnimationState (double globalTime, Unity::Component& animation);
void Init(const UnityStr& name, AnimationClip* clip, double globalTime, int wrap, bool isClone = false);
void CleanupCurves ();
void SetAutoCleanup(){ m_AutoCleanup = 1; }
void ForceAutoCleanup() { SetAutoCleanup(); m_ShouldCleanup = true; }
bool ShouldAutoCleanupNow () { return m_ShouldCleanup; }
bool IsClone() { return m_IsClone; }
typedef AnimationCurveBase** Curves;
Curves GetCurves() { return m_Curves; }
Curves const GetCurves() const { return m_Curves; }
void AllocateCurves(int count);
void SetClonedCurves(AnimationState& state);
bool ShouldMixTransform (Transform& transform);
void AddMixingTransform(Transform& transform, bool recursive);
void RemoveMixingTransform(Transform& transform);
/// When an animation is stopped and it is the only animation playing.
/// Then you usually want the last frame to display before the animation stops.
/// For example an elevator moving up. It should always make sure the last frame gets sampled.
/// -> Now unfortunately we stop time during UpdateAnimationState which means the time gets reset
/// -> Which wrapped time and weight will be set to zero when actually sampling the animation.
/// -> So we just fix the very specific, single animation playing and stopping case,
/// by storing the wrap mode prior to animation stop and then afterwards reverting it again.
/// *** I guess the right way to solve this would be to make animation stopping happen after sampling or something...
void SetupUnstoppedState ();
void CleanupUnstoppedState ();
bool FireEvents (const float deltaTime, float newWrappedTime, bool reverse, Unity::Component& animation, const float beginTime, const float offsetTime, const bool reverseOffsetTime);
// We made a bunch of fixes in Unity 3.2, but we couldn't use them since it breaks backwards compatibility,
// so we enable the fixes only for 3.2 content
// TODO : get rid of this function and all related backwards compatible functions as soon as we are allowed to break backwards compatibility
static bool UseUnity32AnimationFixes();
// Same story (see above) with animation fixes in Unity 3.4
static bool UseUnity34AnimationFixes();
// Same story (see above) with animation fixes in Unity 3.5
static bool UseUnity35AnimationFixes();
private:
bool UseStopTime() const { return m_WrapMode == kClamp || m_WrapMode == kDefaultWrapMode; }
void SetupStopTime();
typedef List< ListNode<AnimationState> > AnimationStateList;
static void DidModifyAnimationClip (AnimationClip* clip, AnimationStateList& states);
bool UpdateFading_Before32(float deltaTime);
bool UpdateFading(float deltaTime);
bool UpdateBlendingWeight(const float deltaTime, const bool instantBlend);
private:
Curves m_Curves;
// int m_CurvesCount;
float m_Weight;
float m_WrappedTime; // Always keep in animation clip length range
double m_Time; // Keeps on increasing forever -> higher precision
double m_LastGlobalTime; // Keeps on increasing forever -> higher precision
int m_Layer;
float m_Speed;
float m_SyncedSpeed;
float m_StopTime;
float m_FadeOutLength;
float m_WeightTarget;
UInt32 m_FadeBlend : 1;
UInt32 m_Enabled : 1;
UInt32 m_StopWhenFadedOut : 1;
UInt32 m_AutoCleanup : 1;
UInt32 m_OwnsCurves : 1;
UInt32 m_IsFadingOut : 1;
UInt32 m_ShouldCleanup : 1;
UInt32 m_HasAnimationEvent : 1;
UInt32 m_IsClone : 1;
// make sure that there are enough bits to store kAnimationEventStates
UInt32 m_AnimationEventState : 2;
int m_AnimationEventIndex;
UInt32 m_DirtyMask;
int m_WrapMode; ///< enum { Default = 0, Once = 1, Loop = 2, PingPong = 4, ClampForever = 8 }
int m_BlendMode; ///< enum { Blend = 0, Additive = 1 }
float m_WeightDelta;
///@TODO: FIXME HACKED Time stopping
float m_UnstoppedLastWrappedTime;
float m_UnstoppedLastWeight;
std::pair<float, float> m_CachedRange;
AnimationClip* m_Clip;
ListNode<AnimationState> m_AnimationClipNode;
UnityStr m_Name;
UnityStr m_ParentName;
typedef std::map<PPtr<Transform>, bool> MixingTransforms;
MixingTransforms m_MixingTransforms;
friend class Animation;
};
float WrapTime (float time, const std::pair<float, float>& range, int m_WrapMode);
inline bool AnimationState::ShouldUse() const
{
return m_Clip && m_Enabled && m_Weight > kReallySmallWeight;
}
// For debugging purposes display some of the animation state information!
#if UNITY_EDITOR
#include "Runtime/Serialize/SerializeTraits.h"
template<>
class SerializeTraits<AnimationState*> : public SerializeTraitsBase<AnimationState*>
{
public:
typedef AnimationState* value_type;
inline static const char* GetTypeString (void*) { return "AnimationState"; }
inline static bool IsAnimationChannel () { return false; }
inline static bool MightContainPPtr () { return true; }
inline static bool AllowTransferOptimization () { return false; }
template<class TransferFunction> inline
static void Transfer (value_type& data, TransferFunction& transfer)
{
TRANSFER_PROPERTY_DEBUG(UnityStr, m_Name, data->GetName)
TRANSFER_PROPERTY_DEBUG(bool, m_Enabled, data->GetEnabled)
transfer.Align();
TRANSFER_PROPERTY_DEBUG(float, m_Weight, data->GetWeight)
TRANSFER_PROPERTY_DEBUG(float, m_Time, data->GetTime)
TRANSFER_PROPERTY_DEBUG(float, m_Speed, data->GetSpeed)
TRANSFER_PROPERTY_DEBUG(float, m_SyncedSpeed, data->GetSyncedSpeed)
TRANSFER_PROPERTY_DEBUG(int, m_WrapMode, data->GetWrapMode)
TRANSFER_PROPERTY_DEBUG(int, m_BlendMode, data->GetBlendMode)
TRANSFER_PROPERTY_DEBUG(PPtr<AnimationClip>, m_Clip, data->GetClip)
}
};
#endif
|