Fixed svace defect
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / builder-animations.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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
18 // EXTERNAL INCLUDES
19 #include <dali/public-api/actors/layer.h>
20 #include <dali/integration-api/debug.h>
21
22 // INTERNAL INCLUDES
23 #include <dali-toolkit/internal/builder/builder-impl.h>
24 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
25 #include <dali-toolkit/internal/builder/replacement.h>
26
27 namespace // unnamed namespace
28 {
29
30 using namespace Dali;
31
32 TimePeriod GetTimePeriod( const TreeNode& child, const Toolkit::Internal::Replacement& constant )
33 {
34   OptionalFloat delay      = constant.IsFloat( IsChild(child, "delay" ) );
35   OptionalFloat duration   = constant.IsFloat( IsChild(child, "duration" ) );
36   DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
37
38   if( delay )
39   {
40     return TimePeriod( *delay, *duration );
41   }
42   else
43   {
44     return TimePeriod( *duration );
45   }
46 }
47
48 Property::Value GetPropertyValue( const Property::Type& propType, const TreeNode& child )
49 {
50   switch ( propType )
51   {
52     case Property::BOOLEAN:
53     {
54       return Property::Value( GetBoolean( child ) );
55     }
56
57     case Property::FLOAT:
58     {
59       return Property::Value( GetFloat( child ) );
60     }
61
62     case Property::VECTOR2:
63     {
64       return Property::Value( GetVector2( child ) );
65     }
66
67     case Property::VECTOR3:
68     {
69       return Property::Value( GetVector3( child ) );
70     }
71
72     case Property::VECTOR4:
73     {
74       return Property::Value( GetVector4( child ) );
75     }
76
77     case Property::ROTATION:
78     {
79       if( 4 == child.Size() )
80       {
81         Vector4 v(GetVector4(child));
82         // angle, axis as per spec
83         return Property::Value( Quaternion(Radian(Degree(v[3])),
84                                            Vector3(v[0],v[1],v[2])) );
85       }
86       else
87       {
88         // degrees as per spec
89         Vector3 rotation = GetVector3( child );
90         return Property::Value( Quaternion(Radian(Degree(rotation.x)),
91                                            Radian(Degree(rotation.y)),
92                                            Radian(Degree(rotation.z))) );
93       }
94     }
95
96     case Property::NONE: // fall
97     default:
98     {
99       DALI_ASSERT_ALWAYS( !"Property type incorrect" );
100     }
101   }
102 }
103
104 AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
105 {
106   typedef std::map< const std::string, Dali::AlphaFunction > AlphaFunctionLut;
107   static AlphaFunctionLut alphaFunctionLut;
108
109   if( 0 == alphaFunctionLut.size() )
110   {
111     // coding convention is uppercase enums
112     alphaFunctionLut["DEFAULT"]                    = AlphaFunction(AlphaFunction::DEFAULT);
113     alphaFunctionLut["LINEAR"]                     = AlphaFunction(AlphaFunction::LINEAR);
114     alphaFunctionLut["REVERSE"]                    = AlphaFunction(AlphaFunction::REVERSE);
115     alphaFunctionLut["EASE_IN_SQUARE"]             = AlphaFunction(AlphaFunction::EASE_IN_SQUARE);
116     alphaFunctionLut["EASE_OUT_SQUARE"]            = AlphaFunction(AlphaFunction::EASE_OUT_SQUARE);
117     alphaFunctionLut["EASE_IN"]                    = AlphaFunction(AlphaFunction::EASE_IN);
118     alphaFunctionLut["EASE_OUT"]                   = AlphaFunction(AlphaFunction::EASE_OUT);
119     alphaFunctionLut["EASE_IN_OUT"]                = AlphaFunction(AlphaFunction::EASE_IN_OUT);
120     alphaFunctionLut["EASE_IN_SINE"]               = AlphaFunction(AlphaFunction::EASE_IN_SINE);
121     alphaFunctionLut["EASE_OUT_SINE"]              = AlphaFunction(AlphaFunction::EASE_OUT_SINE);
122     alphaFunctionLut["EASE_IN_OUT_SINE"]           = AlphaFunction(AlphaFunction::EASE_IN_OUT_SINE);
123     alphaFunctionLut["BOUNCE"]                     = AlphaFunction(AlphaFunction::BOUNCE);
124     alphaFunctionLut["SIN"]                        = AlphaFunction(AlphaFunction::SIN);
125     alphaFunctionLut["EASE_OUT_BACK"]              = AlphaFunction(AlphaFunction::EASE_OUT_BACK);
126   }
127
128   const AlphaFunctionLut::const_iterator iter( alphaFunctionLut.find( alphaFunction ) );
129
130   if( iter != alphaFunctionLut.end() )
131   {
132     return iter->second;
133   }
134   else
135   {
136     DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Alpha Constant" );
137     return Dali::AlphaFunction::DEFAULT;
138   }
139 }
140
141 } // unnamed namespace
142
143
144 namespace Dali
145 {
146
147 namespace Toolkit
148 {
149
150 namespace Internal
151 {
152
153 Animation CreateAnimation( const TreeNode& child, const Replacement& constant, Dali::Actor searchRoot, Builder* const builder )
154 {
155   float durationSum = 0.f;
156
157   Dali::Actor searchActor = searchRoot ? searchRoot : Dali::Stage::GetCurrent().GetRootLayer();
158
159   Animation animation( Animation::New( 0.f ) );
160
161   // duration needs to be set before AnimateTo calls for correct operation when AnimateTo has no "timePeriod".
162   OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
163
164   if( duration )
165   {
166     animation.SetDuration( *duration );
167   }
168
169   if( OptionalBoolean looping = constant.IsBoolean(  IsChild(child, "loop" ) ) )
170   {
171     animation.SetLooping( *looping );
172   }
173
174   if( OptionalString endAction = constant.IsString(  IsChild(child, "endAction" ) ) )
175   {
176     if("BAKE" == *endAction)
177     {
178       animation.SetEndAction( Animation::Bake );
179     }
180     else if("DISCARD" == *endAction)
181     {
182       animation.SetEndAction( Animation::Discard );
183     }
184     else if("BAKE_FINAL" == *endAction)
185     {
186       animation.SetEndAction( Animation::BakeFinal );
187     }
188   }
189
190   if( OptionalString endAction = constant.IsString(  IsChild(child, "disconnectAction" ) ) )
191   {
192     if("BAKE" == *endAction)
193     {
194       animation.SetDisconnectAction( Animation::Bake );
195     }
196     else if("DISCARD" == *endAction)
197     {
198       animation.SetDisconnectAction( Animation::Discard );
199     }
200     else if("BAKE_FINAL" == *endAction)
201     {
202       animation.SetDisconnectAction( Animation::BakeFinal );
203     }
204   }
205
206   OptionalChild propertiesNode = IsChild(child, "properties" );
207   if(propertiesNode)
208   {
209     const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
210     for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
211     {
212       const TreeNode::KeyNodePair& pKeyChild = *iter;
213
214       OptionalString actorName( constant.IsString( IsChild(pKeyChild.second, "actor" ) ) );
215       OptionalString property(  constant.IsString( IsChild(pKeyChild.second, "property" ) ) );
216       DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
217
218       Handle targetHandle = searchActor.FindChildByName( *actorName );
219       DALI_ASSERT_ALWAYS( targetHandle && "Actor must exist for property" );
220
221       Property::Value propValue;
222       Property::Index propIndex = Property::INVALID_INDEX;
223       if( property )
224       {
225         propIndex = targetHandle.GetPropertyIndex( *property );
226
227         // if the property is not found from the (actor) handle, try to downcast it to renderable actor
228         // to allow animating shader uniforms
229         if( propIndex == Property::INVALID_INDEX )
230         {
231             DALI_SCRIPT_WARNING( "Cannot find property on object\n" );
232             continue;
233         }
234       }
235
236       // these are the defaults
237       AlphaFunction alphaFunction( AlphaFunction::DEFAULT );
238       TimePeriod timePeriod( 0.f );
239
240       OptionalChild timeChild = IsChild( pKeyChild.second, "timePeriod" );
241
242       if( timeChild )
243       {
244         timePeriod = GetTimePeriod( *timeChild, constant );
245       }
246
247       durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
248
249       if( OptionalString alphaChild = constant.IsString( IsChild(pKeyChild.second, "alphaFunction" ) ) )
250       {
251         alphaFunction = GetAlphaFunction( *alphaChild );
252       }
253
254       if( OptionalChild keyFrameChild = IsChild(pKeyChild.second, "keyFrames") )
255       {
256         DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
257         Property prop = Property( targetHandle, propIndex );
258
259         KeyFrames keyframes = KeyFrames::New();
260
261         const TreeNode::ConstIterator endIter = (*keyFrameChild).CEnd();
262         for( TreeNode::ConstIterator iter = (*keyFrameChild).CBegin(); endIter != iter; ++iter )
263         {
264           const TreeNode::KeyNodePair& kfKeyChild = *iter;
265
266           OptionalFloat kfProgress = constant.IsFloat( IsChild(kfKeyChild.second, "progress" ) );
267           DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
268
269           OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
270           DALI_ASSERT_ALWAYS( kfValue && "Key frame entry must have 'value'" );
271
272           try
273           {
274             propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *kfValue );
275           }
276           catch(...)
277           {
278             DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n",
279                               (*property).c_str(),
280                               PropertyTypes::GetName(prop.object.GetPropertyType(prop.propertyIndex)) );
281
282             throw;
283           }
284
285           AlphaFunction kfAlphaFunction( AlphaFunction::DEFAULT );
286           if( OptionalString alphaFuncStr = constant.IsString( IsChild(pKeyChild.second, "alphaFunction") ) )
287           {
288             kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
289           }
290
291           keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
292         }
293
294         if( timeChild )
295         {
296           animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
297         }
298         else
299         {
300           animation.AnimateBetween( prop, keyframes, alphaFunction );
301         }
302       }
303       else if( OptionalString pathChild = IsString(pKeyChild.second, "path") )
304       {
305         //Get path
306         Path path = builder->GetPath(*pathChild);
307         if( path )
308         {
309           //Get forward vector if specified
310           Vector3 forward( 0.0f, 0.0f, 0.0f );
311           OptionalVector3 forwardProperty = constant.IsVector3( IsChild(pKeyChild.second, "forward" ) );
312           if( forwardProperty )
313           {
314             forward = *forwardProperty;
315           }
316
317           Actor actor = Actor::DownCast( targetHandle );
318           if( actor )
319           {
320             if( timeChild )
321             {
322               animation.Animate( actor, path, forward, alphaFunction, timePeriod );
323             }
324             else
325             {
326               animation.Animate( actor, path, forward, alphaFunction );
327             }
328
329           }
330         }
331         else
332         {
333           //Path not found
334           DALI_SCRIPT_WARNING( "Cannot find animation path '%s'\n", (*pathChild).c_str() );
335         }
336       }
337       else
338       {
339         DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
340
341         Property prop = Property( targetHandle, propIndex );
342         try
343         {
344           propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *IsChild(pKeyChild.second, "value") );
345         }
346         catch(...)
347         {
348           DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n", (*property).c_str(),
349                             PropertyTypes::GetName( prop.object.GetPropertyType(prop.propertyIndex) ) );
350
351           throw;
352         }
353
354         if( OptionalBoolean relative = constant.IsBoolean( IsChild(pKeyChild.second, "relative") ) )
355         {
356           if( timeChild )
357           {
358             animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
359           }
360           else
361           {
362             animation.AnimateBy( prop, propValue, alphaFunction );
363           }
364         }
365         else
366         {
367           if( timeChild )
368           {
369             animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
370           }
371           else
372           {
373             animation.AnimateTo( prop, propValue, alphaFunction );
374           }
375         }
376       }
377     }
378   }
379
380   if( !duration )
381   {
382     animation.SetDuration( durationSum );
383   }
384
385   return animation;
386 }
387
388 Animation CreateAnimation( const TreeNode& child, Builder* const builder )
389 {
390   Replacement replacement;
391   return CreateAnimation( child, replacement, Stage::GetCurrent().GetRootLayer(), builder );
392 }
393
394 } // namespace Internal
395
396 } // namespace Toolkit
397
398 } // namespace Dali
399