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