1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#ifndef SCENE_PLUGIN_ECS_ANIMATION_H
16#define SCENE_PLUGIN_ECS_ANIMATION_H
17
18#undef InterlockedIncrement
19#undef InterlockedDecrement
20
21#include <optional>
22#include <scene_plugin/interface/intf_ecs_animation.h>
23
24#include <3d/ecs/components/animation_component.h>
25#include <3d/ecs/components/animation_input_component.h>
26#include <3d/ecs/components/animation_output_component.h>
27#include <3d/ecs/components/animation_track_component.h>
28#include <3d/ecs/components/name_component.h>
29#include <core/ecs/intf_component_manager.h>
30#include <core/ecs/intf_ecs.h>
31
32#include <meta/base/shared_ptr.h>
33#include <meta/ext/animation/interpolator.h>
34#include <meta/ext/attachment/attachment.h>
35#include <meta/ext/object_container.h>
36#include <meta/ext/event_impl.h>
37#include <meta/interface/animation/builtin_animations.h>
38#include <meta/interface/intf_container.h>
39
40#include "scene_holder.h"
41
42SCENE_BEGIN_NAMESPACE()
43
44class EcsTrackAnimation final : public META_NS::ObjectFwd<EcsTrackAnimation, ClassId::EcsTrackAnimation, META_NS::ClassId::Object,
45          IEcsTrackAnimation, META_NS::IStartableAnimation, META_NS::ITrackAnimation, META_NS::IPropertyAnimation,
46          META_NS::IContainable, META_NS::IMutableContainable, SCENE_NS::IEcsProxyObject, META_NS::ITimedAnimation> {
47public:
48    // From INamed
49    META_IMPLEMENT_PROPERTY(BASE_NS::string, Name)
50
51    // From ITrackAnimation
52    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(ITrackAnimation, float, Timestamps, {})
53    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(ITrackAnimation, META_NS::IFunction::Ptr, KeyframeHandlers)
54    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(ITrackAnimation, uint32_t, CurrentKeyframeIndex, -1)
55    META_IMPLEMENT_INTERFACE_PROPERTY(IPropertyAnimation, META_NS::IProperty::WeakPtr, Property, {})
56    META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(ITrackAnimation, META_NS::ICurve1D::Ptr, KeyframeCurves, {})
57    META_NS::IProperty::Ptr Keyframes() const override;
58    size_t AddKeyframe(float timestamp, const META_NS::IAny::ConstPtr& value) override;
59    bool RemoveKeyframe(size_t index) override;
60    void RemoveAllKeyframes() override;
61
62    // From IAnimation
63    META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, bool, Enabled, true)
64    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Valid, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
65    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, META_NS::TimeSpan, TotalDuration,
66        META_NS::TimeSpan::Milliseconds(500), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
67    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Running, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
68    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, float, Progress, 0, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
69    META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, META_NS::ICurve1D::Ptr, Curve)
70    META_IMPLEMENT_INTERFACE_PROPERTY(
71        IAnimation, META_NS::IAnimationController::WeakPtr, Controller, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
72
73    // From IAnimationWithModifiableDuration
74    META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, META_NS::TimeSpan, Duration, META_NS::TimeSpan::Milliseconds(500))
75
76    bool Build(const META_NS::IMetadata::Ptr& data) override;
77
78    void Seek(float position) override;
79    void Step(const META_NS::IClock::ConstPtr& clock) override;
80    void Start() override;
81    void Stop() override;
82    void Pause() override;
83    void Restart() override;
84    void Finish() override;
85
86    META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnFinished)
87    META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnStarted)
88
89    void SetEntity(CORE_NS::Entity entity) override
90    {
91        entity_ = entity;
92        if (auto ecsListener = ecsListener_.lock()) {
93            if (auto animationTrackManager =
94                    CORE_NS::GetManager<CORE3D_NS::IAnimationTrackComponentManager>(*ecsListener->ecs_)) {
95                ecsListener->AddEntity(entity, GetSelf<SCENE_NS::IEcsProxyObject>(), *animationTrackManager);
96            }
97            if (auto animationInputManager =
98                    CORE_NS::GetManager<CORE3D_NS::IAnimationInputComponentManager>(*ecsListener->ecs_)) {
99                ecsListener->AddEntity(entity, GetSelf<SCENE_NS::IEcsProxyObject>(), *animationInputManager);
100            }
101        }
102    }
103
104public: // from IEcsProxyObject
105    void SetCommonListener(BASE_NS::shared_ptr<SCENE_NS::EcsListener> ecsListener) override
106    {
107        ecsListener_ = ecsListener;
108    }
109
110    void DoEntityEvent(CORE_NS::IEcs::EntityListener::EventType type, const CORE_NS::Entity& entity) override
111    {
112        if (auto parent = interface_pointer_cast<SCENE_NS::IEcsProxyObject>(GetParent())) {
113            parent->DoEntityEvent(type, entity);
114        }
115    }
116
117    void DoComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type,
118        const CORE_NS::IComponentManager& componentManager, const CORE_NS::Entity& entity) override
119    {
120        if (auto parent = interface_pointer_cast<SCENE_NS::IEcsProxyObject>(GetParent())) {
121            parent->DoComponentEvent(type, componentManager, entity);
122        }
123    }
124
125    CORE_NS::Entity GetEntity() const override
126    {
127        return entity_;
128    }
129
130    void SetSuperInstance(const IObject::Ptr& aggr, const IObject::Ptr& super) override
131    {
132        ObjectFwd::SetSuperInstance(aggr, super);
133        containable_ = interface_cast<IContainable>(super);
134        mutableContainable_ = interface_cast<IMutableContainable>(super);
135    }
136
137    void SetParent(const IObject::Ptr& parent) override
138    {
139        if (mutableContainable_) {
140            mutableContainable_->SetParent(parent);
141        } else {
142            parent_ = parent;
143        }
144    }
145
146    IObject::Ptr GetParent() const override
147    {
148        if (containable_) {
149            return containable_->GetParent();
150        }
151        return parent_.lock();
152    }
153
154    void Destroy() override
155    {
156        if (auto ecsListener = ecsListener_.lock()) {
157            if (!ecsListener->ecs_) {
158                return;
159            }
160            if (auto animationTrackManager =
161                    CORE_NS::GetManager<CORE3D_NS::IAnimationTrackComponentManager>(*ecsListener->ecs_)) {
162                ecsListener->RemoveEntity(entity_, GetSelf<SCENE_NS::IEcsProxyObject>(), *animationTrackManager);
163            }
164            if (auto animationInputManager =
165                    CORE_NS::GetManager<CORE3D_NS::IAnimationInputComponentManager>(*ecsListener->ecs_)) {
166                ecsListener->RemoveEntity(entity_, GetSelf<SCENE_NS::IEcsProxyObject>(), *animationInputManager);
167            }
168        }
169    }
170
171private:
172    CORE_NS::Entity entity_;
173    BASE_NS::string name_;
174    META_NS::IProperty::Ptr keyframes_;
175
176    mutable META_NS::EventImpl<META_NS::IOnChanged> onFinished_;
177    mutable META_NS::EventImpl<META_NS::IOnChanged> onStarted_;
178
179    BASE_NS::weak_ptr<SCENE_NS::EcsListener> ecsListener_;
180    META_NS::IContainable* containable_ {};
181    META_NS::IMutableContainable* mutableContainable_ {};
182    META_NS::IObject::WeakPtr parent_;
183};
184
185class EcsAnimation final : public META_NS::ObjectContainerFwd<EcsAnimation, ClassId::EcsAnimation, IEcsAnimation,
186                                META_NS::IParallelAnimation, META_NS::ITimedAnimation, META_NS::IStartableAnimation,
187                               SCENE_NS::IEcsProxyObject, META_NS::IAttachment> {
188public:
189    // From IEcsAnimation
190    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(
191        IEcsAnimation, bool, ReadOnly, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
192
193    // From INamed
194    META_IMPLEMENT_INTERFACE_PROPERTY(INamed, BASE_NS::string, Name, {})
195
196    // From IAnimation
197    META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, bool, Enabled, true)
198    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Valid, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
199    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, META_NS::TimeSpan, TotalDuration,
200        META_NS::TimeSpan::Milliseconds(500), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
201    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Running, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
202    META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, float, Progress, 0, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
203    META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, META_NS::ICurve1D::Ptr, Curve)
204    META_IMPLEMENT_INTERFACE_PROPERTY(
205        IAnimation, META_NS::IAnimationController::WeakPtr, Controller, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
206    META_IMPLEMENT_READONLY_PROPERTY(META_NS::IObject::WeakPtr, DataContext)
207    META_IMPLEMENT_READONLY_PROPERTY(META_NS::IAttach::WeakPtr, AttachedTo)
208
209    META_IMPLEMENT_INTERFACE_PROPERTY(
210        ITimedAnimation, META_NS::TimeSpan, Duration, META_NS::TimeSpan::Milliseconds(500))
211
212    void AddAnimation(const IAnimation::Ptr&) override;
213    void RemoveAnimation(const IAnimation::Ptr&) override;
214
215    BASE_NS::vector<IAnimation::Ptr> GetAnimations() const override;
216
217public:
218    void SetSceneHolder(SceneHolder::Ptr& sceneHolder)
219    {
220        sceneHolder_ = sceneHolder;
221        SetCommonListener(sceneHolder->GetCommonEcsListener());
222    }
223
224    SceneHolder::Ptr GetSceneHolder()
225    {
226        return sceneHolder_.lock();
227    }
228
229    // from IEcsProxyObject
230    void SetCommonListener(BASE_NS::shared_ptr<SCENE_NS::EcsListener> ecsListener) override
231    {
232        ecsListener_ = ecsListener;
233    }
234    void DoEntityEvent(CORE_NS::IEcs::EntityListener::EventType, const CORE_NS::Entity& entity) override {}
235    void DoComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type,
236        const CORE_NS::IComponentManager& componentManager, const CORE_NS::Entity& entity) override;
237
238    // From Object
239    BASE_NS::string GetName() const override;
240
241    bool SetRootEntity(CORE_NS::Entity entity) override;
242    CORE_NS::Entity GetRootEntity() const override;
243
244    void SetEntity(CORE_NS::IEcs& ecs, CORE_NS::Entity entity) override;
245    CORE_NS::Entity GetEntity() const override;
246
247    void SetDuration(uint32_t ms) override;
248
249    bool Retarget(CORE_NS::Entity entity) override;
250
251    void Seek(float position) override;
252    void Step(const META_NS::IClock::ConstPtr& clock) override;
253    void Start() override;
254    void Stop() override;
255    void Pause() override;
256    void Restart() override;
257    void Finish() override;
258
259    META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnFinished)
260    META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnStarted)
261
262    void AddKey(IEcsTrackAnimation::Ptr track, float time) override;
263    void RemoveKey(IEcsTrackAnimation::Ptr track, uint32_t index) override;
264    void UpdateKey(IEcsTrackAnimation::Ptr track, uint32_t oldKeyIndex, uint32_t newKeyIndex, float time) override;
265
266    IEcsTrackAnimation::Ptr CreateAnimationTrack(
267        CORE_NS::Entity rootEntity, CORE_NS::Entity target, BASE_NS::string_view property) override;
268    IEcsTrackAnimation::Ptr GetAnimationTrack(CORE_NS::Entity target, BASE_NS::string_view property) override;
269    void DestroyAnimationTrack(IEcsTrackAnimation::Ptr track) override;
270    void DestroyAllAnimationTracks() override;
271    void Destroy() override;
272
273    BASE_NS::vector<CORE_NS::EntityReference> GetAllRelatedEntities() const override;
274
275public: // ISerialization
276    //todo
277    //bool Export(
278    //    META_NS::Serialization::IExportContext& context, META_NS::Serialization::ClassPrimitive& value) const override;
279
280    //bool Import(
281    //    META_NS::Serialization::IImportContext& context, const META_NS::Serialization::ClassPrimitive& value) override;
282
283    /**
284     * @brief Called by the framework when an the attachment is being attached to an IObject. If this
285     *        function succeeds, the object is attached to the target.
286     * @param object The IObject instance the attachment is attached to.
287     * @param dataContext The data context for this attachment.
288     * @note The data context can be the same object as the object being attached to, or
289     *       something else. It is up to the attachment to decide how to handle them.
290     * @return The implementation should return true if the attachment can be attached to target object.
291     *         If the attachment cannot be added, the implementation should return false.
292     */
293    bool Attaching(const IAttach::Ptr& target, const IObject::Ptr& dataContext) override
294    {
295        META_ACCESS_PROPERTY(AttachedTo)->SetValue(target);
296        META_ACCESS_PROPERTY(DataContext)->SetValue(dataContext);
297        return true;
298    }
299    /**
300     * @brief Detach the attachment from an object.
301     * @param object The object to attach to.
302     * @return If the attachment can be detached from the target, the implementation should return true.
303     *         If detaching is not possible, the implementation should return false. In such a case the
304     *         target may choose to not remove the attachment. During for example object destruction,
305     *         the target will ignore the return value.
306     */
307    bool Detaching(const IAttach::Ptr& target) override
308    {
309        META_ACCESS_PROPERTY(AttachedTo)->SetValue({});
310        META_ACCESS_PROPERTY(DataContext)->SetValue({});
311        return true;
312    }
313
314protected:
315    bool Build(const META_NS::IMetadata::Ptr& data) override;
316
317private:
318    struct Data {
319        inline explicit operator bool()
320        {
321            return (property != nullptr) && !data.empty();
322        };
323
324        const CORE_NS::PropertyTypeDecl* property { nullptr };
325        BASE_NS::vector<uint8_t> data;
326    };
327
328    CORE_NS::Entity TryResolveAnimationRoot();
329
330    Data GetProperty(BASE_NS::Uid componentUid, CORE_NS::Entity entity, BASE_NS::string property) const;
331    void SetKeyFrameData(CORE_NS::Entity animationTrack, float timeStamp, BASE_NS::vector<uint8_t> valueData);
332    void UpdateTimestamps(IEcsTrackAnimation& track, CORE_NS::Entity timestampEntity);
333
334    // Return the highest timestamp from the keyframes of the animation track.
335    float GetTrackDuration(CORE_NS::Entity animationTrack);
336    void UpdateAnimationTrackDuration(CORE_NS::Entity animationTrack);
337
338    void SetProgress(float progress);
339    void SetTime(uint32_t value);
340
341    void OnDestroyAnimationTrack(IEcsTrackAnimation::Ptr track);
342
343    void OnAnimationStateChanged(CORE_NS::IEcs::ComponentListener::EventType event);
344    void OnAnimationNameChanged(CORE_NS::IEcs::ComponentListener::EventType event);
345    void OnAnimationChanged(CORE_NS::IEcs::ComponentListener::EventType event);
346    void OnAnimationTracksChanged(CORE_NS::IEcs::ComponentListener::EventType event, CORE_NS::Entity entity);
347    void OnAnimationInputsChanged(CORE_NS::IEcs::ComponentListener::EventType event, CORE_NS::Entity entity);
348
349    void OnNamePropertyChanged();
350    void OnDurationPropertyChanged();
351    void OnProgressPropertyChanged();
352
353    void OnAnimationTrackChanged(IEcsTrackAnimation& track, CORE_NS::Entity trackEntity);
354    void OnAnimationTimestampsChanged(IEcsTrackAnimation& track, CORE_NS::Entity timestampEntity);
355
356    bool IsAnimationTrackArrayModified();
357    void GatherAnimationTracks();
358
359    CORE_NS::IEcs* ecs_ { nullptr };
360    CORE_NS::EntityReference entity_ {};
361    CORE_NS::Entity root_ {};
362
363    CORE3D_NS::IAnimationComponentManager* animationManager_ { nullptr };
364    CORE3D_NS::IAnimationTrackComponentManager* animationTrackManager_ { nullptr };
365    CORE3D_NS::IAnimationInputComponentManager* animationInputManager_ { nullptr };
366    CORE3D_NS::IAnimationOutputComponentManager* animationOutputManager_ { nullptr };
367    CORE_NS::IComponentManager* animationStateManager_ { nullptr };
368    CORE3D_NS::INameComponentManager* nameManager_ { nullptr };
369
370    bool updateGuard_ { false };
371
372    int32_t repeatCount_ { 1 };
373    std::optional<META_NS::TimeSpan> lastFrameTime_ {};
374
375    mutable META_NS::EventImpl<META_NS::IOnChanged> onFinished_;
376    mutable META_NS::EventImpl<META_NS::IOnChanged> onStarted_;
377
378    SceneHolder::WeakPtr sceneHolder_;
379    BASE_NS::weak_ptr<SCENE_NS::EcsListener> ecsListener_;
380};
381
382void RegisterEcsAnimationObjectType();
383void UnregisterEcsAnimationObjectType();
384
385SCENE_END_NAMESPACE()
386
387#endif // SCENE_PLUGIN_ECS_ANIMATION_H
388