18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "track_animation.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <meta/ext/serialization/serializer.h>
198bf80f4bSopenharmony_ci
208bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
218bf80f4bSopenharmony_ci
228bf80f4bSopenharmony_cinamespace Internal {
238bf80f4bSopenharmony_ci
248bf80f4bSopenharmony_ciAnimationState::AnimationStateParams TrackAnimation::GetParams()
258bf80f4bSopenharmony_ci{
268bf80f4bSopenharmony_ci    AnimationState::AnimationStateParams params;
278bf80f4bSopenharmony_ci    params.owner = GetSelf<IAnimation>();
288bf80f4bSopenharmony_ci    params.runningProperty = META_ACCESS_PROPERTY(Running);
298bf80f4bSopenharmony_ci    params.progressProperty = META_ACCESS_PROPERTY(Progress);
308bf80f4bSopenharmony_ci    params.totalDuration = META_ACCESS_PROPERTY(TotalDuration);
318bf80f4bSopenharmony_ci    return params;
328bf80f4bSopenharmony_ci}
338bf80f4bSopenharmony_ci
348bf80f4bSopenharmony_cibool TrackAnimation::Build(const IMetadata::Ptr& data)
358bf80f4bSopenharmony_ci{
368bf80f4bSopenharmony_ci    if (Super::Build(data)) {
378bf80f4bSopenharmony_ci        TrackAnimationState::TrackDataParams params { META_ACCESS_PROPERTY(Timestamps) };
388bf80f4bSopenharmony_ci        GetState().SetTrackDataParams(BASE_NS::move(params));
398bf80f4bSopenharmony_ci
408bf80f4bSopenharmony_ci        auto updateKf = MakeCallback<IOnChanged>(this, &TrackAnimation::UpdateKeyframes);
418bf80f4bSopenharmony_ci
428bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Timestamps)->OnChanged()->AddHandler(updateKf);
438bf80f4bSopenharmony_ci        constexpr BASE_NS::string_view name = "Keyframes";
448bf80f4bSopenharmony_ci        keyframes_ = GetObjectRegistry().GetPropertyRegister().Create(ClassId::StackProperty, name);
458bf80f4bSopenharmony_ci        if (keyframes_) {
468bf80f4bSopenharmony_ci            keyframes_->OnChanged()->AddHandler(updateKf);
478bf80f4bSopenharmony_ci            AddProperty(keyframes_);
488bf80f4bSopenharmony_ci        }
498bf80f4bSopenharmony_ci        UpdateKeyframes();
508bf80f4bSopenharmony_ci        return keyframes_ != nullptr;
518bf80f4bSopenharmony_ci    }
528bf80f4bSopenharmony_ci    return false;
538bf80f4bSopenharmony_ci}
548bf80f4bSopenharmony_ci
558bf80f4bSopenharmony_civoid TrackAnimation::Initialize()
568bf80f4bSopenharmony_ci{
578bf80f4bSopenharmony_ci    ResetTrack();
588bf80f4bSopenharmony_ci}
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_civoid TrackAnimation::OnAnimationStateChanged(const IAnimationInternal::AnimationStateChangedInfo& info)
618bf80f4bSopenharmony_ci{
628bf80f4bSopenharmony_ci    using AnimationTargetState = IAnimationInternal::AnimationTargetState;
638bf80f4bSopenharmony_ci    if (auto p = GetTargetProperty()) {
648bf80f4bSopenharmony_ci        switch (info.state) {
658bf80f4bSopenharmony_ci            case AnimationTargetState::FINISHED:
668bf80f4bSopenharmony_ci                [[fallthrough]];
678bf80f4bSopenharmony_ci            case AnimationTargetState::STOPPED:
688bf80f4bSopenharmony_ci                // Evaluate current value
698bf80f4bSopenharmony_ci                Evaluate();
708bf80f4bSopenharmony_ci                // Remove ourselves from the target property's stack
718bf80f4bSopenharmony_ci                RemoveModifier(p.stack);
728bf80f4bSopenharmony_ci                // Then set the correct keyframe value to the underlying property
738bf80f4bSopenharmony_ci                if (auto value = GetState().GetCurrentValue()) {
748bf80f4bSopenharmony_ci                    p.property->SetValue(*value);
758bf80f4bSopenharmony_ci                }
768bf80f4bSopenharmony_ci                break;
778bf80f4bSopenharmony_ci            case AnimationTargetState::RUNNING:
788bf80f4bSopenharmony_ci                // Evaluate current value
798bf80f4bSopenharmony_ci                Evaluate();
808bf80f4bSopenharmony_ci                // Add ourselves to the target property's stack
818bf80f4bSopenharmony_ci                p.stack->AddModifier(GetSelf<IModifier>());
828bf80f4bSopenharmony_ci                break;
838bf80f4bSopenharmony_ci            default:
848bf80f4bSopenharmony_ci                break;
858bf80f4bSopenharmony_ci        }
868bf80f4bSopenharmony_ci    }
878bf80f4bSopenharmony_ci}
888bf80f4bSopenharmony_ci
898bf80f4bSopenharmony_ciEvaluationResult TrackAnimation::ProcessOnGet(IAny& value)
908bf80f4bSopenharmony_ci{
918bf80f4bSopenharmony_ci    if (auto& currentValue = GetState().GetCurrentValue()) {
928bf80f4bSopenharmony_ci        if (auto result = value.CopyFrom(*currentValue)) {
938bf80f4bSopenharmony_ci            return result == AnyReturn::NOTHING_TO_DO ? EvaluationResult::EVAL_CONTINUE
948bf80f4bSopenharmony_ci                                                      : EvaluationResult::EVAL_VALUE_CHANGED;
958bf80f4bSopenharmony_ci        }
968bf80f4bSopenharmony_ci    }
978bf80f4bSopenharmony_ci    return EvaluationResult::EVAL_CONTINUE;
988bf80f4bSopenharmony_ci}
998bf80f4bSopenharmony_ci
1008bf80f4bSopenharmony_civoid TrackAnimation::Start()
1018bf80f4bSopenharmony_ci{
1028bf80f4bSopenharmony_ci    GetState().Start();
1038bf80f4bSopenharmony_ci}
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_civoid TrackAnimation::Stop()
1068bf80f4bSopenharmony_ci{
1078bf80f4bSopenharmony_ci    GetState().Stop();
1088bf80f4bSopenharmony_ci}
1098bf80f4bSopenharmony_ci
1108bf80f4bSopenharmony_civoid TrackAnimation::Pause()
1118bf80f4bSopenharmony_ci{
1128bf80f4bSopenharmony_ci    GetState().Pause();
1138bf80f4bSopenharmony_ci}
1148bf80f4bSopenharmony_ci
1158bf80f4bSopenharmony_civoid TrackAnimation::Restart()
1168bf80f4bSopenharmony_ci{
1178bf80f4bSopenharmony_ci    GetState().Restart();
1188bf80f4bSopenharmony_ci}
1198bf80f4bSopenharmony_ci
1208bf80f4bSopenharmony_civoid TrackAnimation::Finish()
1218bf80f4bSopenharmony_ci{
1228bf80f4bSopenharmony_ci    GetState().Finish();
1238bf80f4bSopenharmony_ci}
1248bf80f4bSopenharmony_ci
1258bf80f4bSopenharmony_civoid TrackAnimation::Seek(float position)
1268bf80f4bSopenharmony_ci{
1278bf80f4bSopenharmony_ci    GetState().Seek(position);
1288bf80f4bSopenharmony_ci}
1298bf80f4bSopenharmony_ci
1308bf80f4bSopenharmony_civoid TrackAnimation::Step(const IClock::ConstPtr& clock)
1318bf80f4bSopenharmony_ci{
1328bf80f4bSopenharmony_ci    GetState().Step(clock);
1338bf80f4bSopenharmony_ci}
1348bf80f4bSopenharmony_ci
1358bf80f4bSopenharmony_civoid TrackAnimation::Evaluate()
1368bf80f4bSopenharmony_ci{
1378bf80f4bSopenharmony_ci    float progress = META_ACCESS_PROPERTY_VALUE(Progress);
1388bf80f4bSopenharmony_ci    if (auto curve = META_ACCESS_PROPERTY_VALUE(Curve)) {
1398bf80f4bSopenharmony_ci        progress = curve->Transform(progress);
1408bf80f4bSopenharmony_ci    }
1418bf80f4bSopenharmony_ci    const auto trackState = GetState().UpdateIndex(progress);
1428bf80f4bSopenharmony_ci    const PropertyAnimationState::EvaluationData data { GetState().GetCurrentValue(), GetState().GetCurrentTrackStart(),
1438bf80f4bSopenharmony_ci        GetState().GetCurrentTrackEnd(), trackState.second,
1448bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(KeyframeCurves)->GetValueAt(trackState.first) };
1458bf80f4bSopenharmony_ci    const auto status = GetState().EvaluateValue(data);
1468bf80f4bSopenharmony_ci    UpdateCurrentTrack(trackState.first);
1478bf80f4bSopenharmony_ci    if (status == AnyReturn::SUCCESS) {
1488bf80f4bSopenharmony_ci        NotifyChanged();
1498bf80f4bSopenharmony_ci    }
1508bf80f4bSopenharmony_ci}
1518bf80f4bSopenharmony_ci
1528bf80f4bSopenharmony_civoid TrackAnimation::RemoveModifier(const IStackProperty::Ptr& stack)
1538bf80f4bSopenharmony_ci{
1548bf80f4bSopenharmony_ci    if (stack) {
1558bf80f4bSopenharmony_ci        stack->RemoveModifier(GetSelf<IModifier>());
1568bf80f4bSopenharmony_ci    }
1578bf80f4bSopenharmony_ci}
1588bf80f4bSopenharmony_ci
1598bf80f4bSopenharmony_civoid TrackAnimation::OnPropertyChanged(const TargetProperty& property, const IStackProperty::Ptr& previous)
1608bf80f4bSopenharmony_ci{
1618bf80f4bSopenharmony_ci    if (previous && GetState().IsRunning()) {
1628bf80f4bSopenharmony_ci        // Property changed while running, clean up previous property's stack
1638bf80f4bSopenharmony_ci        RemoveModifier(previous);
1648bf80f4bSopenharmony_ci        if (auto p = interface_cast<IProperty>(previous)) {
1658bf80f4bSopenharmony_ci            p->SetValue(*GetState().GetCurrentValue());
1668bf80f4bSopenharmony_ci        }
1678bf80f4bSopenharmony_ci    }
1688bf80f4bSopenharmony_ci
1698bf80f4bSopenharmony_ci    Initialize();
1708bf80f4bSopenharmony_ci
1718bf80f4bSopenharmony_ci    if (auto p = GetTargetProperty()) {
1728bf80f4bSopenharmony_ci        auto& property = p.property;
1738bf80f4bSopenharmony_ci        auto& value = property->GetValue();
1748bf80f4bSopenharmony_ci        bool alreadyCompatible = value.GetTypeId() == GetState().GetKeyframeItemTypeId();
1758bf80f4bSopenharmony_ci        if (!alreadyCompatible) {
1768bf80f4bSopenharmony_ci            IAny::Ptr array {};
1778bf80f4bSopenharmony_ci            if (!value.IsArray()) {
1788bf80f4bSopenharmony_ci                // Clone the target property's value to an array of the value's underlying type
1798bf80f4bSopenharmony_ci                array = value.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ARRAY });
1808bf80f4bSopenharmony_ci            } else {
1818bf80f4bSopenharmony_ci                CORE_LOG_E("TrackAnimation: Cannot animate array types");
1828bf80f4bSopenharmony_ci            }
1838bf80f4bSopenharmony_ci            if (!array) {
1848bf80f4bSopenharmony_ci                CORE_LOG_E("TrackAnimation: Failed to create an array of target property type");
1858bf80f4bSopenharmony_ci            }
1868bf80f4bSopenharmony_ci            if (auto kf = interface_pointer_cast<IArrayAny>(array)) {
1878bf80f4bSopenharmony_ci                keyframes_->SetValue(*kf);
1888bf80f4bSopenharmony_ci            } else {
1898bf80f4bSopenharmony_ci                keyframes_->ResetValue();
1908bf80f4bSopenharmony_ci            }
1918bf80f4bSopenharmony_ci        }
1928bf80f4bSopenharmony_ci    }
1938bf80f4bSopenharmony_ci
1948bf80f4bSopenharmony_ci    UpdateValid();
1958bf80f4bSopenharmony_ci}
1968bf80f4bSopenharmony_ci
1978bf80f4bSopenharmony_cisize_t TrackAnimation::AddKeyframe(float timestamp, const IAny::ConstPtr& value)
1988bf80f4bSopenharmony_ci{
1998bf80f4bSopenharmony_ci    auto index = GetState().AddKeyframe(timestamp, value);
2008bf80f4bSopenharmony_ci    if (index != ITrackAnimation::INVALID_INDEX) {
2018bf80f4bSopenharmony_ci        keyframes_->NotifyChange();
2028bf80f4bSopenharmony_ci    }
2038bf80f4bSopenharmony_ci    return index;
2048bf80f4bSopenharmony_ci}
2058bf80f4bSopenharmony_ci
2068bf80f4bSopenharmony_cibool TrackAnimation::RemoveKeyframe(size_t index)
2078bf80f4bSopenharmony_ci{
2088bf80f4bSopenharmony_ci    bool success = false;
2098bf80f4bSopenharmony_ci    if (GetState().RemoveKeyframe(index)) {
2108bf80f4bSopenharmony_ci        keyframes_->NotifyChange();
2118bf80f4bSopenharmony_ci        success = true;
2128bf80f4bSopenharmony_ci    } else {
2138bf80f4bSopenharmony_ci        CORE_LOG_E("TrackAnimation: Cannot remove keyframe from index %u.", static_cast<uint32_t>(index));
2148bf80f4bSopenharmony_ci    }
2158bf80f4bSopenharmony_ci    return success;
2168bf80f4bSopenharmony_ci}
2178bf80f4bSopenharmony_ci
2188bf80f4bSopenharmony_civoid TrackAnimation::RemoveAllKeyframes()
2198bf80f4bSopenharmony_ci{
2208bf80f4bSopenharmony_ci    Stop();
2218bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(Timestamps)->Reset();
2228bf80f4bSopenharmony_ci    keyframes_->ResetValue();
2238bf80f4bSopenharmony_ci    UpdateValid();
2248bf80f4bSopenharmony_ci}
2258bf80f4bSopenharmony_ci
2268bf80f4bSopenharmony_civoid TrackAnimation::UpdateKeyframes()
2278bf80f4bSopenharmony_ci{
2288bf80f4bSopenharmony_ci    IArrayAny::Ptr kfArray;
2298bf80f4bSopenharmony_ci    if (auto stack = interface_cast<IStackProperty>(keyframes_)) {
2308bf80f4bSopenharmony_ci        // Get the topmost IArrayAny value, that should be our keyframe array
2318bf80f4bSopenharmony_ci        auto values = stack->GetValues({}, true);
2328bf80f4bSopenharmony_ci        for (auto it = values.rbegin(); it != values.rend(); ++it) {
2338bf80f4bSopenharmony_ci            if (auto arr = interface_pointer_cast<IArrayAny>(*it)) {
2348bf80f4bSopenharmony_ci                kfArray = arr;
2358bf80f4bSopenharmony_ci                break;
2368bf80f4bSopenharmony_ci            }
2378bf80f4bSopenharmony_ci        }
2388bf80f4bSopenharmony_ci    }
2398bf80f4bSopenharmony_ci    GetState().SetKeyframes(kfArray);
2408bf80f4bSopenharmony_ci    UpdateValid();
2418bf80f4bSopenharmony_ci}
2428bf80f4bSopenharmony_ci
2438bf80f4bSopenharmony_civoid TrackAnimation::UpdateValid()
2448bf80f4bSopenharmony_ci{
2458bf80f4bSopenharmony_ci    bool valid = false;
2468bf80f4bSopenharmony_ci    auto& timestamps = META_ACCESS_PROPERTY(Timestamps);
2478bf80f4bSopenharmony_ci
2488bf80f4bSopenharmony_ci    if (const auto p = GetTargetProperty(); p && timestamps) {
2498bf80f4bSopenharmony_ci        valid = GetState().UpdateValid();
2508bf80f4bSopenharmony_ci    }
2518bf80f4bSopenharmony_ci
2528bf80f4bSopenharmony_ci    if (valid != META_ACCESS_PROPERTY_VALUE(Valid)) {
2538bf80f4bSopenharmony_ci        if (!valid) {
2548bf80f4bSopenharmony_ci            Stop();
2558bf80f4bSopenharmony_ci            ResetTrack();
2568bf80f4bSopenharmony_ci        }
2578bf80f4bSopenharmony_ci        SetValue(META_ACCESS_PROPERTY(Valid), valid);
2588bf80f4bSopenharmony_ci    }
2598bf80f4bSopenharmony_ci
2608bf80f4bSopenharmony_ci    GetState().ResetCurrentTrack();
2618bf80f4bSopenharmony_ci}
2628bf80f4bSopenharmony_ci
2638bf80f4bSopenharmony_civoid TrackAnimation::ResetTrack()
2648bf80f4bSopenharmony_ci{
2658bf80f4bSopenharmony_ci    GetState().ResetCurrentTrack();
2668bf80f4bSopenharmony_ci    SetValue(META_ACCESS_PROPERTY(CurrentKeyframeIndex), -1);
2678bf80f4bSopenharmony_ci}
2688bf80f4bSopenharmony_ci
2698bf80f4bSopenharmony_civoid TrackAnimation::UpdateCurrentTrack(uint32_t index)
2708bf80f4bSopenharmony_ci{
2718bf80f4bSopenharmony_ci    auto currentIndex = META_ACCESS_PROPERTY_VALUE(CurrentKeyframeIndex);
2728bf80f4bSopenharmony_ci    if (currentIndex != index) {
2738bf80f4bSopenharmony_ci        SetValue(META_ACCESS_PROPERTY(CurrentKeyframeIndex), index);
2748bf80f4bSopenharmony_ci        if (auto f = META_ACCESS_PROPERTY(KeyframeHandlers)->GetValueAt(index)) {
2758bf80f4bSopenharmony_ci            CallMetaFunction<void>(f);
2768bf80f4bSopenharmony_ci        }
2778bf80f4bSopenharmony_ci    }
2788bf80f4bSopenharmony_ci}
2798bf80f4bSopenharmony_ci
2808bf80f4bSopenharmony_ciReturnError TrackAnimation::Export(IExportContext& c) const
2818bf80f4bSopenharmony_ci{
2828bf80f4bSopenharmony_ci    return Serializer(c) & AutoSerialize() & NamedValue("Keyframes", keyframes_);
2838bf80f4bSopenharmony_ci}
2848bf80f4bSopenharmony_ciReturnError TrackAnimation::Import(IImportContext& c)
2858bf80f4bSopenharmony_ci{
2868bf80f4bSopenharmony_ci    return Serializer(c) & AutoSerialize() & NamedValue("Keyframes", keyframes_);
2878bf80f4bSopenharmony_ci}
2888bf80f4bSopenharmony_ciReturnError TrackAnimation::Finalize(IImportFunctions& f)
2898bf80f4bSopenharmony_ci{
2908bf80f4bSopenharmony_ci    auto res = Super::Finalize(f);
2918bf80f4bSopenharmony_ci    if (res) {
2928bf80f4bSopenharmony_ci        UpdateKeyframes();
2938bf80f4bSopenharmony_ci    }
2948bf80f4bSopenharmony_ci    return res;
2958bf80f4bSopenharmony_ci}
2968bf80f4bSopenharmony_ci} // namespace Internal
2978bf80f4bSopenharmony_ci
2988bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
299