2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/integration-api/debug.h>
22 #include <dali-toolkit/internal/builder/builder-impl.h>
23 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
24 #include <dali-toolkit/internal/builder/replacement.h>
26 namespace // unnamed namespace
31 TimePeriod GetTimePeriod( const TreeNode& child, const Toolkit::Internal::Replacement& constant )
33 OptionalFloat delay = constant.IsFloat( IsChild(child, "delay" ) );
34 OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
35 DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
39 return TimePeriod( *delay, *duration );
43 return TimePeriod( *duration );
47 Property::Value GetPropertyValue( const Property::Type& propType, const TreeNode& child )
51 case Property::BOOLEAN:
53 return Property::Value( GetBoolean( child ) );
58 return Property::Value( GetFloat( child ) );
61 case Property::VECTOR2:
63 return Property::Value( GetVector2( child ) );
66 case Property::VECTOR3:
68 return Property::Value( GetVector3( child ) );
71 case Property::VECTOR4:
73 return Property::Value( GetVector4( child ) );
76 case Property::ROTATION:
78 if( 4 == child.Size() )
80 Vector4 v(GetVector4(child));
81 // angle, axis as per spec
82 return Property::Value( Quaternion(Radian(Degree(v[3])),
83 Vector3(v[0],v[1],v[2])) );
87 // degrees as per spec
88 Vector3 rotation = GetVector3( child );
89 return Property::Value( Quaternion(Radian(Degree(rotation.x)),
90 Radian(Degree(rotation.y)),
91 Radian(Degree(rotation.z))) );
95 case Property::NONE: // fall
98 DALI_ASSERT_ALWAYS( !"Property type incorrect" );
103 AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
105 typedef std::map< const std::string, Dali::AlphaFunction > AlphaFunctionLut;
106 static AlphaFunctionLut alphaFunctionLut;
108 if( 0 == alphaFunctionLut.size() )
110 // coding convention is uppercase enums
111 alphaFunctionLut["DEFAULT"] = AlphaFunctions::Default;
112 alphaFunctionLut["LINEAR"] = AlphaFunctions::Linear;
113 alphaFunctionLut["SQUARE"] = AlphaFunctions::Square;
114 alphaFunctionLut["REVERSE"] = AlphaFunctions::Reverse;
115 alphaFunctionLut["EASE_IN"] = AlphaFunctions::EaseIn;
116 alphaFunctionLut["EASE_OUT"] = AlphaFunctions::EaseOut;
117 alphaFunctionLut["EASE_IN_OUT"] = AlphaFunctions::EaseInOut;
118 alphaFunctionLut["EASE_IN_SINE"] = AlphaFunctions::EaseInSine;
119 alphaFunctionLut["EASE_OUT_SINE"] = AlphaFunctions::EaseOutSine;
120 alphaFunctionLut["EASE_IN_OUT_SINE"] = AlphaFunctions::EaseInOutSine;
121 alphaFunctionLut["EASE_IN_SINE_33"] = AlphaFunctions::EaseInSine33;
122 alphaFunctionLut["EASE_OUT_SINE_33"] = AlphaFunctions::EaseOutSine33;
123 alphaFunctionLut["EASE_IN_OUT_SINE_33"] = AlphaFunctions::EaseInOutSine33;
124 alphaFunctionLut["EASE_IN_OUT_SINE_50"] = AlphaFunctions::EaseInOutSine50;
125 alphaFunctionLut["EASE_IN_OUT_SINE_60"] = AlphaFunctions::EaseInOutSine60;
126 alphaFunctionLut["EASE_IN_OUT_SINE_70"] = AlphaFunctions::EaseInOutSine70;
127 alphaFunctionLut["EASE_IN_OUT_SINE_80"] = AlphaFunctions::EaseInOutSine80;
128 alphaFunctionLut["EASE_IN_OUT_SINE_90"] = AlphaFunctions::EaseInOutSine90;
129 alphaFunctionLut["DOUBLE_EASE_IN_OUT_SINE_60"] = AlphaFunctions::DoubleEaseInOutSine60;
130 alphaFunctionLut["EASE_OUT_QUINT_50"] = AlphaFunctions::EaseOutQuint50;
131 alphaFunctionLut["EASE_OUT_QUINT_80"] = AlphaFunctions::EaseOutQuint80;
132 alphaFunctionLut["BOUNCE"] = AlphaFunctions::Bounce;
133 alphaFunctionLut["BOUNCE_BACK"] = AlphaFunctions::BounceBack;
134 alphaFunctionLut["EASE_IN_BACK"] = AlphaFunctions::EaseInBack;
135 alphaFunctionLut["EASE_OUT_BACK"] = AlphaFunctions::EaseOutBack;
136 alphaFunctionLut["EASE_IN_OUT_BACK"] = AlphaFunctions::EaseInOutBack;
137 alphaFunctionLut["SIN"] = AlphaFunctions::Sin;
138 alphaFunctionLut["SIN2X"] = AlphaFunctions::Sin2x;
141 const AlphaFunctionLut::const_iterator iter( alphaFunctionLut.find( alphaFunction ) );
143 if( iter != alphaFunctionLut.end() )
149 DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Anchor Constant" );
150 return Dali::AlphaFunctions::Default;
154 } // unnamed namespace
166 Animation CreateAnimation( const TreeNode& child, const Replacement& constant, Dali::Actor searchRoot, Builder* const builder )
168 float durationSum = 0.f;
170 Dali::Actor searchActor = searchRoot ? searchRoot : Dali::Stage::GetCurrent().GetRootLayer();
172 Animation animation( Animation::New( 0.f ) );
174 // duration needs to be set before AnimateTo calls for correct operation when AnimateTo has no "time-period".
175 OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
179 animation.SetDuration( *duration );
182 if( OptionalBoolean looping = constant.IsBoolean( IsChild(child, "loop" ) ) )
184 animation.SetLooping( *looping );
187 if( OptionalString endAction = constant.IsString( IsChild(child, "end-action" ) ) )
189 if("BAKE" == *endAction)
191 animation.SetEndAction( Animation::Bake );
193 else if("DISCARD" == *endAction)
195 animation.SetEndAction( Animation::Discard );
197 else if("BAKE_FINAL" == *endAction)
199 animation.SetEndAction( Animation::BakeFinal );
203 if( OptionalString endAction = constant.IsString( IsChild(child, "disconnect-action" ) ) )
205 if("BAKE" == *endAction)
207 animation.SetDisconnectAction( Animation::Bake );
209 else if("DISCARD" == *endAction)
211 animation.SetDisconnectAction( Animation::Discard );
213 else if("BAKE_FINAL" == *endAction)
215 animation.SetDisconnectAction( Animation::BakeFinal );
219 OptionalChild propertiesNode = IsChild(child, "properties" );
222 const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
223 for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
225 const TreeNode::KeyNodePair& pKeyChild = *iter;
227 OptionalString actorName( constant.IsString( IsChild(pKeyChild.second, "actor" ) ) );
228 OptionalString property( constant.IsString( IsChild(pKeyChild.second, "property" ) ) );
229 DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
231 Handle targetHandle = searchActor.FindChildByName( *actorName );
232 DALI_ASSERT_ALWAYS( targetHandle && "Actor must exist for property" );
234 Property::Value propValue;
235 Property::Index propIndex = Property::INVALID_INDEX;
238 propIndex = targetHandle.GetPropertyIndex( *property );
240 // if the property is not found from the (actor) handle, try to downcast it to renderable actor
241 // to allow animating shader uniforms
242 if( propIndex == Property::INVALID_INDEX )
244 RenderableActor renderable = RenderableActor::DownCast( targetHandle );
247 // A limitation here is that its possible that between creation of animation
248 // and running it the ShaderEffect of the actor has been changed.
249 // However this is a unlikely use case especially when using scripts.
250 if( ShaderEffect effect = renderable.GetShaderEffect() )
252 propIndex = effect.GetPropertyIndex( *property );
253 if(propIndex != Property::INVALID_INDEX)
255 targetHandle = effect;
259 DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
266 DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
271 if( propIndex == Property::INVALID_INDEX)
273 DALI_ASSERT_ALWAYS( propIndex != Property::INVALID_INDEX && "Animation must specify a valid property" );
278 // these are the defaults
279 AlphaFunction alphaFunction( AlphaFunctions::Default );
280 TimePeriod timePeriod( 0.f );
282 OptionalChild timeChild = IsChild( pKeyChild.second, "time-period" );
286 timePeriod = GetTimePeriod( *timeChild, constant );
289 durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
291 if( OptionalString alphaChild = constant.IsString( IsChild(pKeyChild.second, "alpha-function" ) ) )
293 alphaFunction = GetAlphaFunction( *alphaChild );
296 if( OptionalChild keyFrameChild = IsChild(pKeyChild.second, "key-frames") )
298 DALI_ASSERT_ALWAYS( property && "Animation must specify a property name" );
299 Property prop = Property( targetHandle, propIndex );
301 KeyFrames keyframes = KeyFrames::New();
303 const TreeNode::ConstIterator endIter = (*keyFrameChild).CEnd();
304 for( TreeNode::ConstIterator iter = (*keyFrameChild).CBegin(); endIter != iter; ++iter )
306 const TreeNode::KeyNodePair& kfKeyChild = *iter;
308 OptionalFloat kfProgress = constant.IsFloat( IsChild(kfKeyChild.second, "progress" ) );
309 DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
311 OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
312 DALI_ASSERT_ALWAYS( kfValue && "Key frame entry must have 'value'" );
316 propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *kfValue );
320 DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n",
322 PropertyTypes::GetName(prop.object.GetPropertyType(prop.propertyIndex)) );
327 AlphaFunction kfAlphaFunction( AlphaFunctions::Default );
328 if( OptionalString alphaFuncStr = constant.IsString( IsChild(pKeyChild.second, "alpha-function") ) )
330 kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
333 keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
338 animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
342 animation.AnimateBetween( prop, keyframes, alphaFunction );
345 else if( OptionalString pathChild = IsString(pKeyChild.second, "path") )
348 Path path = builder->GetPath(*pathChild);
351 //Get forward vector if specified
352 Vector3 forward( 0.0f, 0.0f, 0.0f );
353 OptionalVector3 forwardProperty = constant.IsVector3( IsChild(pKeyChild.second, "forward" ) );
354 if( forwardProperty )
356 forward = *forwardProperty;
359 Actor actor = Actor::DownCast( targetHandle );
364 animation.Animate( actor, path, forward, alphaFunction, timePeriod );
368 animation.Animate( actor, path, forward, alphaFunction );
376 DALI_SCRIPT_WARNING( "Cannot find animation path '%s'\n", (*pathChild).c_str() );
381 DALI_ASSERT_ALWAYS( property && "Animation must specify a property name" );
383 Property prop = Property( targetHandle, propIndex );
386 propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *IsChild(pKeyChild.second, "value") );
390 DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n", (*property).c_str(),
391 PropertyTypes::GetName( prop.object.GetPropertyType(prop.propertyIndex) ) );
396 if( OptionalBoolean relative = constant.IsBoolean( IsChild(pKeyChild.second, "relative") ) )
400 animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
404 animation.AnimateBy( prop, propValue, alphaFunction );
411 animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
415 animation.AnimateTo( prop, propValue, alphaFunction );
424 animation.SetDuration( durationSum );
430 Animation CreateAnimation( const TreeNode& child, Builder* const builder )
432 Replacement replacement;
433 return CreateAnimation( child, replacement, Stage::GetCurrent().GetRootLayer(), builder );
436 } // namespace Internal
438 } // namespace Toolkit