Support Animation Blend for AnimateBetween
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / key-frames-impl.h
1 #ifndef DALI_INTERNAL_KEY_FRAMES_H
2 #define DALI_INTERNAL_KEY_FRAMES_H
3
4 /*
5  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <memory>
23
24 // INTERNAL INCLUDES
25 #include <dali/internal/event/animation/key-frame-channel.h>
26 #include <dali/public-api/animation/alpha-function.h>
27 #include <dali/public-api/animation/key-frames.h>
28 #include <dali/public-api/common/vector-wrapper.h>
29 #include <dali/public-api/object/base-object.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 class KeyFrameSpec;
36 class KeyFrames;
37
38 /**
39  * KeyFrames class is responsible for creating and building a specialized KeyFrame class
40  * from the Property::Value type used in Add.
41  */
42 class KeyFrames : public BaseObject
43 {
44 public:
45   static KeyFrames* New();
46
47 private:
48   /**
49    * Create a specialization from the given type, and store it to the mSpec
50    * member variable
51    */
52   void CreateKeyFramesSpec(Property::Type type);
53
54 public:
55   /**
56    * Get the type of this key frame.
57    * An empty key frame will return Property::NONE, wheras an initialised
58    * key frame object will return the type of it's first element.
59    * @return the Property::Type of the key frame values
60    */
61   Property::Type GetType() const;
62
63   /**
64    * Add a key frame. The first key frame to be added denotes the type
65    * of all subsequent key frames. If a value with a different type is
66    * added, it will throw a run time assert.
67    * @param[in] time The time (between 0 and 1)
68    * @param[in] value The value of the keyframe at the given time
69    * @param[in] alpha An alpha function to blend between this key frame and the
70    * next key frame.
71    */
72   void Add(float time, const Property::Value& value, AlphaFunction alpha);
73
74   /**
75    * Return the key frames without specialization. The GetSpecialization methods
76    * below will convert to the specialized objects.
77    */
78   KeyFrameSpec* GetKeyFramesBase() const;
79
80   /**
81    * Return the value of the last key frame.
82    */
83   Dali::Property::Value GetLastKeyFrameValue() const;
84
85   /**
86    * @copydoc Dali::DevelKeyFrames::GetKeyFrameCount()
87    */
88   std::size_t GetKeyFrameCount() const;
89
90   /**
91    * @copydoc Dali::DevelKeyFrames::GetKeyFrame()
92    */
93   void GetKeyFrame(std::size_t index, float& time, Property::Value& value) const;
94
95   /**
96    * @copydoc Dali::DevelKeyFrames::SetKeyFrameValue()
97    */
98   void SetKeyFrameValue(std::size_t index, const Property::Value& value);
99
100 private:
101   Dali::Property::Type          mType{Property::NONE}; // Type of the specialization
102   std::unique_ptr<KeyFrameSpec> mKeyFrames;            // Pointer to the specialized key frame object
103 };
104
105 /**
106  * This is the base class for the individual template specializations, allowing a ptr to be
107  * stored in the handle object above.
108  */
109 class KeyFrameSpec
110 {
111 public:
112   virtual ~KeyFrameSpec() = default;
113
114   virtual std::size_t GetNumberOfKeyFrames() const = 0;
115
116   /**
117    * Get the key frame value as a Property::Value.
118    * @param[in] index The index of the key frame to fetch
119    * @param[out] time The progress of the given key frame
120    * @param[out] value The value of the given key frame
121    */
122   virtual void GetKeyFrameAsValue(std::size_t index, float& time, Property::Value& value) const = 0;
123
124   /**
125    * Set the key frame value as a Property::Value.
126    * @param[in] index The index of the key frame to set
127    * @param[in] value The value of the given key frame
128    */
129   virtual void SetKeyFrameValue(std::size_t index, const Property::Value& value) = 0;
130 };
131
132 /**
133  * The base template class for each key frame specialization.
134  */
135 template<typename V>
136 class KeyFrameBaseSpec : public KeyFrameSpec
137 {
138   KeyFrameChannel<V> mChannel; // The key frame channel
139
140 public:
141   /**
142    * Add a key frame to the channel. Key frames should be added
143    * in time order (this method does not sort the vector by time)
144    * @param[in] t - progress
145    * @param[in] v - value
146    * @param[in] alpha - Alpha function for blending to the next keyframe
147    */
148   void AddKeyFrame(float t, V v, AlphaFunction alpha)
149   {
150     mChannel.mValues.push_back({t, v});
151   }
152
153   /**
154    * Get the number of key frames
155    * @return Channel size
156    */
157   std::size_t GetNumberOfKeyFrames() const override
158   {
159     return mChannel.mValues.size();
160   }
161
162   /**
163    * Get a key frame.
164    * @param[in] index The index of the key frame to fetch
165    * @param[out] time The progress of the given key frame
166    * @param[out] value The value of the given key frame
167    */
168   void GetKeyFrame(unsigned int index, float& time, V& value) const
169   {
170     DALI_ASSERT_ALWAYS(index < mChannel.mValues.size() && "KeyFrame index is out of bounds");
171     const auto& element = mChannel.mValues[index];
172     time                = element.mProgress;
173     value               = element.mValue;
174   }
175
176   /**
177    * @copydoc KeyFrameSpec::GetKeyFrameAsValue()
178    */
179   void GetKeyFrameAsValue(std::size_t index, float& time, Property::Value& value) const override
180   {
181     const auto& element = mChannel.mValues[index];
182     time                = element.mProgress;
183     value               = element.mValue;
184   }
185
186   /**
187    * @copydoc KeyFrameSpec::SetKeyFrameValue()
188    */
189   void SetKeyFrameValue(std::size_t index, const Property::Value& value) override
190   {
191     auto& element  = mChannel.mValues[index];
192     element.mValue = value.Get<V>();
193   }
194
195   /**
196    * Return whether the progress is valid for the range of keyframes. (The first
197    * keyframe doesn't have to start at 0, and the last doesn't have to end at 1.0)
198    * @param[in] progress The progress to test
199    * @return True if the progress is valid for this object
200    */
201   bool IsActive(float progress) const
202   {
203     return mChannel.IsActive(progress);
204   }
205
206   /**
207    * Return an interpolated value for the given progress.
208    * @param[in] progress The progress to test
209    * @return The interpolated value
210    */
211   V GetValue(float progress, Dali::Animation::Interpolation interpolation) const
212   {
213     return mChannel.GetValue(progress, interpolation);
214   }
215 };
216
217 using KeyFrameNumber     = KeyFrameBaseSpec<float>;
218 using KeyFrameBoolean    = KeyFrameBaseSpec<bool>;
219 using KeyFrameInteger    = KeyFrameBaseSpec<int32_t>;
220 using KeyFrameVector2    = KeyFrameBaseSpec<Vector2>;
221 using KeyFrameVector3    = KeyFrameBaseSpec<Vector3>;
222 using KeyFrameVector4    = KeyFrameBaseSpec<Vector4>;
223 using KeyFrameQuaternion = KeyFrameBaseSpec<Quaternion>;
224
225 template<typename DeriveClass>
226 auto GetSpecialization(const Internal::KeyFrames& keyFrames)
227 {
228   return static_cast<DeriveClass>(keyFrames.GetKeyFramesBase());
229 }
230
231 } // namespace Internal
232
233 // Get impl of handle
234 inline Internal::KeyFrames& GetImplementation(Dali::KeyFrames& keyFrames)
235 {
236   DALI_ASSERT_ALWAYS(keyFrames && "KeyFrames handle is empty");
237   Dali::RefObject& object = keyFrames.GetBaseObject();
238   return static_cast<Internal::KeyFrames&>(object);
239 }
240
241 inline const Internal::KeyFrames& GetImplementation(const Dali::KeyFrames& keyFrames)
242 {
243   DALI_ASSERT_ALWAYS(keyFrames && "KeyFrames handle is empty");
244   const Dali::RefObject& object = keyFrames.GetBaseObject();
245   return static_cast<const Internal::KeyFrames&>(object);
246 }
247
248 } // namespace Dali
249
250 #endif // DALI_INTERNAL_KEY_FRAMES_H