}
END_TEST;
}
+
+int UtcDaliAnimationSetGetBlendPoint(void)
+{
+ TestApplication application;
+
+
+ Animation animation = Animation::New(1.0f);
+ DALI_TEST_EQUALS(animation.GetBlendPoint(), 0.0f, 0.01f, TEST_LOCATION);
+
+ animation.SetBlendPoint(0.5f);
+
+ DALI_TEST_EQUALS(animation.GetBlendPoint(), 0.5f, 0.01f, TEST_LOCATION);
+
+ animation.SetBlendPoint(-0.5f);
+
+ DALI_TEST_EQUALS(animation.GetBlendPoint(), 0.5f, 0.01f, TEST_LOCATION);
+
+ animation.SetBlendPoint(1.5f);
+
+ DALI_TEST_EQUALS(animation.GetBlendPoint(), 0.5f, 0.01f, TEST_LOCATION);
+
+ animation.SetBlendPoint(0.7f);
+
+ DALI_TEST_EQUALS(animation.GetBlendPoint(), 0.7f, 0.01f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendFloatCubic(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", 0.0f);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, 3.0f);
+ keyframes.Add(0.4f, 1.0f);
+ keyframes.Add(0.6f, 1.0f);
+ keyframes.Add(1.0f, 3.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR, Animation::Interpolation::CUBIC);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ float value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 0.989258f, 0.05f, TEST_LOCATION); // original value : 1.603516 (Same value as when progress is 0.75.)
+ // current value : 0.0f
+ // value when progress is 0.5 : 0.75
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 0.750000f, 0.05f, TEST_LOCATION); // value is less than 1.0f
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.603516f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 3.0f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendFloat1(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", 0.0f);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, 1.0f);
+ keyframes.Add(0.2f, 2.0f);
+ keyframes.Add(0.4f, 3.0f);
+ keyframes.Add(0.6f, 4.0f);
+ keyframes.Add(0.8f, 5.0f);
+ keyframes.Add(1.0f, 6.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.9f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ float value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.728395f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 3.302469f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 4.722222f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 6.0f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendFloat2(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", 0.0f);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, 0.0f);
+ keyframes.Add(1.0f, 1.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ float value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 0.25f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 0.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendFloat3(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", 0.0f);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, 1.0f);
+ keyframes.Add(1.0f, 2.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ float value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.0f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendFloat4(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", 0.0f);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, 1.0f);
+ keyframes.Add(1.0f, 2.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ float value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.0f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.5f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(550);
+
+ actor.SetProperty(index, 0.0f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.0f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<float>(index);
+ DALI_TEST_EQUALS(value, 1.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendInt(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", 0);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, 100);
+ keyframes.Add(1.0f, 200);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ int32_t value = actor.GetCurrentProperty<int32_t>(index);
+ DALI_TEST_EQUALS(value, 100, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<int32_t>(index);
+ DALI_TEST_EQUALS(value, 150, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendVector2(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", Vector2::ZERO);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, Vector2::ONE);
+ keyframes.Add(1.0f, Vector2::ONE * 2.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ Vector2 value = actor.GetCurrentProperty<Vector2>(index);
+ DALI_TEST_EQUALS(value, Vector2::ONE, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<Vector2>(index);
+ DALI_TEST_EQUALS(value, Vector2::ONE * 1.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendVector3(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", Vector3::ZERO);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, Vector3::ONE);
+ keyframes.Add(1.0f, Vector3::ONE * 2.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ Vector3 value = actor.GetCurrentProperty<Vector3>(index);
+ DALI_TEST_EQUALS(value, Vector3::ONE, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<Vector3>(index);
+ DALI_TEST_EQUALS(value, Vector3::ONE * 1.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendVector4(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", Vector4::ZERO);
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, Vector4::ONE);
+ keyframes.Add(1.0f, Vector4::ONE * 2.0f);
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ Vector4 value = actor.GetCurrentProperty<Vector4>(index);
+ DALI_TEST_EQUALS(value, Vector4::ONE, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<Vector4>(index);
+ DALI_TEST_EQUALS(value, Vector4::ONE * 1.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayBlendQuaternion(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+ Property::Index index = actor.RegisterProperty("property", Quaternion(Dali::Radian(0.0f), Vector3::ZAXIS));
+
+ Animation animation = Animation::New(1.0f);
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add(0.0f, Quaternion(Dali::Radian(1.0f), Vector3::ZAXIS));
+ keyframes.Add(1.0f, Quaternion(Dali::Radian(2.0f), Vector3::ZAXIS));
+ animation.AnimateBetween(Property(actor, index), keyframes, AlphaFunction::LINEAR);
+
+ application.SendNotification();
+ application.Render(20);
+
+ animation.SetBlendPoint(0.5f);
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(250);
+
+ Quaternion value = actor.GetCurrentProperty<Quaternion>(index);
+ Vector3 axis;
+ Dali::Radian angle;
+ DALI_TEST_EQUALS(value.ToAxisAngle(axis, angle), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(angle.radian, 1.0f, 0.05f, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(250);
+
+ value = actor.GetCurrentProperty<Quaternion>(index);
+ DALI_TEST_EQUALS(value.ToAxisAngle(axis, angle), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(angle.radian, 1.5f, 0.05f, TEST_LOCATION);
+
+ END_TEST;
+}
PathPtr pathCopy = Path::Clone(path);
- //Position animation
+ // Position animation
AddAnimatorConnector(AnimatorConnector<Vector3>::New(actor,
Dali::Actor::Property::POSITION,
Property::INVALID_COMPONENT_INDEX,
alpha,
period));
- //If forward is zero, PathRotationFunctor will always return the unit quaternion
+ // If forward is zero, PathRotationFunctor will always return the unit quaternion
if(forward != Vector3::ZERO)
{
- //Rotation animation
+ // Rotation animation
AddAnimatorConnector(AnimatorConnector<Quaternion>::New(actor,
Dali::Actor::Property::ORIENTATION,
Property::INVALID_COMPONENT_INDEX,
void Animation::SetPlayRange(const Vector2& range)
{
- //Make sure the range specified is between 0.0 and 1.0
+ // Make sure the range specified is between 0.0 and 1.0
if(range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f)
{
Vector2 orderedRange(range);
- //If the range is not in order swap values
+ // If the range is not in order swap values
if(range.x > range.y)
{
orderedRange = Vector2(range.y, range.x);
return mPlayRange;
}
+void Animation::SetBlendPoint(float blendPoint)
+{
+ if(blendPoint >= 0.0f && blendPoint <= 1.0f)
+ {
+ mBlendPoint = blendPoint;
+ SetBlendPointMessage(mEventThreadServices, *mAnimation, mBlendPoint);
+ }
+ else
+ {
+ DALI_LOG_ERROR("Blend Point should be a value between 0 and 1.\n");
+ }
+}
+
+float Animation::GetBlendPoint() const
+{
+ return mBlendPoint;
+}
+
void Animation::SetLoopingMode(Dali::Animation::LoopingMode loopingMode)
{
mAutoReverseEnabled = (loopingMode == Dali::Animation::LoopingMode::AUTO_REVERSE);
Vector2 GetPlayRange() const;
/**
+ * @copydoc Dali::Animation::SetBlendPoint()
+ */
+ void SetBlendPoint(float blendPoint);
+
+ /**
+ * @copydoc Dali::Animation::GetBlendPoint()
+ */
+ float GetBlendPoint() const;
+
+ /**
* @copydoc Dali::Animation::SetLoopingMode()
*/
void SetLoopingMode(Dali::Animation::LoopingMode loopingMode);
AlphaFunction mDefaultAlpha;
Vector2 mPlayRange{0.0f, 1.0f};
+ float mBlendPoint{0.0f};
float mDurationSeconds;
float mSpeedFactor{1.0f};
int32_t mNotificationCount{0}; ///< Keep track of how many Finished signals have been emitted.
template<typename PropertyType>
class AnimatorConnector : public AnimatorConnectorBase
{
- using AnimatorFunction = std::function<PropertyType(float, const PropertyType&)>;
+ using AnimatorFunction = std::function<PropertyType(float, float, const PropertyType&)>;
AnimatorFunction mAnimatorFunction;
template<>
class AnimatorConnector<float> : public AnimatorConnectorBase
{
- using AnimatorFunction = std::function<float(float, const float&)>;
+ using AnimatorFunction = std::function<float(float, float, const float&)>;
AnimatorFunction mAnimatorFunction;
using KeyFrameNumber = KeyFrameBaseSpec<float>;
using KeyFrameBoolean = KeyFrameBaseSpec<bool>;
-using KeyFrameInteger = KeyFrameBaseSpec<int>;
+using KeyFrameInteger = KeyFrameBaseSpec<int32_t>;
using KeyFrameVector2 = KeyFrameBaseSpec<Vector2>;
using KeyFrameVector3 = KeyFrameBaseSpec<Vector3>;
using KeyFrameVector4 = KeyFrameBaseSpec<Vector4>;
#include <dali/internal/common/memory-pool-object-allocator.h>
#include <dali/internal/render/common/performance-monitor.h>
#include <dali/public-api/math/math-utils.h>
-namespace //Unnamed namespace
+namespace // Unnamed namespace
{
-//Memory pool used to allocate new animations. Memory used by this pool will be released when shutting down DALi
+// Memory pool used to allocate new animations. Memory used by this pool will be released when shutting down DALi
Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Animation>& GetAnimationMemoryPool()
{
static Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Animation> gAnimationMemoryPool;
mElapsedSeconds(playRange.x * mDurationSeconds),
mSpeedFactor(speedFactor),
mProgressMarker(0.0f),
+ mBlendPoint(0.0f),
mPlayedCount(0),
mLoopCount(loopCount),
mCurrentLoop(0),
mProgressReachedSignalRequired(false),
mAutoReverseEnabled(false),
mAnimatorSortRequired(false),
- mIsActive{false}
+ mIsActive{false},
+ mIsFirstLoop{true}
{
}
}
}
+void Animation::SetBlendPoint(float blendPoint)
+{
+ mBlendPoint = blendPoint;
+}
+
void Animation::Play()
{
if(mAnimatorSortRequired)
}
else
{
- mElapsedSeconds = mPlayRange.x * mDurationSeconds - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
+ mElapsedSeconds = mPlayRange.x * mDurationSeconds - Math::MACHINE_EPSILON_1; // Force animation to reach it's beginning
}
}
mElapsedSeconds = mPlayRange.x * mDurationSeconds;
mState = Stopped;
+ mIsFirstLoop = true;
return animationFinished;
}
// Recalculate elapsedFactor here
elapsedFactor = signSpeedFactor * mElapsedSeconds;
+ mIsFirstLoop = false;
if(mLoopCount != 0)
{
// Check If this animation is finished
// After update animation, mElapsedSeconds must be begin of value
mElapsedSeconds = playRangeStartSeconds + playRangeEndSeconds - edgeRangeSeconds;
mState = Stopped;
+ mIsFirstLoop = true;
}
}
bool cleanup = false;
- //Loop through all animators
+ // Loop through all animators
for(auto& animator : mAnimators)
{
if(animator->Orphan())
{
progress = Clamp((elapsedSecondsClamped - intervalDelay) / animatorDuration, 0.0f, 1.0f);
}
- animator->Update(bufferIndex, progress, bake);
+ animator->Update(bufferIndex, progress, mIsFirstLoop ? mBlendPoint : 0.0f, bake);
if(animatorDuration > 0.0f && (elapsedSecondsClamped - intervalDelay) <= animatorDuration)
{
if(cleanup)
{
- //Remove animators whose PropertyOwner has been destroyed
- mAnimators.EraseIf([](auto& animator) { return animator->Orphan(); });
+ // Remove animators whose PropertyOwner has been destroyed
+ mAnimators.EraseIf([](auto& animator)
+ { return animator->Orphan(); });
// Need to be re-sort if remained animators size is bigger than one.
// Note that if animator contains only zero or one items, It is already sorted case.
void SetPlayRange(const Vector2& range);
/**
+ * @brief Sets the blend point to interpolate animate property
+ *
+ * @param[in] blendPoint A value between [0,1], If the value of the keyframe whose progress is 0 is different from the current value,
+ * the property is animated as it smoothly blends until the progress reaches the blendPoint.
+ * @note The blendPoint only affects animation registered with AnimateBetween. Other animations operate the same as when Play() is called.
+ */
+ void SetBlendPoint(float blendPoint);
+
+ /**
* Play the animation.
*/
void Play();
float mElapsedSeconds;
float mSpeedFactor;
float mProgressMarker; // Progress marker to trigger a notification
+ float mBlendPoint;
int32_t mPlayedCount; // Incremented at end of animation or completion of all loops
// Never incremented when looping forever. Event thread tracks to signal end.
bool mAutoReverseEnabled; // Flag to identify that the looping mode is auto reverse.
bool mAnimatorSortRequired; // Flag to whether we need to sort animator or not.
bool mIsActive[2]; // Flag to indicate whether the animation is active in the current frame (which is double buffered)
+ bool mIsFirstLoop;
};
-}; //namespace SceneGraph
+}; // namespace SceneGraph
// value types used by messages
template<>
new(slot) LocalType(&animation, &Animation::SetPlayRange, range);
}
+inline void SetBlendPointMessage(EventThreadServices& eventThreadServices, const Animation& animation, float blendPoint)
+{
+ using LocalType = MessageValue1<Animation, float>;
+
+ // Reserve some memory inside the message queue
+ uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new(slot) LocalType(&animation, &Animation::SetBlendPoint, blendPoint);
+}
+
inline void PlayAnimationMessage(EventThreadServices& eventThreadServices, const Animation& animation)
{
using LocalType = Message<Animation>;
// Construct message in the message queue memory; note that delete should not be called on the return value
new(slot) LocalType(&animation, &Animation::Play);
}
-
inline void PlayAnimationFromMessage(EventThreadServices& eventThreadServices, const Animation& animation, float progress)
{
using LocalType = MessageValue1<Animation, float>;
if(mAnimationPlaying && mDisconnectAction != Dali::Animation::DISCARD)
{
// Bake to target-value if BakeFinal, otherwise bake current value
- Update(bufferIndex, (mDisconnectAction == Dali::Animation::BAKE ? mCurrentProgress : 1.0f), true);
+ Update(bufferIndex, (mDisconnectAction == Dali::Animation::BAKE ? mCurrentProgress : 1.0f), 0.0f, true);
}
mEnabled = false;
}
else
{
- //If progress is very close to 0 or very close to 1 we don't need to evaluate the curve as the result will
- //be almost 0 or almost 1 respectively
+ // If progress is very close to 0 or very close to 1 we don't need to evaluate the curve as the result will
+ // be almost 0 or almost 1 respectively
if((progress > Math::MACHINE_EPSILON_1) && ((1.0f - progress) > Math::MACHINE_EPSILON_1))
{
Dali::Vector4 controlPoints = mAlphaFunction.GetBezierControlPoints();
static const float tolerance = 0.00005f; // 15 iteration max
- //Perform a binary search on the curve
+ // Perform a binary search on the curve
float lowerBound(0.0f);
float upperBound(1.0f);
float currentT(0.5f);
* Update the scene object attached to the animator.
* @param[in] bufferIndex The buffer to animate.
* @param[in] progress A value from 0 to 1, where 0 is the start of the animation, and 1 is the end point.
+ * @param[in] blendPoint A value between [0,1], The Animated property is animated as it blends until the progress reaches the blendPoint.
* @param[in] bake Bake.
*/
- void Update(BufferIndex bufferIndex, float progress, bool bake)
+ void Update(BufferIndex bufferIndex, float progress, float blendPoint, bool bake)
{
if(mLoopCount >= 0)
{
float alpha = ApplyAlphaFunction(progress);
// PropertyType specific part
- DoUpdate(bufferIndex, bake, alpha);
+ DoUpdate(bufferIndex, bake, alpha, blendPoint);
mCurrentProgress = progress;
}
* @param bufferIndex index to use
* @param bake whether to bake or not
* @param alpha value from alpha based on progress
+ * @param blendPoint A value between [0,1], The Animated property is animated as it blends until the progress reaches the blendPoint.
*/
- virtual void DoUpdate(BufferIndex bufferIndex, bool bake, float alpha) = 0;
+ virtual void DoUpdate(BufferIndex bufferIndex, bool bake, float alpha, float blendPoint) = 0;
protected:
/**
template<typename PropertyType, typename PropertyAccessorType>
class Animator final : public AnimatorBase
{
- using AnimatorFunction = std::function<PropertyType(float, const PropertyType&)>;
+ using AnimatorFunction = std::function<PropertyType(float, float, const PropertyType&)>;
AnimatorFunction mAnimatorFunction;
/**
* @copydoc AnimatorBase::DoUpdate( BufferIndex bufferIndex, bool bake, float alpha )
*/
- void DoUpdate(BufferIndex bufferIndex, bool bake, float alpha) final
+ void DoUpdate(BufferIndex bufferIndex, bool bake, float alpha, float blendPoint) final
{
const PropertyType& current = mPropertyAccessor.Get(bufferIndex);
// need to cast the return value in case property is integer
- const PropertyType result = static_cast<PropertyType>(mAnimatorFunction(alpha, current));
+ const PropertyType result = static_cast<PropertyType>(mAnimatorFunction(alpha, blendPoint, current));
if(bake)
{
template<typename PropertyType, typename PropertyAccessorType>
class AnimatorTransformProperty final : public AnimatorBase
{
- using AnimatorFunction = std::function<PropertyType(float, const PropertyType&)>;
+ using AnimatorFunction = std::function<PropertyType(float, float, const PropertyType&)>;
AnimatorFunction mAnimatorFunction;
/**
* @copydoc AnimatorBase::DoUpdate( BufferIndex bufferIndex, bool bake, float alpha )
*/
- void DoUpdate(BufferIndex bufferIndex, bool bake, float alpha) final
+ void DoUpdate(BufferIndex bufferIndex, bool bake, float alpha, float blendPoint) final
{
const PropertyType& current = mPropertyAccessor.Get(bufferIndex);
// need to cast the return value in case property is integer
- const PropertyType result = static_cast<PropertyType>(mAnimatorFunction(alpha, current));
+ const PropertyType result = static_cast<PropertyType>(mAnimatorFunction(alpha, blendPoint, current));
if(bake)
{
}
// Undefined
- AnimatorTransformProperty() = delete;
- AnimatorTransformProperty(const AnimatorTransformProperty&) = delete;
+ AnimatorTransformProperty() = delete;
+ AnimatorTransformProperty(const AnimatorTransformProperty&) = delete;
AnimatorTransformProperty& operator=(const AnimatorTransformProperty&) = delete;
protected:
{
}
- float operator()(float alpha, const int32_t& property)
+ float operator()(float alpha, float blendPoint, const int32_t& property)
{
// integers need to be correctly rounded
return roundf(static_cast<float>(property) + static_cast<float>(mRelative) * alpha);
{
}
- float operator()(float alpha, const int32_t& property)
+ float operator()(float alpha, float blendPoint, const int32_t& property)
{
// integers need to be correctly rounded
return roundf(static_cast<float>(property) + (static_cast<float>(mTarget - property) * alpha));
{
}
- float operator()(float alpha, const float& property)
+ float operator()(float alpha, float blendPoint, const float& property)
{
return float(property + mRelative * alpha);
}
{
}
- float operator()(float alpha, const float& property)
+ float operator()(float alpha, float blendPoint, const float& property)
{
return float(property + ((mTarget - property) * alpha));
}
{
}
- Vector2 operator()(float alpha, const Vector2& property)
+ Vector2 operator()(float alpha, float blendPoint, const Vector2& property)
{
return Vector2(property + mRelative * alpha);
}
{
}
- Vector2 operator()(float alpha, const Vector2& property)
+ Vector2 operator()(float alpha, float blendPoint, const Vector2& property)
{
return Vector2(property + ((mTarget - property) * alpha));
}
{
}
- Vector3 operator()(float alpha, const Vector3& property)
+ Vector3 operator()(float alpha, float blendPoint, const Vector3& property)
{
return Vector3(property + mRelative * alpha);
}
{
}
- Vector3 operator()(float alpha, const Vector3& property)
+ Vector3 operator()(float alpha, float blendPoint, const Vector3& property)
{
return Vector3(property + ((mTarget - property) * alpha));
}
{
}
- Vector4 operator()(float alpha, const Vector4& property)
+ Vector4 operator()(float alpha, float blendPoint, const Vector4& property)
{
return Vector4(property + mRelative * alpha);
}
{
}
- Vector4 operator()(float alpha, const Vector4& property)
+ Vector4 operator()(float alpha, float blendPoint, const Vector4& property)
{
return Vector4(property + ((mTarget - property) * alpha));
}
{
}
- Vector4 operator()(float alpha, const Vector4& property)
+ Vector4 operator()(float alpha, float blendPoint, const Vector4& property)
{
Vector4 result(property);
result.a += mRelative * alpha;
{
}
- Vector4 operator()(float alpha, const Vector4& property)
+ Vector4 operator()(float alpha, float blendPoint, const Vector4& property)
{
Vector4 result(property);
result.a = property.a + ((mTarget - property.a) * alpha);
{
}
- bool operator()(float alpha, const bool& property)
+ bool operator()(float alpha, float blendPoint, const bool& property)
{
// Alpha is not useful here, just keeping to the same template as other update functors
return bool(alpha >= 1.0f ? (property || mRelative) : property);
{
}
- bool operator()(float alpha, const bool& property)
+ bool operator()(float alpha, float blendPoint, const bool& property)
{
// Alpha is not useful here, just keeping to the same template as other update functors
return bool(alpha >= 1.0f ? mTarget : property);
{
}
- Quaternion operator()(float alpha, const Quaternion& rotation)
+ Quaternion operator()(float alpha, float blendPoint, const Quaternion& rotation)
{
if(alpha > 0.0f)
{
{
}
- Quaternion operator()(float alpha, const Quaternion& rotation)
+ Quaternion operator()(float alpha, float blendPoint, const Quaternion& rotation)
{
return Quaternion::Slerp(rotation, mTarget, alpha);
}
{
}
- bool operator()(float progress, const bool& property)
+ bool operator()(float progress, float blendPoint, const bool& property)
{
if(mKeyFrames.IsActive(progress))
{
{
}
- float operator()(float progress, const int32_t& property)
+ int32_t operator()(float progress, float blendPoint, const int32_t& property)
{
if(mKeyFrames.IsActive(progress))
{
- return static_cast<float>(mKeyFrames.GetValue(progress, mInterpolation));
+ if(progress < blendPoint)
+ {
+ float subProgress = progress / blendPoint;
+ float original = static_cast<float>(mKeyFrames.GetValue(progress, mInterpolation));
+ float base = Dali::Lerp(subProgress, static_cast<float>(property), static_cast<float>(mKeyFrames.GetValue(blendPoint, mInterpolation)));
+ return static_cast<int32_t>(Dali::Lerp(subProgress, base, original));
+ }
+ else
+ {
+ return static_cast<int32_t>(mKeyFrames.GetValue(progress, mInterpolation));
+ }
}
- return static_cast<float>(property);
+ return static_cast<int32_t>(property);
}
KeyFrameInteger mKeyFrames;
{
}
- float operator()(float progress, const float& property)
+ float operator()(float progress, float blendPoint, const float& property)
{
if(mKeyFrames.IsActive(progress))
{
- return mKeyFrames.GetValue(progress, mInterpolation);
+ if(progress < blendPoint)
+ {
+ float subProgress = progress / blendPoint;
+ float original = mKeyFrames.GetValue(progress, mInterpolation);
+ float base = Dali::Lerp(subProgress, property, mKeyFrames.GetValue(blendPoint, mInterpolation));
+ return Dali::Lerp(subProgress, base, original);
+ }
+ else
+ {
+ return mKeyFrames.GetValue(progress, mInterpolation);
+ }
}
return property;
}
{
}
- Vector2 operator()(float progress, const Vector2& property)
+ Vector2 operator()(float progress, float blendPoint, const Vector2& property)
{
if(mKeyFrames.IsActive(progress))
{
- return mKeyFrames.GetValue(progress, mInterpolation);
+ if(progress < blendPoint)
+ {
+ float subProgress = progress / blendPoint;
+ Vector2 original = mKeyFrames.GetValue(progress, mInterpolation);
+ Vector2 base = Dali::Lerp(subProgress, property, mKeyFrames.GetValue(blendPoint, mInterpolation));
+ return Dali::Lerp(subProgress, base, original);
+ }
+ else
+ {
+ return mKeyFrames.GetValue(progress, mInterpolation);
+ }
}
return property;
}
{
}
- Vector3 operator()(float progress, const Vector3& property)
+ Vector3 operator()(float progress, float blendPoint, const Vector3& property)
{
if(mKeyFrames.IsActive(progress))
{
- return mKeyFrames.GetValue(progress, mInterpolation);
+ if(progress < blendPoint)
+ {
+ float subProgress = progress / blendPoint;
+ Vector3 original = mKeyFrames.GetValue(progress, mInterpolation);
+ Vector3 base = Dali::Lerp(subProgress, property, mKeyFrames.GetValue(blendPoint, mInterpolation));
+ return Dali::Lerp(subProgress, base, original);
+ }
+ else
+ {
+ return mKeyFrames.GetValue(progress, mInterpolation);
+ }
}
return property;
}
{
}
- Vector4 operator()(float progress, const Vector4& property)
+ Vector4 operator()(float progress, float blendPoint, const Vector4& property)
{
if(mKeyFrames.IsActive(progress))
{
- return mKeyFrames.GetValue(progress, mInterpolation);
+ if(progress < blendPoint)
+ {
+ float subProgress = progress / blendPoint;
+ Vector4 original = mKeyFrames.GetValue(progress, mInterpolation);
+ Vector4 base = Dali::Lerp(subProgress, property, mKeyFrames.GetValue(blendPoint, mInterpolation));
+ return Dali::Lerp(subProgress, base, original);
+ }
+ else
+ {
+ return mKeyFrames.GetValue(progress, mInterpolation);
+ }
}
return property;
}
{
}
- Quaternion operator()(float progress, const Quaternion& property)
+ Quaternion operator()(float progress, float blendPoint, const Quaternion& property)
{
if(mKeyFrames.IsActive(progress))
{
- return mKeyFrames.GetValue(progress, Dali::Animation::LINEAR);
+ if(progress < blendPoint)
+ {
+ float subProgress = progress / blendPoint;
+ Quaternion original = mKeyFrames.GetValue(progress, Dali::Animation::LINEAR);
+ Quaternion base = Quaternion::Slerp(property, mKeyFrames.GetValue(blendPoint, Dali::Animation::LINEAR), subProgress);
+ return Quaternion::Slerp(base, original, subProgress);
+ }
+ else
+ {
+ return mKeyFrames.GetValue(progress, Dali::Animation::LINEAR);
+ }
}
return property;
}
{
}
- Vector3 operator()(float progress, const Vector3& property)
+ Vector3 operator()(float progress, float blendPoint, const Vector3& property)
{
Vector3 position(property);
static_cast<void>(mPath->SamplePosition(progress, position));
mForward.Normalize();
}
- Quaternion operator()(float progress, const Quaternion& property)
+ Quaternion operator()(float progress, float blendPoint, const Quaternion& property)
{
Vector3 tangent;
if(mPath->SampleTangent(progress, tangent))
return GetImplementation(*this).GetPlayRange();
}
+void Animation::SetBlendPoint(float blendPoint)
+{
+ GetImplementation(*this).SetBlendPoint(blendPoint);
+}
+
+float Animation::GetBlendPoint() const
+{
+ return GetImplementation(*this).GetBlendPoint();
+}
+
} // namespace Dali
public:
using AnimationSignalType = Signal<void(Animation&)>; ///< Animation finished signal type @SINCE_1_0.0
- using AnyFunction = Any; ///< Interpolation function @SINCE_1_0.0
+ using AnyFunction = Any; ///< Interpolation function @SINCE_1_0.0
/**
* @brief Enumeration for what to do when the animation ends, is stopped, or is destroyed.
void SetCurrentProgress(float progress);
/**
- * @brief Retrieves the current progress of the animation.
- *
- * @SINCE_1_0.0
- * @return The current progress as a normalized value between [0,1]
- */
+ * @brief Retrieves the current progress of the animation.
+ *
+ * @SINCE_1_0.0
+ * @return The current progress as a normalized value between [0,1]
+ */
float GetCurrentProgress();
/**
Vector2 GetPlayRange() const;
/**
+ * @brief Sets the blend point to interpolate animate property
+ *
+ * @SINCE_2_2.26
+ * @param[in] blendPoint A value between [0,1], If the value of the keyframe whose progress is 0 is different from the current value,
+ * the property is animated as it smoothly blends until the progress reaches the blendPoint.
+ * @note The blend point only affects animation registered with AnimateBetween. Other animations operate the same as when Play() is called.
+ * And the blend point needs to be set before this animation plays. If the blend point changes after playback, animation continuity cannot be guaranteed.
+ * @note In the case of a looping animation, the animation is blended only in the first loop.
+ */
+ void SetBlendPoint(float blendPoint);
+
+ /**
+ * @brief Gets the Blend Point
+ *
+ * @SINCE_2_2.26
+ * @return The blend point to interpolate animate property
+ */
+ float GetBlendPoint() const;
+
+ /**
* @brief Play the animation.
* @SINCE_1_0.0
*/