[dali_2.3.29] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / linear-constrainer-impl.h
1 #ifndef DALI_INTERNAL_LINEAR_CONSTRAINER_H
2 #define DALI_INTERNAL_LINEAR_CONSTRAINER_H
3
4 /*
5  * Copyright (c) 2024 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 // INTERNAL INCLUDES
22 #include <dali/internal/event/animation/constrainer.h>
23 #include <dali/public-api/animation/linear-constrainer.h>
24 #include <dali/public-api/math/math-utils.h>
25
26 namespace Dali
27 {
28 namespace Internal
29 {
30 typedef IntrusivePtr<LinearConstrainer> LinearConstrainerPtr;
31
32 /**
33  * @brief Constraint functor to constraint properties given a linear map.
34  */
35 struct LinearConstraintFunctor
36 {
37   /**
38    * @brief Constructor.
39    *
40    * @param[in] value The list of values for the linear map (f(x) of the linear map)
41    * @param[in] progress Progress for each of the values normalized to [0,1] ( x of the linear map)
42    * @param[in] range The range of values in the input property which will be mapped to [0,1]
43    * @param[in] wrap Wrapping domain. Input property value will be wrapped in the domain [wrap.x,wrap.y] before mapping to [0,1]
44    *
45    * @note If progress is an empty vector, the values will be assumed to be equally spaced in the x-axis
46    */
47   LinearConstraintFunctor(Dali::Vector<float>& value, Dali::Vector<float>& progress, const Vector2& range, const Vector2& wrap)
48   : mValue(value),
49     mProgress(progress),
50     mRange(range),
51     mWrap(wrap)
52   {
53   }
54
55   /**
56    * @brief Functor operator for float properties
57    *
58    * @param[out]  value Current value of the property
59    * @param[in]   inputs Contains the input property used as the parameter for the path
60    *
61    * @return The value of the linear map at the given parameter.
62    */
63   void operator()(float&                        value,
64                   const PropertyInputContainer& inputs)
65   {
66     uint32_t valueCount = static_cast<uint32_t>(mValue.Size());
67     if(valueCount == 0)
68     {
69       //No values.
70     }
71     else if(valueCount == 1)
72     {
73       value = mValue[0];
74     }
75     else
76     {
77       float inputWrapped = inputs[0]->GetFloat();
78       if(inputWrapped < mWrap.x || inputWrapped > mWrap.y)
79       {
80         inputWrapped = WrapInDomain(inputWrapped, mWrap.x, mWrap.y);
81       }
82
83       float t = ((inputWrapped - mRange.x) / (mRange.y - mRange.x));
84
85       //Find min and max values and local t between them
86       uint32_t min(0);
87       uint32_t max(0);
88       float    tLocal(0.0f);
89       if(mProgress.Size() < valueCount)
90       {
91         float step      = 1.0f / (static_cast<float>(valueCount) - 1.0f);
92         float tLocation = t / step;
93         if(tLocation < 0)
94         {
95           min = 0;
96           max = 1;
97         }
98         else if(tLocation >= static_cast<float>(valueCount - 1))
99         {
100           min = max = valueCount - 1;
101         }
102         else
103         {
104           min = static_cast<uint32_t>(tLocation);
105           max = min + 1;
106         }
107
108         tLocal = (t - static_cast<float>(min) * step) / step;
109       }
110       else
111       {
112         while((min < valueCount - 1) && (t >= mProgress[min]))
113         {
114           min++;
115         }
116
117         max = min;
118
119         if(min >= valueCount)
120         {
121           min = max = valueCount - 1;
122           tLocal    = 0.0f;
123         }
124         else if(min == 0u)
125         {
126           min = max = 0u;
127           tLocal    = 0.0f;
128         }
129         else
130         {
131           min--;
132           tLocal = (t - mProgress[min]) / (mProgress[max] - mProgress[min]);
133         }
134       }
135
136       //Linear interpolation
137       value = (mValue[max] - mValue[min]) * tLocal + mValue[min];
138     }
139   }
140
141   Dali::Vector<float> mValue;    ///< values for the linear map
142   Dali::Vector<float> mProgress; ///< Progress for each of the values normalized to [0,1]
143   Vector2             mRange;    ///< The range of values in the input property which will be mapped to 0..1
144   Vector2             mWrap;     ///< Wrapping domain. Input property will be wrapped in this domain before being mapped to [0,1]
145 };
146
147 /**
148  * @brief A LinearConstrainer used to constraint properties given a linear map
149  */
150 class LinearConstrainer : public Constrainer
151 {
152 public:
153   /**
154    * Create a new LinearConstrainer
155    * @return A smart-pointer to the newly allocated LinearConstrainer.
156    */
157   static LinearConstrainer* New();
158
159 protected:
160   /**
161    * virtual destructor
162    */
163   ~LinearConstrainer() override;
164
165 private:
166   /**
167    * @copydoc Dali::Internal::Object::SetDefaultProperty()
168    */
169   void SetDefaultProperty(Property::Index index, const Property::Value& propertyValue) override;
170
171   /**
172    * @copydoc Dali::Internal::Object::GetDefaultProperty()
173    */
174   Property::Value GetDefaultProperty(Property::Index index) const override;
175
176   /**
177   * @copydoc Dali::Internal::Object::GetDefaultPropertyCurrentValue()
178   */
179   Property::Value GetDefaultPropertyCurrentValue(Property::Index index) const override;
180
181 public:
182   /**
183    * @copydoc Dali::PathConstrainer::Apply
184    */
185   void Apply(Property target, Property source, const Vector2& range, const Vector2& wrap) override;
186
187 private:
188   //Constructor
189   LinearConstrainer();
190
191   // Undefined
192   LinearConstrainer(const LinearConstrainer&);
193
194   // Undefined
195   LinearConstrainer& operator=(const LinearConstrainer& rhs);
196
197   Dali::Vector<float> mValue;    ///< values for the linear map
198   Dali::Vector<float> mProgress; ///< Progress for each of the values normalized to [0,1]
199 };
200
201 } // namespace Internal
202
203 // Get impl of handle
204 inline Internal::LinearConstrainer& GetImplementation(Dali::LinearConstrainer& linearConstrainer)
205 {
206   DALI_ASSERT_ALWAYS(linearConstrainer && "LinearConstrainer handle is empty");
207   Dali::RefObject& object = linearConstrainer.GetBaseObject();
208   return static_cast<Internal::LinearConstrainer&>(object);
209 }
210
211 inline const Internal::LinearConstrainer& GetImplementation(const Dali::LinearConstrainer& linearConstrainer)
212 {
213   DALI_ASSERT_ALWAYS(linearConstrainer && "LinearConstrainer handle is empty");
214   const Dali::RefObject& object = linearConstrainer.GetBaseObject();
215   return static_cast<const Internal::LinearConstrainer&>(object);
216 }
217
218 } // namespace Dali
219
220 #endif // DALI_INTERNAL_PATH_CONSTRAINER_H