Add 'ExclusiveArch: armv7l' limit build to arm architecture
[platform/core/uifw/dali-toolkit.git] / optional / dali-toolkit / internal / builder / builder-animations.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // EXTERNAL INCLUDES
18 #include <dali/integration-api/debug.h>
19
20 // INTERNAL INCLUDES
21 #include <dali-toolkit/internal/builder/builder-impl.h>
22 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
23 #include <dali-toolkit/internal/builder/replacement.h>
24
25 namespace // unnamed namespace
26 {
27
28 using namespace Dali;
29
30 TimePeriod GetTimePeriod( const TreeNode& child, const Toolkit::Internal::Replacement& constant )
31 {
32   OptionalFloat delay      = constant.IsFloat( IsChild(child, "delay" ) );
33   OptionalFloat duration   = constant.IsFloat( IsChild(child, "duration" ) );
34   DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
35
36   if( delay )
37   {
38     return TimePeriod( *delay, *duration );
39   }
40   else
41   {
42     return TimePeriod( *duration );
43   }
44 }
45
46 Property::Value GetPropertyValue( const Property::Type& propType, const TreeNode& child )
47 {
48   switch ( propType )
49   {
50     case Property::BOOLEAN:
51     {
52       return Property::Value( GetBoolean( child ) );
53     }
54
55     case Property::FLOAT:
56     {
57       return Property::Value( GetFloat( child ) );
58     }
59
60     case Property::VECTOR2:
61     {
62       return Property::Value( GetVector2( child ) );
63     }
64
65     case Property::VECTOR3:
66     {
67       return Property::Value( GetVector3( child ) );
68     }
69
70     case Property::VECTOR4:
71     {
72       return Property::Value( GetVector4( child ) );
73     }
74
75     case Property::ROTATION:
76     {
77       if( 4 == child.Size() )
78       {
79         Vector4 v(GetVector4(child));
80         // angle, axis as per spec
81         return Property::Value( Quaternion(Radian(Degree(v[3])),
82                                            Vector3(v[0],v[1],v[2])) );
83       }
84       else
85       {
86         // degrees as per spec
87         Vector3 rotation = GetVector3( child );
88         return Property::Value( Quaternion(Radian(Degree(rotation.x)),
89                                            Radian(Degree(rotation.y)),
90                                            Radian(Degree(rotation.z))) );
91       }
92     }
93
94     case Property::NONE: // fall
95     default:
96     {
97       DALI_ASSERT_ALWAYS( !"Property type incorrect" );
98       return Property::Value();
99     }
100   }
101 }
102
103 AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
104 {
105   typedef std::map< const std::string, Dali::AlphaFunction > AlphaFunctionLut;
106   static AlphaFunctionLut alphaFunctionLut;
107
108   if( 0 == alphaFunctionLut.size() )
109   {
110     // coding convention is uppercase enums
111     alphaFunctionLut["DEFAULT"]         = Dali::AlphaFunctions::Default;
112     alphaFunctionLut["LINEAR"]          = Dali::AlphaFunctions::Linear;
113     alphaFunctionLut["REVERSE"]         = Dali::AlphaFunctions::Reverse;
114     alphaFunctionLut["EASE_IN"]         = Dali::AlphaFunctions::EaseIn;
115     alphaFunctionLut["EASE_OUT"]        = Dali::AlphaFunctions::EaseOut;
116     alphaFunctionLut["EASE_IN_OUT"]     = Dali::AlphaFunctions::EaseInOut;
117     alphaFunctionLut["EASE_IN_SINE"]    = Dali::AlphaFunctions::EaseInSine;
118     alphaFunctionLut["EASE_OUT_SINE"]   = Dali::AlphaFunctions::EaseOutSine;
119     alphaFunctionLut["EASE_IN_OUT_SINE"]= Dali::AlphaFunctions::EaseInOutSine;
120     alphaFunctionLut["BOUNCE"]          = Dali::AlphaFunctions::Bounce;
121     alphaFunctionLut["BOUNCE_BACK"]     = Dali::AlphaFunctions::BounceBack;
122     alphaFunctionLut["EASE_OUT_BACK"]   = Dali::AlphaFunctions::EaseOutBack;
123     alphaFunctionLut["SIN"]             = Dali::AlphaFunctions::Sin;
124     alphaFunctionLut["SIN2X"]           = Dali::AlphaFunctions::Sin;
125   }
126
127   const AlphaFunctionLut::const_iterator iter( alphaFunctionLut.find( alphaFunction ) );
128
129   if( iter != alphaFunctionLut.end() )
130   {
131     return iter->second;
132   }
133   else
134   {
135     DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Anchor Constant" );
136     return Dali::AlphaFunctions::Default;
137   }
138 }
139
140 } // unnamed namespace
141
142
143 namespace Dali
144 {
145
146 namespace Toolkit
147 {
148
149 namespace Internal
150 {
151
152 Animation CreateAnimation( const TreeNode& child, const Replacement& constant, Dali::Actor searchRoot )
153 {
154   float durationSum = 0.f;
155
156   Dali::Actor searchActor = searchRoot ? searchRoot : Dali::Stage::GetCurrent().GetRootLayer();
157
158   Animation animation( Animation::New( 0.f ) );
159
160   // duration needs to be set before AnimateTo calls for correct operation when AnimateTo has no "time-period".
161   OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
162
163   if( duration )
164   {
165     animation.SetDuration( *duration );
166   }
167
168   if( OptionalBoolean looping = constant.IsBoolean(  IsChild(child, "loop" ) ) )
169   {
170     animation.SetLooping( *looping );
171   }
172
173   if( OptionalString endAction = constant.IsString(  IsChild(child, "end-action" ) ) )
174   {
175     if("BAKE" == *endAction)
176     {
177       animation.SetEndAction( Animation::Bake );
178     }
179     else if("DISCARD" == *endAction)
180     {
181       animation.SetEndAction( Animation::Discard );
182     }
183     else if("BAKE_FINAL" == *endAction)
184     {
185       animation.SetEndAction( Animation::BakeFinal );
186     }
187   }
188
189   if( OptionalString endAction = constant.IsString(  IsChild(child, "destroy-action" ) ) )
190   {
191     if("BAKE" == *endAction)
192     {
193       animation.SetDestroyAction( Animation::Bake );
194     }
195     else if("DISCARD" == *endAction)
196     {
197       animation.SetDestroyAction( Animation::Discard );
198     }
199     else if("BAKE_FINAL" == *endAction)
200     {
201       animation.SetDestroyAction( Animation::BakeFinal );
202     }
203   }
204
205   OptionalChild propertiesNode = IsChild(child, "properties" );
206   if(propertiesNode)
207   {
208     const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
209     for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
210     {
211       const TreeNode::KeyNodePair& pKeyChild = *iter;
212
213       OptionalString actorName( constant.IsString( IsChild(pKeyChild.second, "actor" ) ) );
214       OptionalString property(  constant.IsString( IsChild(pKeyChild.second, "property" ) ) );
215       DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
216       DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
217
218       Actor targetActor = searchActor.FindChildByName( *actorName );
219       DALI_ASSERT_ALWAYS( targetActor && "Actor must exist for property" );
220
221       Property::Index idx( targetActor.GetPropertyIndex( *property ) );
222
223       // A limitation here is that its possible that between binding to the signal and
224       // the signal call that the ShaderEffect of the targetActor has been changed.
225       // However this is a unlikely use case especially when using scripts.
226       if( idx == Property::INVALID_INDEX )
227       {
228         if( ShaderEffect effect = targetActor.GetShaderEffect() )
229         {
230           idx = effect.GetPropertyIndex( *property );
231           if(idx != Property::INVALID_INDEX)
232           {
233             targetActor = effect;
234           }
235           else
236           {
237             DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
238             continue;
239           }
240         }
241         else
242         {
243           DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
244           continue;
245         }
246       }
247
248       if( idx == Property::INVALID_INDEX)
249       {
250         DALI_ASSERT_ALWAYS( idx != Property::INVALID_INDEX && "Animation must specify a valid property" );
251         continue;
252       }
253
254       Property prop( Property( targetActor, idx ) );
255       Property::Value propValue;
256
257       // these are the defaults
258       AlphaFunction alphaFunction( AlphaFunctions::Default );
259       TimePeriod timePeriod( 0.f );
260
261       OptionalChild timeChild = IsChild( pKeyChild.second, "time-period" );
262
263       if( timeChild )
264       {
265         timePeriod = GetTimePeriod( *timeChild, constant );
266       }
267
268       durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
269
270       if( OptionalString alphaChild = constant.IsString( IsChild(pKeyChild.second, "alpha-function" ) ) )
271       {
272         alphaFunction = GetAlphaFunction( *alphaChild );
273       }
274
275       if( OptionalChild keyFrameChild = IsChild(pKeyChild.second, "key-frames") )
276       {
277         KeyFrames keyframes = KeyFrames::New();
278
279         const TreeNode::ConstIterator endIter = (*keyFrameChild).CEnd();
280         for( TreeNode::ConstIterator iter = (*keyFrameChild).CBegin(); endIter != iter; ++iter )
281         {
282           const TreeNode::KeyNodePair& kfKeyChild = *iter;
283
284           OptionalFloat kfProgress = constant.IsFloat( IsChild(kfKeyChild.second, "progress" ) );
285           DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
286
287           OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
288           DALI_ASSERT_ALWAYS( kfValue && "Key frame entry must have 'value'" );
289
290           try
291           {
292             propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *kfValue );
293           }
294           catch(...)
295           {
296             DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n",
297                               (*property).c_str(),
298                               PropertyTypes::GetName(prop.object.GetPropertyType(prop.propertyIndex)) );
299
300             throw;
301           }
302
303           AlphaFunction kfAlphaFunction( AlphaFunctions::Default );
304           if( OptionalString alphaFuncStr = constant.IsString( IsChild(pKeyChild.second, "alpha-function") ) )
305           {
306             kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
307           }
308
309           keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
310         }
311
312         if( timeChild )
313         {
314           animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
315         }
316         else
317         {
318           animation.AnimateBetween( prop, keyframes, alphaFunction );
319         }
320       }
321       else
322       {
323         try
324         {
325           propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *IsChild(pKeyChild.second, "value") );
326         }
327         catch(...)
328         {
329           DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n", (*property).c_str(),
330                             PropertyTypes::GetName( prop.object.GetPropertyType(prop.propertyIndex) ) );
331
332           throw;
333         }
334
335         if( OptionalBoolean relative = constant.IsBoolean( IsChild(pKeyChild.second, "relative") ) )
336         {
337           if( timeChild )
338           {
339             animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
340           }
341           else
342           {
343             animation.AnimateBy( prop, propValue, alphaFunction );
344           }
345         }
346         else
347         {
348           if( timeChild )
349           {
350             animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
351           }
352           else
353           {
354             animation.AnimateTo( prop, propValue, alphaFunction );
355           }
356         }
357       }
358     }
359   }
360
361   if( !duration )
362   {
363     animation.SetDuration( durationSum );
364   }
365
366   return animation;
367 }
368
369 Animation CreateAnimation( const TreeNode& child )
370 {
371   Replacement replacement;
372   return CreateAnimation( child, replacement, Stage::GetCurrent().GetRootLayer() );
373 }
374
375 } // namespace Internal
376
377 } // namespace Toolkit
378
379 } // namespace Dali
380