1 #ifndef __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
2 #define __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
5 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <boost/function.hpp>
25 #include <dali/public-api/common/set-wrapper.h>
26 #include <dali/internal/common/event-to-update.h>
27 #include <dali/internal/common/message.h>
28 #include <dali/internal/event/common/proxy-object.h>
29 #include <dali/internal/event/common/thread-local-storage.h>
30 #include <dali/internal/event/common/stage-impl.h>
31 #include <dali/internal/event/animation/active-constraint-base.h>
32 #include <dali/internal/event/animation/constraint-source-impl.h>
33 #include <dali/internal/event/animation/property-constraint-ptr.h>
34 #include <dali/internal/update/common/animatable-property.h>
35 #include <dali/internal/update/common/property-owner.h>
36 #include <dali/internal/update/common/property-owner-messages.h>
37 #include <dali/internal/update/animation/scene-graph-constraint.h>
38 #include <dali/internal/update/animation/property-accessor.h>
39 #include <dali/internal/update/animation/property-component-accessor.h>
48 * Connects a constraint which takes another property as an input.
50 template < typename PropertyType >
51 class ActiveConstraint : public ActiveConstraintBase
55 typedef SceneGraph::Constraint< PropertyType, PropertyAccessor<PropertyType> > SceneGraphConstraint;
56 typedef const SceneGraph::AnimatableProperty<PropertyType>* ScenePropertyPtr;
57 typedef typename PropertyConstraintPtr<PropertyType>::Type ConstraintFunctionPtr;
58 typedef boost::function< PropertyType (const PropertyType&, const PropertyType&, float) > InterpolatorFunction;
61 * Construct a new active-constraint.
62 * @param[in] targetIndex The index of the property to constrain.
63 * @param[in] sources The sources of the input properties passed to func.
64 * @param[in] func The constraint function.
65 * @param[in] interpolator The interpolator function.
66 * @return A newly allocated active-constraint.
68 static ActiveConstraintBase* New( Property::Index targetIndex,
69 SourceContainer& sources,
70 ConstraintFunctionPtr func,
71 InterpolatorFunction interpolator )
73 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
75 return new ActiveConstraint< PropertyType >( tls.GetEventToUpdate(), targetIndex, sources, sources.size(), func, interpolator );
81 virtual ~ActiveConstraint()
83 // This is not responsible for removing constraints.
87 * @copydoc ActiveConstraintBase::Clone()
89 virtual ActiveConstraintBase* Clone()
91 ActiveConstraintBase* clone( NULL );
93 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
95 clone = new ActiveConstraint< PropertyType >( mEventToUpdate,
100 mInterpolatorFunction );
102 clone->SetAlphaFunction(mAlphaFunction);
103 clone->SetRemoveAction(mRemoveAction);
104 clone->SetTag( mTag );
112 * Private constructor; see also ActiveConstraint::New().
114 ActiveConstraint( EventToUpdate& eventToUpdate,
115 Property::Index targetIndex,
116 SourceContainer& sources,
117 unsigned int sourceCount,
118 ConstraintFunctionPtr& func,
119 InterpolatorFunction& interpolator )
120 : ActiveConstraintBase( eventToUpdate, targetIndex, sources, sourceCount ),
121 mTargetIndex( targetIndex ),
122 mUserFunction( func ),
123 mInterpolatorFunction( interpolator )
128 ActiveConstraint( const ActiveConstraint& );
131 ActiveConstraint& operator=( const ActiveConstraint& rhs );
134 * Create and connect a constraint for a scene-object.
136 void ConnectConstraint()
138 // Should not come here any proxies have been destroyed
139 DALI_ASSERT_DEBUG( NULL != mTargetProxy );
140 DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
142 // Guard against double connections
143 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
145 // Short-circuit until the target scene-object exists
146 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetProxy->GetSceneObject() );
147 if ( NULL == targetObject )
152 // Build a set of property-owners, providing the scene-graph properties
153 SceneGraph::PropertyOwnerSet propertyOwners;
154 propertyOwners.insert( targetObject );
156 // Build the constraint function; this requires a scene-graph property from each source
157 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
161 // Create the SceneGraphConstraint, and connect to the scene-graph
163 const SceneGraph::PropertyBase* targetProperty = mTargetProxy->GetSceneObjectAnimatableProperty( mTargetIndex );
165 // The targetProperty should exist, when targetObject exists
166 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
168 // Connect the constraint
169 SceneGraph::ConstraintBase* sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
172 mInterpolatorFunction,
174 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
175 sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
176 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
178 // object is being used in a separate thread; queue a message to apply the constraint
179 ApplyConstraintMessage( Stage::GetCurrent()->GetUpdateInterface(), *targetObject, *sceneGraphConstraint );
181 // Keep a raw-pointer to the scene-graph constraint
182 mSceneGraphConstraint = sceneGraphConstraint;
184 // Notify ProxyObject base-class that the scene-graph constraint has been added
190 * Helper for ConnectConstraint. Creates a connected constraint-function.
191 * Also populates the property-owner set, for each input connected to the constraint-function.
192 * @param[out] propertyOwners The set of property-owners providing the scene-graph properties.
193 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
195 PropertyConstraintBase<PropertyType>* ConnectConstraintFunction( SceneGraph::PropertyOwnerSet& propertyOwners )
197 PropertyConstraintBase<PropertyType>* func = mUserFunction->Clone();
198 bool usingComponentFunc( false );
200 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
202 Source& source = *iter;
204 PropertyInputImpl* inputProperty( NULL );
205 int componentIndex( Property::INVALID_COMPONENT_INDEX );
207 if ( OBJECT_PROPERTY == source.sourceType )
209 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
211 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
213 // The property owner will not exist, if the target proxy-object is off-stage
216 propertyOwners.insert( owner );
217 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
218 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
220 // The scene-object property should exist, when the property owner exists
221 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
224 else if ( LOCAL_PROPERTY == source.sourceType )
226 DALI_ASSERT_ALWAYS( mTargetProxy->IsPropertyAConstraintInput( source.propertyIndex ) );
228 inputProperty = const_cast< PropertyInputImpl* >( mTargetProxy->GetSceneObjectInputProperty( source.propertyIndex ) );
229 componentIndex = mTargetProxy->GetPropertyComponentIndex( source.propertyIndex );
231 // The target scene-object should provide this property
232 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
236 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
238 ProxyObject* proxyParent = dynamic_cast< Actor& >( *mTargetProxy ).GetParent();
240 // This will not exist, if the target proxy-object is off-stage
241 if ( NULL != proxyParent )
243 DALI_ASSERT_ALWAYS( proxyParent->IsPropertyAConstraintInput( source.propertyIndex ) );
245 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( proxyParent->GetSceneObject() );
247 // The property owner will not exist, if the parent proxy-object is off-stage
250 propertyOwners.insert( owner );
251 inputProperty = const_cast< PropertyInputImpl* >( proxyParent->GetSceneObjectInputProperty( source.propertyIndex ) );
252 componentIndex = proxyParent->GetPropertyComponentIndex( source.propertyIndex );
254 // The scene-object property should exist, when the property owner exists
255 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
260 if ( NULL == inputProperty )
265 // Exit if a scene-graph object is not available from one of the sources
268 else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
270 // Special case where component indices are required
271 if ( !usingComponentFunc )
273 PropertyConstraintBase<PropertyType>* componentFunc = func->CloneComponentFunc();
274 usingComponentFunc = true;
276 // Switch to function supporting component indices
278 func = componentFunc;
282 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
290 Property::Index mTargetIndex;
292 ConstraintFunctionPtr mUserFunction;
293 InterpolatorFunction mInterpolatorFunction;
297 * Variant which allows float components to be animated individually.
300 class ActiveConstraint<float> : public ActiveConstraintBase
304 typedef typename PropertyConstraintPtr<float>::Type ConstraintFunctionPtr;
305 typedef boost::function< float (const float&, const float&, float) > InterpolatorFunction;
308 * Construct a new active-constraint.
309 * @param[in] targetIndex The index of the property to constrain.
310 * @param[in] sources The sources of the input properties passed to func.
311 * @param[in] func The constraint function.
312 * @param[in] interpolator The interpolator function.
313 * @return A newly allocated active-constraint.
315 static ActiveConstraintBase* New( Property::Index targetIndex,
316 SourceContainer& sources,
317 ConstraintFunctionPtr func,
318 InterpolatorFunction interpolator )
320 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
322 return new ActiveConstraint< float >( tls.GetEventToUpdate(), targetIndex, sources, sources.size(), func, interpolator );
326 * Virtual destructor.
328 virtual ~ActiveConstraint()
330 // This is not responsible for removing constraints.
334 * @copydoc ActiveConstraintBase::Clone()
336 virtual ActiveConstraintBase* Clone()
338 ActiveConstraintBase* clone( NULL );
340 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
342 clone = new ActiveConstraint< float >( mEventToUpdate,
347 mInterpolatorFunction );
349 clone->SetAlphaFunction(mAlphaFunction);
350 clone->SetRemoveAction(mRemoveAction);
351 clone->SetTag( mTag );
359 * Private constructor; see also ActiveConstraint::New().
361 ActiveConstraint( EventToUpdate& eventToUpdate,
362 Property::Index targetIndex,
363 SourceContainer& sources,
364 unsigned int sourceCount,
365 ConstraintFunctionPtr& func,
366 InterpolatorFunction& interpolator )
367 : ActiveConstraintBase( eventToUpdate, targetIndex, sources, sourceCount ),
368 mTargetIndex( targetIndex ),
369 mUserFunction( func ),
370 mInterpolatorFunction( interpolator )
375 ActiveConstraint( const ActiveConstraint& );
378 ActiveConstraint& operator=( const ActiveConstraint& rhs );
381 * Create and connect a constraint for a scene-object.
383 void ConnectConstraint()
385 // Should not come here any proxies have been destroyed
386 DALI_ASSERT_DEBUG( NULL != mTargetProxy );
387 DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
389 // Guard against double connections
390 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
392 // Short-circuit until the target scene-object exists
393 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetProxy->GetSceneObject() );
394 if ( NULL == targetObject )
399 // Build a set of property-owners, providing the scene-graph properties
400 SceneGraph::PropertyOwnerSet propertyOwners;
401 propertyOwners.insert( targetObject );
403 // Build the constraint function; this requires a scene-graph property from each source
404 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
408 // Create the SceneGraphConstraint, and connect to the scene-graph
410 const SceneGraph::PropertyBase* targetProperty = mTargetProxy->GetSceneObjectAnimatableProperty( mTargetIndex );
412 // The targetProperty should exist, when targetObject exists
413 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
415 const int componentIndex = mTargetProxy->GetPropertyComponentIndex( mTargetIndex );
417 SceneGraph::ConstraintBase* sceneGraphConstraint( NULL );
419 if ( Property::INVALID_COMPONENT_INDEX == componentIndex )
421 // Not a Vector3 or Vector4 component, expecting float type
422 DALI_ASSERT_DEBUG( PropertyTypes::Get< float >() == targetProperty->GetType() );
424 typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
426 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
429 mInterpolatorFunction,
434 // Expecting Vector3 or Vector4 type
436 if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
438 // Constrain float component of Vector3 property
440 if ( 0 == componentIndex )
442 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> > SceneGraphConstraint;
443 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
445 else if ( 1 == componentIndex )
447 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> > SceneGraphConstraint;
448 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
450 else if ( 2 == componentIndex )
452 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
453 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
456 else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
458 // Constrain float component of Vector4 property
460 if ( 0 == componentIndex )
462 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> > SceneGraphConstraint;
463 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
465 else if ( 1 == componentIndex )
467 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> > SceneGraphConstraint;
468 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
470 else if ( 2 == componentIndex )
472 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> > SceneGraphConstraint;
473 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
475 else if ( 3 == componentIndex )
477 typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
478 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
483 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
484 sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
485 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
487 // object is being used in a separate thread; queue a message to apply the constraint
488 ApplyConstraintMessage( Stage::GetCurrent()->GetUpdateInterface(), *targetObject, *sceneGraphConstraint );
490 // Keep a raw-pointer to the scene-graph constraint
491 mSceneGraphConstraint = sceneGraphConstraint;
493 // Notify ProxyObject base-class that the scene-graph constraint has been added
499 * Helper for ConnectConstraint. Creates a connected constraint-function.
500 * Also populates the property-owner set, for each input connected to the constraint-function.
501 * @param[out] propertyOwners The set of property-owners providing the scene-graph properties.
502 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
504 PropertyConstraintBase<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerSet& propertyOwners )
506 PropertyConstraintBase<float>* func = mUserFunction->Clone();
507 bool usingComponentFunc( false );
509 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
511 Source& source = *iter;
513 PropertyInputImpl* inputProperty( NULL );
514 int componentIndex( Property::INVALID_COMPONENT_INDEX );
516 if ( OBJECT_PROPERTY == source.sourceType )
518 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
520 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
522 // The property owner will not exist, if the target proxy-object is off-stage
525 propertyOwners.insert( owner );
526 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
527 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
529 // The scene-object property should exist, when the property owner exists
530 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
533 else if ( LOCAL_PROPERTY == source.sourceType )
535 DALI_ASSERT_ALWAYS( mTargetProxy->IsPropertyAConstraintInput( source.propertyIndex ) );
537 inputProperty = const_cast< PropertyInputImpl* >( mTargetProxy->GetSceneObjectInputProperty( source.propertyIndex ) );
538 componentIndex = mTargetProxy->GetPropertyComponentIndex( source.propertyIndex );
540 // The target scene-object should provide this property
541 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
545 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
547 ProxyObject* proxyParent = dynamic_cast< Actor& >( *mTargetProxy ).GetParent();
549 // This will not exist, if the target proxy-object is off-stage
550 if ( NULL != proxyParent )
552 DALI_ASSERT_ALWAYS( proxyParent->IsPropertyAConstraintInput( source.propertyIndex ) );
554 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( proxyParent->GetSceneObject() );
556 // The property owner will not exist, if the parent proxy-object is off-stage
559 propertyOwners.insert( owner );
560 inputProperty = const_cast< PropertyInputImpl* >( proxyParent->GetSceneObjectInputProperty( source.propertyIndex ) );
561 componentIndex = proxyParent->GetPropertyComponentIndex( source.propertyIndex );
563 // The scene-object property should exist, when the property owner exists
564 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
569 if ( NULL == inputProperty )
574 // Exit if a scene-graph object is not available from one of the sources
577 else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
579 // Special case where component indices are required
580 if ( !usingComponentFunc )
582 PropertyConstraintBase<float>* componentFunc = func->CloneComponentFunc();
583 usingComponentFunc = true;
585 // Switch to function supporting component indices
587 func = componentFunc;
591 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
599 Property::Index mTargetIndex;
601 ConstraintFunctionPtr mUserFunction;
602 InterpolatorFunction mInterpolatorFunction;
605 } // namespace Internal
609 #endif // __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__