ValueAnimationInfo.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../IO/Log.h"
  5. #include "../Scene/ValueAnimation.h"
  6. #include "../Scene/ValueAnimationInfo.h"
  7. #include "../DebugNew.h"
  8. namespace Urho3D
  9. {
  10. ValueAnimationInfo::ValueAnimationInfo(ValueAnimation* animation, WrapMode wrapMode, float speed) :
  11. animation_(animation),
  12. wrapMode_(wrapMode),
  13. speed_(speed),
  14. currentTime_(0.0f),
  15. lastScaledTime_(0.0f)
  16. {
  17. speed_ = Max(0.0f, speed_);
  18. }
  19. ValueAnimationInfo::ValueAnimationInfo(Object* target, ValueAnimation* animation, WrapMode wrapMode, float speed) :
  20. target_(target),
  21. animation_(animation),
  22. wrapMode_(wrapMode),
  23. speed_(speed),
  24. currentTime_(0.0f),
  25. lastScaledTime_(0.0f)
  26. {
  27. speed_ = Max(0.0f, speed_);
  28. }
  29. ValueAnimationInfo::ValueAnimationInfo(const ValueAnimationInfo& other) :
  30. target_(other.target_),
  31. animation_(other.animation_),
  32. wrapMode_(other.wrapMode_),
  33. speed_(other.speed_),
  34. currentTime_(0.0f),
  35. lastScaledTime_(0.0f)
  36. {
  37. }
  38. ValueAnimationInfo::~ValueAnimationInfo() = default;
  39. bool ValueAnimationInfo::Update(float timeStep)
  40. {
  41. if (!animation_ || !target_)
  42. return true;
  43. return SetTime(currentTime_ + timeStep * speed_);
  44. }
  45. bool ValueAnimationInfo::SetTime(float time)
  46. {
  47. if (!animation_ || !target_)
  48. return true;
  49. currentTime_ = time;
  50. if (!animation_->IsValid())
  51. return true;
  52. bool finished = false;
  53. // Calculate scale time by wrap mode
  54. float scaledTime = CalculateScaledTime(currentTime_, finished);
  55. // Apply to the target object
  56. ApplyValue(animation_->GetAnimationValue(scaledTime));
  57. // Send keyframe event if necessary
  58. if (animation_->HasEventFrames())
  59. {
  60. Vector<const VAnimEventFrame*> eventFrames;
  61. GetEventFrames(lastScaledTime_, scaledTime, eventFrames);
  62. if (eventFrames.Size())
  63. {
  64. // Make a copy of the target weakptr, since if it expires, the AnimationInfo is deleted as well, in which case the
  65. // member variable cannot be accessed
  66. WeakPtr<Object> targetWeak(target_);
  67. for (unsigned i = 0; i < eventFrames.Size(); ++i)
  68. target_->SendEvent(eventFrames[i]->eventType_, const_cast<VariantMap&>(eventFrames[i]->eventData_));
  69. // Break immediately if target expired due to event
  70. if (targetWeak.Expired())
  71. return true;
  72. }
  73. }
  74. lastScaledTime_ = scaledTime;
  75. return finished;
  76. }
  77. Object* ValueAnimationInfo::GetTarget() const
  78. {
  79. return target_;
  80. }
  81. void ValueAnimationInfo::ApplyValue(const Variant& newValue)
  82. {
  83. }
  84. float ValueAnimationInfo::CalculateScaledTime(float currentTime, bool& finished) const
  85. {
  86. float beginTime = animation_->GetBeginTime();
  87. float endTime = animation_->GetEndTime();
  88. switch (wrapMode_)
  89. {
  90. case WM_LOOP:
  91. {
  92. float span = endTime - beginTime;
  93. float time = fmodf(currentTime - beginTime, span);
  94. if (time < 0.0f)
  95. time += span;
  96. return beginTime + time;
  97. }
  98. case WM_ONCE:
  99. finished = (currentTime >= endTime);
  100. [[fallthrough]];
  101. case WM_CLAMP:
  102. return Clamp(currentTime, beginTime, endTime);
  103. default:
  104. URHO3D_LOGERROR("Unsupported attribute animation wrap mode");
  105. return beginTime;
  106. }
  107. }
  108. void ValueAnimationInfo::GetEventFrames(float beginTime, float endTime, Vector<const VAnimEventFrame*>& eventFrames)
  109. {
  110. switch (wrapMode_)
  111. {
  112. case WM_LOOP:
  113. /// \todo This can miss an event if the deltatime is exactly the animation's length
  114. if (beginTime <= endTime)
  115. animation_->GetEventFrames(beginTime, endTime, eventFrames);
  116. else
  117. {
  118. animation_->GetEventFrames(beginTime, animation_->GetEndTime(), eventFrames);
  119. animation_->GetEventFrames(animation_->GetBeginTime(), endTime, eventFrames);
  120. }
  121. break;
  122. case WM_ONCE:
  123. case WM_CLAMP:
  124. animation_->GetEventFrames(beginTime, endTime, eventFrames);
  125. break;
  126. }
  127. }
  128. }