Merge branch 'devel/master' into tizen
[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) 2021 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         min--;
118         max = min + 1;
119
120         if(min >= valueCount - 1)
121         {
122           min = max = valueCount - 1;
123           tLocal    = 0.0f;
124         }
125         else
126         {
127           tLocal = (t - mProgress[min]) / (mProgress[max] - mProgress[min]);
128         }
129       }
130
131       //Linear interpolation
132       value = (mValue[max] - mValue[min]) * tLocal + mValue[min];
133     }
134   }
135
136   Dali::Vector<float> mValue;    ///< values for the linear map
137   Dali::Vector<float> mProgress; ///< Progress for each of the values normalized to [0,1]
138   Vector2             mRange;    ///< The range of values in the input property which will be mapped to 0..1
139   Vector2             mWrap;     ///< Wrapping domain. Input property will be wrapped in this domain before being mapped to [0,1]
140 };
141
142 /**
143  * @brief A LinearConstrainer used to constraint properties given a linear map
144  */
145 class LinearConstrainer : public Constrainer
146 {
147 public:
148   /**
149    * Create a new LinearConstrainer
150    * @return A smart-pointer to the newly allocated LinearConstrainer.
151    */
152   static LinearConstrainer* New();
153
154 protected:
155   /**
156    * virtual destructor
157    */
158   ~LinearConstrainer() override;
159
160 private:
161   /**
162    * @copydoc Dali::Internal::Object::SetDefaultProperty()
163    */
164   void SetDefaultProperty(Property::Index index, const Property::Value& propertyValue) override;
165
166   /**
167    * @copydoc Dali::Internal::Object::GetDefaultProperty()
168    */
169   Property::Value GetDefaultProperty(Property::Index index) const override;
170
171   /**
172   * @copydoc Dali::Internal::Object::GetDefaultPropertyCurrentValue()
173   */
174   Property::Value GetDefaultPropertyCurrentValue(Property::Index index) const override;
175
176 public:
177   /**
178    * @copydoc Dali::PathConstrainer::Apply
179    */
180   void Apply(Property target, Property source, const Vector2& range, const Vector2& wrap) override;
181
182 private:
183   //Constructor
184   LinearConstrainer();
185
186   // Undefined
187   LinearConstrainer(const LinearConstrainer&);
188
189   // Undefined
190   LinearConstrainer& operator=(const LinearConstrainer& rhs);
191
192   Dali::Vector<float> mValue;    ///< values for the linear map
193   Dali::Vector<float> mProgress; ///< Progress for each of the values normalized to [0,1]
194 };
195
196 } // namespace Internal
197
198 // Get impl of handle
199 inline Internal::LinearConstrainer& GetImplementation(Dali::LinearConstrainer& linearConstrainer)
200 {
201   DALI_ASSERT_ALWAYS(linearConstrainer && "LinearConstrainer handle is empty");
202   Dali::RefObject& object = linearConstrainer.GetBaseObject();
203   return static_cast<Internal::LinearConstrainer&>(object);
204 }
205
206 inline const Internal::LinearConstrainer& GetImplementation(const Dali::LinearConstrainer& linearConstrainer)
207 {
208   DALI_ASSERT_ALWAYS(linearConstrainer && "LinearConstrainer handle is empty");
209   const Dali::RefObject& object = linearConstrainer.GetBaseObject();
210   return static_cast<const Internal::LinearConstrainer&>(object);
211 }
212
213 } // namespace Dali
214
215 #endif // DALI_INTERNAL_PATH_CONSTRAINER_H