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/internal/common/event-to-update.h>
26 #include <dali/internal/common/message.h>
27 #include <dali/internal/event/common/proxy-object.h>
28 #include <dali/internal/event/common/thread-local-storage.h>
29 #include <dali/internal/event/common/stage-impl.h>
30 #include <dali/internal/event/animation/active-constraint-base.h>
31 #include <dali/internal/event/animation/constraint-source-impl.h>
32 #include <dali/internal/event/animation/property-constraint-ptr.h>
33 #include <dali/internal/update/common/animatable-property.h>
34 #include <dali/internal/update/common/property-owner.h>
35 #include <dali/internal/update/common/property-owner-messages.h>
36 #include <dali/internal/update/animation/scene-graph-constraint.h>
37 #include <dali/internal/update/animation/property-accessor.h>
38 #include <dali/internal/update/animation/property-component-accessor.h>
47 * Helper to add only unique entries to the propertyOwner container
48 * @param propertyOwners to add the entries to
49 * @param object to add
51 inline void AddUnique( SceneGraph::PropertyOwnerContainer& propertyOwners, SceneGraph::PropertyOwner* object )
53 const SceneGraph::PropertyOwnerIter iter = std::find( propertyOwners.Begin(), propertyOwners.End(), object );
54 if( iter == propertyOwners.End() )
56 // each owner should only be added once
57 propertyOwners.PushBack( object );
62 * Connects a constraint which takes another property as an input.
64 template < typename PropertyType >
65 class ActiveConstraint : public ActiveConstraintBase
69 typedef SceneGraph::Constraint< PropertyType, PropertyAccessor<PropertyType> > SceneGraphConstraint;
70 typedef const SceneGraph::AnimatableProperty<PropertyType>* ScenePropertyPtr;
71 typedef typename PropertyConstraintPtr<PropertyType>::Type ConstraintFunctionPtr;
72 typedef boost::function< PropertyType (const PropertyType&, const PropertyType&, float) > InterpolatorFunction;
75 * Construct a new active-constraint.
76 * @param[in] targetIndex The index of the property to constrain.
77 * @param[in] sources The sources of the input properties passed to func.
78 * @param[in] func The constraint function.
79 * @param[in] interpolator The interpolator function.
80 * @return A newly allocated active-constraint.
82 static ActiveConstraintBase* New( Property::Index targetIndex,
83 SourceContainer& sources,
84 ConstraintFunctionPtr func,
85 InterpolatorFunction interpolator )
87 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
89 return new ActiveConstraint< PropertyType >( tls.GetEventToUpdate(), targetIndex, sources, sources.size(), func, interpolator );
95 virtual ~ActiveConstraint()
97 // This is not responsible for removing constraints.
101 * @copydoc ActiveConstraintBase::Clone()
103 virtual ActiveConstraintBase* Clone()
105 ActiveConstraintBase* clone( NULL );
107 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
109 clone = new ActiveConstraint< PropertyType >( mEventToUpdate,
114 mInterpolatorFunction );
116 clone->SetAlphaFunction(mAlphaFunction);
117 clone->SetRemoveAction(mRemoveAction);
118 clone->SetTag( mTag );
126 * Private constructor; see also ActiveConstraint::New().
128 ActiveConstraint( EventToUpdate& eventToUpdate,
129 Property::Index targetIndex,
130 SourceContainer& sources,
131 unsigned int sourceCount,
132 ConstraintFunctionPtr& func,
133 InterpolatorFunction& interpolator )
134 : ActiveConstraintBase( eventToUpdate, targetIndex, sources, sourceCount ),
135 mTargetIndex( targetIndex ),
136 mUserFunction( func ),
137 mInterpolatorFunction( interpolator )
142 ActiveConstraint( const ActiveConstraint& );
145 ActiveConstraint& operator=( const ActiveConstraint& rhs );
148 * Create and connect a constraint for a scene-object.
150 void ConnectConstraint()
152 // Should not come here any proxies have been destroyed
153 DALI_ASSERT_DEBUG( NULL != mTargetProxy );
154 DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
156 // Guard against double connections
157 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
159 // Short-circuit until the target scene-object exists
160 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetProxy->GetSceneObject() );
161 if ( NULL == targetObject )
166 // Build a container of property-owners, providing the scene-graph properties
167 SceneGraph::PropertyOwnerContainer propertyOwners;
168 propertyOwners.PushBack( targetObject );
170 // Build the constraint function; this requires a scene-graph property from each source
171 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
175 // Create the SceneGraphConstraint, and connect to the scene-graph
177 const SceneGraph::PropertyBase* targetProperty = mTargetProxy->GetSceneObjectAnimatableProperty( mTargetIndex );
179 // The targetProperty should exist, when targetObject exists
180 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
182 // Connect the constraint
183 SceneGraph::ConstraintBase* sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
186 mInterpolatorFunction,
188 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
189 sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
190 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
192 // object is being used in a separate thread; queue a message to apply the constraint
193 ApplyConstraintMessage( Stage::GetCurrent()->GetUpdateInterface(), *targetObject, *sceneGraphConstraint );
195 // Keep a raw-pointer to the scene-graph constraint
196 mSceneGraphConstraint = sceneGraphConstraint;
198 // Notify ProxyObject base-class that the scene-graph constraint has been added
204 * Helper for ConnectConstraint. Creates a connected constraint-function.
205 * Also populates the property-owner container, for each input connected to the constraint-function.
206 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
207 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
209 PropertyConstraintBase<PropertyType>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
211 PropertyConstraintBase<PropertyType>* func = mUserFunction->Clone();
212 bool usingComponentFunc( false );
214 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
216 Source& source = *iter;
218 PropertyInputImpl* inputProperty( NULL );
219 int componentIndex( Property::INVALID_COMPONENT_INDEX );
221 if ( OBJECT_PROPERTY == source.sourceType )
223 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
225 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
227 // The property owner will not exist, if the target proxy-object is off-stage
230 AddUnique( propertyOwners, owner );
231 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
232 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
234 // The scene-object property should exist, when the property owner exists
235 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
238 else if ( LOCAL_PROPERTY == source.sourceType )
240 DALI_ASSERT_ALWAYS( mTargetProxy->IsPropertyAConstraintInput( source.propertyIndex ) );
242 inputProperty = const_cast< PropertyInputImpl* >( mTargetProxy->GetSceneObjectInputProperty( source.propertyIndex ) );
243 componentIndex = mTargetProxy->GetPropertyComponentIndex( source.propertyIndex );
245 // The target scene-object should provide this property
246 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
250 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
252 ProxyObject* proxyParent = dynamic_cast< Actor& >( *mTargetProxy ).GetParent();
254 // This will not exist, if the target proxy-object is off-stage
255 if ( NULL != proxyParent )
257 DALI_ASSERT_ALWAYS( proxyParent->IsPropertyAConstraintInput( source.propertyIndex ) );
259 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( proxyParent->GetSceneObject() );
261 // The property owner will not exist, if the parent proxy-object is off-stage
264 AddUnique( propertyOwners, owner );
265 inputProperty = const_cast< PropertyInputImpl* >( proxyParent->GetSceneObjectInputProperty( source.propertyIndex ) );
266 componentIndex = proxyParent->GetPropertyComponentIndex( source.propertyIndex );
268 // The scene-object property should exist, when the property owner exists
269 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
274 if ( NULL == inputProperty )
279 // Exit if a scene-graph object is not available from one of the sources
282 else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
284 // Special case where component indices are required
285 if ( !usingComponentFunc )
287 PropertyConstraintBase<PropertyType>* componentFunc = func->CloneComponentFunc();
288 usingComponentFunc = true;
290 // Switch to function supporting component indices
292 func = componentFunc;
296 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
304 Property::Index mTargetIndex;
306 ConstraintFunctionPtr mUserFunction;
307 InterpolatorFunction mInterpolatorFunction;
311 * Variant which allows float components to be animated individually.
314 class ActiveConstraint<float> : public ActiveConstraintBase
318 typedef typename PropertyConstraintPtr<float>::Type ConstraintFunctionPtr;
319 typedef boost::function< float (const float&, const float&, float) > InterpolatorFunction;
322 * Construct a new active-constraint.
323 * @param[in] targetIndex The index of the property to constrain.
324 * @param[in] sources The sources of the input properties passed to func.
325 * @param[in] func The constraint function.
326 * @param[in] interpolator The interpolator function.
327 * @return A newly allocated active-constraint.
329 static ActiveConstraintBase* New( Property::Index targetIndex,
330 SourceContainer& sources,
331 ConstraintFunctionPtr func,
332 InterpolatorFunction interpolator )
334 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
336 return new ActiveConstraint< float >( tls.GetEventToUpdate(), targetIndex, sources, sources.size(), func, interpolator );
340 * Virtual destructor.
342 virtual ~ActiveConstraint()
344 // This is not responsible for removing constraints.
348 * @copydoc ActiveConstraintBase::Clone()
350 virtual ActiveConstraintBase* Clone()
352 ActiveConstraintBase* clone( NULL );
354 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
356 clone = new ActiveConstraint< float >( mEventToUpdate,
361 mInterpolatorFunction );
363 clone->SetAlphaFunction(mAlphaFunction);
364 clone->SetRemoveAction(mRemoveAction);
365 clone->SetTag( mTag );
373 * Private constructor; see also ActiveConstraint::New().
375 ActiveConstraint( EventToUpdate& eventToUpdate,
376 Property::Index targetIndex,
377 SourceContainer& sources,
378 unsigned int sourceCount,
379 ConstraintFunctionPtr& func,
380 InterpolatorFunction& interpolator )
381 : ActiveConstraintBase( eventToUpdate, targetIndex, sources, sourceCount ),
382 mTargetIndex( targetIndex ),
383 mUserFunction( func ),
384 mInterpolatorFunction( interpolator )
389 ActiveConstraint( const ActiveConstraint& );
392 ActiveConstraint& operator=( const ActiveConstraint& rhs );
395 * Create and connect a constraint for a scene-object.
397 void ConnectConstraint()
399 // Should not come here any proxies have been destroyed
400 DALI_ASSERT_DEBUG( NULL != mTargetProxy );
401 DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
403 // Guard against double connections
404 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
406 // Short-circuit until the target scene-object exists
407 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetProxy->GetSceneObject() );
408 if ( NULL == targetObject )
413 // Build a container of property-owners, providing the scene-graph properties
414 SceneGraph::PropertyOwnerContainer propertyOwners;
415 propertyOwners.PushBack( targetObject );
417 // Build the constraint function; this requires a scene-graph property from each source
418 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
422 // Create the SceneGraphConstraint, and connect to the scene-graph
424 const SceneGraph::PropertyBase* targetProperty = mTargetProxy->GetSceneObjectAnimatableProperty( mTargetIndex );
426 // The targetProperty should exist, when targetObject exists
427 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
429 const int componentIndex = mTargetProxy->GetPropertyComponentIndex( mTargetIndex );
431 SceneGraph::ConstraintBase* sceneGraphConstraint( NULL );
433 if ( Property::INVALID_COMPONENT_INDEX == componentIndex )
435 // Not a Vector3 or Vector4 component, expecting float type
436 DALI_ASSERT_DEBUG( PropertyTypes::Get< float >() == targetProperty->GetType() );
438 typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
440 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
443 mInterpolatorFunction,
448 // Expecting Vector3 or Vector4 type
450 if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
452 // Constrain float component of Vector3 property
454 if ( 0 == componentIndex )
456 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> > SceneGraphConstraint;
457 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
459 else if ( 1 == componentIndex )
461 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> > SceneGraphConstraint;
462 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
464 else if ( 2 == componentIndex )
466 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
467 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
470 else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
472 // Constrain float component of Vector4 property
474 if ( 0 == componentIndex )
476 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> > SceneGraphConstraint;
477 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
479 else if ( 1 == componentIndex )
481 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> > SceneGraphConstraint;
482 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
484 else if ( 2 == componentIndex )
486 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> > SceneGraphConstraint;
487 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
489 else if ( 3 == componentIndex )
491 typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
492 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mInterpolatorFunction, mCustomWeight );
497 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
498 sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
499 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
501 // object is being used in a separate thread; queue a message to apply the constraint
502 ApplyConstraintMessage( Stage::GetCurrent()->GetUpdateInterface(), *targetObject, *sceneGraphConstraint );
504 // Keep a raw-pointer to the scene-graph constraint
505 mSceneGraphConstraint = sceneGraphConstraint;
507 // Notify ProxyObject base-class that the scene-graph constraint has been added
513 * Helper for ConnectConstraint. Creates a connected constraint-function.
514 * Also populates the property-owner container, for each input connected to the constraint-function.
515 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
516 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
518 PropertyConstraintBase<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
520 PropertyConstraintBase<float>* func = mUserFunction->Clone();
521 bool usingComponentFunc( false );
523 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
525 Source& source = *iter;
527 PropertyInputImpl* inputProperty( NULL );
528 int componentIndex( Property::INVALID_COMPONENT_INDEX );
530 if ( OBJECT_PROPERTY == source.sourceType )
532 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
534 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
536 // The property owner will not exist, if the target proxy-object is off-stage
539 AddUnique( propertyOwners, owner );
540 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
541 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
543 // The scene-object property should exist, when the property owner exists
544 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
547 else if ( LOCAL_PROPERTY == source.sourceType )
549 DALI_ASSERT_ALWAYS( mTargetProxy->IsPropertyAConstraintInput( source.propertyIndex ) );
551 inputProperty = const_cast< PropertyInputImpl* >( mTargetProxy->GetSceneObjectInputProperty( source.propertyIndex ) );
552 componentIndex = mTargetProxy->GetPropertyComponentIndex( source.propertyIndex );
554 // The target scene-object should provide this property
555 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
559 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
561 ProxyObject* proxyParent = dynamic_cast< Actor& >( *mTargetProxy ).GetParent();
563 // This will not exist, if the target proxy-object is off-stage
564 if ( NULL != proxyParent )
566 DALI_ASSERT_ALWAYS( proxyParent->IsPropertyAConstraintInput( source.propertyIndex ) );
568 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( proxyParent->GetSceneObject() );
570 // The property owner will not exist, if the parent proxy-object is off-stage
573 AddUnique( propertyOwners, owner );
574 inputProperty = const_cast< PropertyInputImpl* >( proxyParent->GetSceneObjectInputProperty( source.propertyIndex ) );
575 componentIndex = proxyParent->GetPropertyComponentIndex( source.propertyIndex );
577 // The scene-object property should exist, when the property owner exists
578 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
583 if ( NULL == inputProperty )
588 // Exit if a scene-graph object is not available from one of the sources
591 else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
593 // Special case where component indices are required
594 if ( !usingComponentFunc )
596 PropertyConstraintBase<float>* componentFunc = func->CloneComponentFunc();
597 usingComponentFunc = true;
599 // Switch to function supporting component indices
601 func = componentFunc;
605 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
613 Property::Index mTargetIndex;
615 ConstraintFunctionPtr mUserFunction;
616 InterpolatorFunction mInterpolatorFunction;
619 } // namespace Internal
623 #endif // __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__