1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Precompiled.h"
24 
25 #include "../Core/Context.h"
26 #include "../Core/StringUtils.h"
27 #include "../IO/Deserializer.h"
28 #include "../IO/Log.h"
29 #include "../IO/Serializer.h"
30 #include "../Resource/XMLFile.h"
31 #include "../Resource/JSONFile.h"
32 #include "../Scene/Animatable.h"
33 #include "../Scene/ObjectAnimation.h"
34 #include "../Scene/ValueAnimation.h"
35 
36 #include "../DebugNew.h"
37 
38 namespace Urho3D
39 {
40 
41 const char* interpMethodNames[] =
42 {
43     "None",
44     "Linear",
45     "Spline",
46     0
47 };
48 
ValueAnimation(Context * context)49 ValueAnimation::ValueAnimation(Context* context) :
50     Resource(context),
51     owner_(0),
52     interpolationMethod_(IM_LINEAR),
53     splineTension_(0.5f),
54     valueType_(VAR_NONE),
55     interpolatable_(false),
56     beginTime_(M_INFINITY),
57     endTime_(-M_INFINITY),
58     splineTangentsDirty_(false)
59 {
60 }
61 
~ValueAnimation()62 ValueAnimation::~ValueAnimation()
63 {
64 }
65 
RegisterObject(Context * context)66 void ValueAnimation::RegisterObject(Context* context)
67 {
68     context->RegisterFactory<ValueAnimation>();
69 }
70 
BeginLoad(Deserializer & source)71 bool ValueAnimation::BeginLoad(Deserializer& source)
72 {
73     XMLFile xmlFile(context_);
74     if (!xmlFile.Load(source))
75         return false;
76 
77     return LoadXML(xmlFile.GetRoot());
78 }
79 
Save(Serializer & dest) const80 bool ValueAnimation::Save(Serializer& dest) const
81 {
82     XMLFile xmlFile(context_);
83 
84     XMLElement rootElem = xmlFile.CreateRoot("valueanimation");
85     if (!SaveXML(rootElem))
86         return false;
87 
88     return xmlFile.Save(dest);
89 }
90 
LoadXML(const XMLElement & source)91 bool ValueAnimation::LoadXML(const XMLElement& source)
92 {
93     valueType_ = VAR_NONE;
94     eventFrames_.Clear();
95 
96     String interpMethodString = source.GetAttribute("interpolationmethod");
97     InterpMethod method = (InterpMethod)GetStringListIndex(interpMethodString.CString(), interpMethodNames, IM_LINEAR);
98 
99     SetInterpolationMethod(method);
100     if (interpolationMethod_ == IM_SPLINE)
101         splineTension_ = source.GetFloat("splinetension");
102 
103     XMLElement keyFrameElem = source.GetChild("keyframe");
104     while (keyFrameElem)
105     {
106         float time = keyFrameElem.GetFloat("time");
107         Variant value = keyFrameElem.GetVariant();
108         SetKeyFrame(time, value);
109 
110         keyFrameElem = keyFrameElem.GetNext("keyframe");
111     }
112 
113     XMLElement eventFrameElem = source.GetChild("eventframe");
114     while (eventFrameElem)
115     {
116         float time = eventFrameElem.GetFloat("time");
117         unsigned eventType = eventFrameElem.GetUInt("eventtype");
118         VariantMap eventData = eventFrameElem.GetChild("eventdata").GetVariantMap();
119 
120         SetEventFrame(time, StringHash(eventType), eventData);
121         eventFrameElem = eventFrameElem.GetNext("eventframe");
122     }
123 
124     return true;
125 }
126 
SaveXML(XMLElement & dest) const127 bool ValueAnimation::SaveXML(XMLElement& dest) const
128 {
129     dest.SetAttribute("interpolationmethod", interpMethodNames[interpolationMethod_]);
130     if (interpolationMethod_ == IM_SPLINE)
131         dest.SetFloat("splinetension", splineTension_);
132 
133     for (unsigned i = 0; i < keyFrames_.Size(); ++i)
134     {
135         const VAnimKeyFrame& keyFrame = keyFrames_[i];
136         XMLElement keyFrameEleme = dest.CreateChild("keyframe");
137         keyFrameEleme.SetFloat("time", keyFrame.time_);
138         keyFrameEleme.SetVariant(keyFrame.value_);
139     }
140 
141     for (unsigned i = 0; i < eventFrames_.Size(); ++i)
142     {
143         const VAnimEventFrame& eventFrame = eventFrames_[i];
144         XMLElement eventFrameElem = dest.CreateChild("eventframe");
145         eventFrameElem.SetFloat("time", eventFrame.time_);
146         eventFrameElem.SetUInt("eventtype", eventFrame.eventType_.Value());
147         eventFrameElem.CreateChild("eventdata").SetVariantMap(eventFrame.eventData_);
148     }
149 
150     return true;
151 }
152 
LoadJSON(const JSONValue & source)153 bool ValueAnimation::LoadJSON(const JSONValue& source)
154 {
155     valueType_ = VAR_NONE;
156     eventFrames_.Clear();
157 
158     String interpMethodString = source.Get("interpolationmethod").GetString();
159     InterpMethod method = (InterpMethod)GetStringListIndex(interpMethodString.CString(), interpMethodNames, IM_LINEAR);
160 
161     SetInterpolationMethod(method);
162     if (interpolationMethod_ == IM_SPLINE)
163         splineTension_ = source.Get("splinetension").GetFloat();
164 
165     // Load keyframes
166     JSONArray keyFramesArray = source.Get("keyframes").GetArray();
167     for (unsigned i = 0; i < keyFramesArray.Size(); i++)
168     {
169         const JSONValue& val = keyFramesArray[i];
170         float time = val.Get("time").GetFloat();
171         Variant value = val.Get("value").GetVariant();
172         SetKeyFrame(time, value);
173     }
174 
175     // Load event frames
176     JSONArray eventFramesArray = source.Get("eventframes").GetArray();
177     for (unsigned i = 0; i < eventFramesArray.Size(); i++)
178     {
179         const JSONValue& eventFrameVal = eventFramesArray[i];
180         float time = eventFrameVal.Get("time").GetFloat();
181         unsigned eventType = eventFrameVal.Get("eventtype").GetUInt();
182         VariantMap eventData = eventFrameVal.Get("eventdata").GetVariantMap();
183         SetEventFrame(time, StringHash(eventType), eventData);
184     }
185 
186     return true;
187 }
188 
SaveJSON(JSONValue & dest) const189 bool ValueAnimation::SaveJSON(JSONValue& dest) const
190 {
191     dest.Set("interpolationmethod", interpMethodNames[interpolationMethod_]);
192     if (interpolationMethod_ == IM_SPLINE)
193         dest.Set("splinetension", (float) splineTension_);
194 
195     JSONArray keyFramesArray;
196     keyFramesArray.Reserve(keyFrames_.Size());
197     for (unsigned i = 0; i < keyFrames_.Size(); ++i)
198     {
199         const VAnimKeyFrame& keyFrame = keyFrames_[i];
200         JSONValue keyFrameVal;
201         keyFrameVal.Set("time", keyFrame.time_);
202         JSONValue valueVal;
203         valueVal.SetVariant(keyFrame.value_);
204         keyFrameVal.Set("value", valueVal);
205         keyFramesArray.Push(keyFrameVal);
206     }
207     dest.Set("keyframes", keyFramesArray);
208 
209     JSONArray eventFramesArray;
210     eventFramesArray.Reserve(eventFrames_.Size());
211     for (unsigned i = 0; i < eventFrames_.Size(); ++i)
212     {
213         const VAnimEventFrame& eventFrame = eventFrames_[i];
214         JSONValue eventFrameVal;
215         eventFrameVal.Set("time", eventFrame.time_);
216         eventFrameVal.Set("eventtype", eventFrame.eventType_.Value());
217         JSONValue eventDataVal;
218         eventDataVal.SetVariantMap(eventFrame.eventData_);
219         eventFrameVal.Set("eventdata", eventDataVal);
220 
221         eventFramesArray.Push(eventFrameVal);
222     }
223     dest.Set("eventframes", eventFramesArray);
224 
225     return true;
226 }
227 
SetValueType(VariantType valueType)228 void ValueAnimation::SetValueType(VariantType valueType)
229 {
230     if (valueType == valueType_)
231         return;
232 
233     valueType_ = valueType;
234     interpolatable_ =
235         (valueType_ == VAR_FLOAT) || (valueType_ == VAR_VECTOR2) || (valueType_ == VAR_VECTOR3) || (valueType_ == VAR_VECTOR4) ||
236         (valueType_ == VAR_QUATERNION) || (valueType_ == VAR_COLOR);
237 
238     if ((valueType_ == VAR_INTRECT) || (valueType_ == VAR_INTVECTOR2) || (valueType_ == VAR_INTVECTOR3))
239     {
240         interpolatable_ = true;
241         // Force linear interpolation for IntRect, IntVector2 and IntVector3
242         if (interpolationMethod_ == IM_SPLINE)
243             interpolationMethod_ = IM_LINEAR;
244     }
245 
246     keyFrames_.Clear();
247     eventFrames_.Clear();
248     beginTime_ = M_INFINITY;
249     endTime_ = -M_INFINITY;
250 }
251 
SetOwner(void * owner)252 void ValueAnimation::SetOwner(void* owner)
253 {
254     owner_ = owner;
255 }
256 
SetInterpolationMethod(InterpMethod method)257 void ValueAnimation::SetInterpolationMethod(InterpMethod method)
258 {
259     if (method == interpolationMethod_)
260         return;
261 
262     // Force linear interpolation for IntRect, IntVector2 and IntVector3
263     if (method == IM_SPLINE && (valueType_ == VAR_INTRECT || valueType_ == VAR_INTVECTOR2 || valueType_ == VAR_INTVECTOR3))
264         method = IM_LINEAR;
265 
266     interpolationMethod_ = method;
267     splineTangentsDirty_ = true;
268 }
269 
SetSplineTension(float tension)270 void ValueAnimation::SetSplineTension(float tension)
271 {
272     splineTension_ = tension;
273     splineTangentsDirty_ = true;
274 }
275 
SetKeyFrame(float time,const Variant & value)276 bool ValueAnimation::SetKeyFrame(float time, const Variant& value)
277 {
278     if (valueType_ == VAR_NONE)
279         SetValueType(value.GetType());
280     else if (value.GetType() != valueType_)
281         return false;
282 
283     VAnimKeyFrame keyFrame;
284     keyFrame.time_ = time;
285     keyFrame.value_ = value;
286 
287     if (keyFrames_.Empty() || time > keyFrames_.Back().time_)
288         keyFrames_.Push(keyFrame);
289     else
290     {
291         for (unsigned i = 0; i < keyFrames_.Size(); ++i)
292         {
293             // Guard against interpolation error caused by division by error due to 0 delta time between two key frames
294             if (time == keyFrames_[i].time_)
295                 return false;
296             if (time < keyFrames_[i].time_)
297             {
298                 keyFrames_.Insert(i, keyFrame);
299                 break;
300             }
301         }
302     }
303 
304     beginTime_ = Min(time, beginTime_);
305     endTime_ = Max(time, endTime_);
306     splineTangentsDirty_ = true;
307 
308     return true;
309 }
310 
SetEventFrame(float time,const StringHash & eventType,const VariantMap & eventData)311 void ValueAnimation::SetEventFrame(float time, const StringHash& eventType, const VariantMap& eventData)
312 {
313     VAnimEventFrame eventFrame;
314     eventFrame.time_ = time;
315     eventFrame.eventType_ = eventType;
316     eventFrame.eventData_ = eventData;
317 
318     if (eventFrames_.Empty() || time >= eventFrames_.Back().time_)
319         eventFrames_.Push(eventFrame);
320     else
321     {
322         for (unsigned i = 0; i < eventFrames_.Size(); ++i)
323         {
324             if (time < eventFrames_[i].time_)
325             {
326                 eventFrames_.Insert(i, eventFrame);
327                 break;
328             }
329         }
330     }
331 
332     beginTime_ = Min(time, beginTime_);
333     endTime_ = Max(time, endTime_);
334 }
335 
IsValid() const336 bool ValueAnimation::IsValid() const
337 {
338     return (interpolationMethod_ == IM_NONE) ||
339            (interpolationMethod_ == IM_LINEAR && keyFrames_.Size() > 1) ||
340            (interpolationMethod_ == IM_SPLINE && keyFrames_.Size() > 2);
341 }
342 
GetAnimationValue(float scaledTime)343 Variant ValueAnimation::GetAnimationValue(float scaledTime)
344 {
345     unsigned index = 1;
346     for (; index < keyFrames_.Size(); ++index)
347     {
348         if (scaledTime < keyFrames_[index].time_)
349             break;
350     }
351 
352     if (index >= keyFrames_.Size() || !interpolatable_ || interpolationMethod_ == IM_NONE)
353         return keyFrames_[index - 1].value_;
354     else
355     {
356         if (interpolationMethod_ == IM_LINEAR)
357             return LinearInterpolation(index - 1, index, scaledTime);
358         else
359             return SplineInterpolation(index - 1, index, scaledTime);
360     }
361 }
362 
GetEventFrames(float beginTime,float endTime,PODVector<const VAnimEventFrame * > & eventFrames) const363 void ValueAnimation::GetEventFrames(float beginTime, float endTime, PODVector<const VAnimEventFrame*>& eventFrames) const
364 {
365     for (unsigned i = 0; i < eventFrames_.Size(); ++i)
366     {
367         const VAnimEventFrame& eventFrame = eventFrames_[i];
368         if (eventFrame.time_ > endTime)
369             break;
370 
371         if (eventFrame.time_ >= beginTime)
372             eventFrames.Push(&eventFrame);
373     }
374 }
375 
LinearInterpolation(unsigned index1,unsigned index2,float scaledTime) const376 Variant ValueAnimation::LinearInterpolation(unsigned index1, unsigned index2, float scaledTime) const
377 {
378     const VAnimKeyFrame& keyFrame1 = keyFrames_[index1];
379     const VAnimKeyFrame& keyFrame2 = keyFrames_[index2];
380 
381     float t = (scaledTime - keyFrame1.time_) / (keyFrame2.time_ - keyFrame1.time_);
382     const Variant& value1 = keyFrame1.value_;
383     const Variant& value2 = keyFrame2.value_;
384 
385     switch (valueType_)
386     {
387     case VAR_FLOAT:
388         return Lerp(value1.GetFloat(), value2.GetFloat(), t);
389 
390     case VAR_VECTOR2:
391         return value1.GetVector2().Lerp(value2.GetVector2(), t);
392 
393     case VAR_VECTOR3:
394         return value1.GetVector3().Lerp(value2.GetVector3(), t);
395 
396     case VAR_VECTOR4:
397         return value1.GetVector4().Lerp(value2.GetVector4(), t);
398 
399     case VAR_QUATERNION:
400         return value1.GetQuaternion().Slerp(value2.GetQuaternion(), t);
401 
402     case VAR_COLOR:
403         return value1.GetColor().Lerp(value2.GetColor(), t);
404 
405     case VAR_INTRECT:
406         {
407             float s = 1.0f - t;
408             const IntRect& r1 = value1.GetIntRect();
409             const IntRect& r2 = value2.GetIntRect();
410             return IntRect((int)(r1.left_ * s + r2.left_ * t), (int)(r1.top_ * s + r2.top_ * t), (int)(r1.right_ * s + r2.right_ * t),
411                 (int)(r1.bottom_ * s + r2.bottom_ * t));
412         }
413 
414     case VAR_INTVECTOR2:
415         {
416             float s = 1.0f - t;
417             const IntVector2& v1 = value1.GetIntVector2();
418             const IntVector2& v2 = value2.GetIntVector2();
419             return IntVector2((int)(v1.x_ * s + v2.x_ * t), (int)(v1.y_ * s + v2.y_ * t));
420         }
421 
422     case VAR_INTVECTOR3:
423         {
424             float s = 1.0f - t;
425             const IntVector3& v1 = value1.GetIntVector3();
426             const IntVector3& v2 = value2.GetIntVector3();
427             return IntVector3((int)(v1.x_ * s + v2.x_ * t), (int)(v1.y_ * s + v2.y_ * t), (int)(v1.z_ * s + v2.z_ * t));
428         }
429 
430     case VAR_DOUBLE:
431         return value1.GetDouble() * (1.0f - t) + value2.GetDouble() * t;
432 
433     default:
434         URHO3D_LOGERROR("Invalid value type for linear interpolation");
435         return Variant::EMPTY;
436     }
437 }
438 
SplineInterpolation(unsigned index1,unsigned index2,float scaledTime)439 Variant ValueAnimation::SplineInterpolation(unsigned index1, unsigned index2, float scaledTime)
440 {
441     if (splineTangentsDirty_)
442         UpdateSplineTangents();
443 
444     const VAnimKeyFrame& keyFrame1 = keyFrames_[index1];
445     const VAnimKeyFrame& keyFrame2 = keyFrames_[index2];
446 
447     float t = (scaledTime - keyFrame1.time_) / (keyFrame2.time_ - keyFrame1.time_);
448 
449     float tt = t * t;
450     float ttt = t * tt;
451 
452     float h1 = 2.0f * ttt - 3.0f * tt + 1.0f;
453     float h2 = -2.0f * ttt + 3.0f * tt;
454     float h3 = ttt - 2.0f * tt + t;
455     float h4 = ttt - tt;
456 
457     const Variant& v1 = keyFrame1.value_;
458     const Variant& v2 = keyFrame2.value_;
459     const Variant& t1 = splineTangents_[index1];
460     const Variant& t2 = splineTangents_[index2];
461 
462     switch (valueType_)
463     {
464     case VAR_FLOAT:
465         return v1.GetFloat() * h1 + v2.GetFloat() * h2 + t1.GetFloat() * h3 + t2.GetFloat() * h4;
466 
467     case VAR_VECTOR2:
468         return v1.GetVector2() * h1 + v2.GetVector2() * h2 + t1.GetVector2() * h3 + t2.GetVector2() * h4;
469 
470     case VAR_VECTOR3:
471         return v1.GetVector3() * h1 + v2.GetVector3() * h2 + t1.GetVector3() * h3 + t2.GetVector3() * h4;
472 
473     case VAR_VECTOR4:
474         return v1.GetVector4() * h1 + v2.GetVector4() * h2 + t1.GetVector4() * h3 + t2.GetVector4() * h4;
475 
476     case VAR_QUATERNION:
477         return v1.GetQuaternion() * h1 + v2.GetQuaternion() * h2 + t1.GetQuaternion() * h3 + t2.GetQuaternion() * h4;
478 
479     case VAR_COLOR:
480         return v1.GetColor() * h1 + v2.GetColor() * h2 + t1.GetColor() * h3 + t2.GetColor() * h4;
481 
482     case VAR_DOUBLE:
483         return v1.GetDouble() * h1 + v2.GetDouble() * h2 + t1.GetDouble() * h3 + t2.GetDouble() * h4;
484 
485     default:
486         URHO3D_LOGERROR("Invalid value type for spline interpolation");
487         return Variant::EMPTY;
488     }
489 }
490 
UpdateSplineTangents()491 void ValueAnimation::UpdateSplineTangents()
492 {
493     splineTangents_.Clear();
494 
495     if (!IsValid())
496         return;
497 
498     unsigned size = keyFrames_.Size();
499     splineTangents_.Resize(size);
500 
501     for (unsigned i = 1; i < size - 1; ++i)
502         splineTangents_[i] = SubstractAndMultiply(keyFrames_[i + 1].value_, keyFrames_[i - 1].value_, splineTension_);
503 
504     // If spline is not closed, make end point's tangent zero
505     if (keyFrames_[0].value_ != keyFrames_[size - 1].value_)
506         splineTangents_[0] = splineTangents_[size - 1] =
507             SubstractAndMultiply(keyFrames_[0].value_, keyFrames_[0].value_, splineTension_);
508     else
509         splineTangents_[0] = splineTangents_[size - 1] =
510             SubstractAndMultiply(keyFrames_[1].value_, keyFrames_[size - 2].value_, splineTension_);
511 
512     splineTangentsDirty_ = false;
513 }
514 
SubstractAndMultiply(const Variant & value1,const Variant & value2,float t) const515 Variant ValueAnimation::SubstractAndMultiply(const Variant& value1, const Variant& value2, float t) const
516 {
517     switch (valueType_)
518     {
519     case VAR_FLOAT:
520         return (value1.GetFloat() - value2.GetFloat()) * t;
521 
522     case VAR_VECTOR2:
523         return (value1.GetVector2() - value2.GetVector2()) * t;
524 
525     case VAR_VECTOR3:
526         return (value1.GetVector3() - value2.GetVector3()) * t;
527 
528     case VAR_VECTOR4:
529         return (value1.GetVector4() - value2.GetVector4()) * t;
530 
531     case VAR_QUATERNION:
532         return (value1.GetQuaternion() - value2.GetQuaternion()) * t;
533 
534     case VAR_COLOR:
535         return (value1.GetColor() - value2.GetColor()) * t;
536 
537     case VAR_DOUBLE:
538         return (value1.GetDouble() - value2.GetDouble()) * t;
539 
540     default:
541         URHO3D_LOGERROR("Invalid value type for spline interpolation's subtract and multiply operation");
542         return Variant::EMPTY;
543     }
544 }
545 
546 }
547