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/message.h>
26 #include <dali/internal/event/common/event-thread-services.h>
27 #include <dali/internal/event/common/object-impl.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;
74 * Construct a new active-constraint.
75 * @param[in] targetIndex The index of the property to constrain.
76 * @param[in] sources The sources of the input properties passed to func.
77 * @param[in] func The constraint function.
78 * @return A newly allocated active-constraint.
80 static ActiveConstraintBase* New( Property::Index targetIndex,
81 SourceContainer& sources,
82 ConstraintFunctionPtr func )
84 return new ActiveConstraint< PropertyType >( targetIndex, sources, sources.size(), func );
90 virtual ~ActiveConstraint()
92 // This is not responsible for removing constraints.
96 * @copydoc ActiveConstraintBase::Clone()
98 virtual ActiveConstraintBase* Clone()
100 ActiveConstraintBase* clone( NULL );
102 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
104 clone = new ActiveConstraint< PropertyType >( mTargetIndex,
109 clone->SetAlphaFunction(mAlphaFunction);
110 clone->SetRemoveAction(mRemoveAction);
111 clone->SetTag( mTag );
119 * Private constructor; see also ActiveConstraint::New().
121 ActiveConstraint( Property::Index targetIndex,
122 SourceContainer& sources,
123 unsigned int sourceCount,
124 ConstraintFunctionPtr& func )
125 : ActiveConstraintBase( targetIndex, sources, sourceCount ),
126 mTargetIndex( targetIndex ),
127 mUserFunction( func )
132 ActiveConstraint( const ActiveConstraint& );
135 ActiveConstraint& operator=( const ActiveConstraint& rhs );
138 * Create and connect a constraint for a scene-object.
140 void ConnectConstraint()
142 // Should not come here any objects have been destroyed
143 DALI_ASSERT_DEBUG( NULL != mTargetObject );
144 DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
146 // Guard against double connections
147 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
149 // Short-circuit until the target scene-object exists
150 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetObject->GetSceneObject() );
151 if ( NULL == targetObject )
156 // Build a container of property-owners, providing the scene-graph properties
157 SceneGraph::PropertyOwnerContainer propertyOwners;
158 propertyOwners.PushBack( targetObject );
160 // Build the constraint function; this requires a scene-graph property from each source
161 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
165 // Create the SceneGraphConstraint, and connect to the scene-graph
167 const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex );
169 // The targetProperty should exist, when targetObject exists
170 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
172 // Connect the constraint
173 SceneGraph::ConstraintBase* sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
177 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
178 sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
179 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
181 // object is being used in a separate thread; queue a message to apply the constraint
182 ApplyConstraintMessage( GetEventThreadServices(), *targetObject, *sceneGraphConstraint );
184 // Keep a raw-pointer to the scene-graph constraint
185 mSceneGraphConstraint = sceneGraphConstraint;
187 // Notify Object base-class that the scene-graph constraint has been added
193 * Helper for ConnectConstraint. Creates a connected constraint-function.
194 * Also populates the property-owner container, for each input connected to the constraint-function.
195 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
196 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
198 PropertyConstraintBase<PropertyType>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
200 PropertyConstraintBase<PropertyType>* func = mUserFunction->Clone();
201 bool usingComponentFunc( false );
203 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
205 Source& source = *iter;
207 PropertyInputImpl* inputProperty( NULL );
208 int componentIndex( Property::INVALID_COMPONENT_INDEX );
210 if ( OBJECT_PROPERTY == source.sourceType )
212 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
214 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
216 // The property owner will not exist, if the target object is off-stage
219 AddUnique( propertyOwners, owner );
220 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
221 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
223 // The scene-object property should exist, when the property owner exists
224 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
227 else if ( LOCAL_PROPERTY == source.sourceType )
229 DALI_ASSERT_ALWAYS( mTargetObject->IsPropertyAConstraintInput( source.propertyIndex ) );
231 inputProperty = const_cast< PropertyInputImpl* >( mTargetObject->GetSceneObjectInputProperty( source.propertyIndex ) );
232 componentIndex = mTargetObject->GetPropertyComponentIndex( source.propertyIndex );
234 // The target scene-object should provide this property
235 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
239 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
241 Object* objectParent = dynamic_cast< Actor& >( *mTargetObject ).GetParent();
243 // This will not exist, if the target object is off-stage
244 if ( NULL != objectParent )
246 DALI_ASSERT_ALWAYS( objectParent->IsPropertyAConstraintInput( source.propertyIndex ) );
248 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( objectParent->GetSceneObject() );
250 // The property owner will not exist, if the parent object is off-stage
253 AddUnique( propertyOwners, owner );
254 inputProperty = const_cast< PropertyInputImpl* >( objectParent->GetSceneObjectInputProperty( source.propertyIndex ) );
255 componentIndex = objectParent->GetPropertyComponentIndex( source.propertyIndex );
257 // The scene-object property should exist, when the property owner exists
258 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
263 if ( NULL == inputProperty )
268 // Exit if a scene-graph object is not available from one of the sources
271 else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
273 // Special case where component indices are required
274 if ( !usingComponentFunc )
276 PropertyConstraintBase<PropertyType>* componentFunc = func->CloneComponentFunc();
277 usingComponentFunc = true;
279 // Switch to function supporting component indices
281 func = componentFunc;
285 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
293 Property::Index mTargetIndex;
295 ConstraintFunctionPtr mUserFunction;
299 * Variant which allows float components to be animated individually.
302 class ActiveConstraint<float> : public ActiveConstraintBase
306 typedef typename PropertyConstraintPtr<float>::Type ConstraintFunctionPtr;
309 * Construct a new active-constraint.
310 * @param[in] targetIndex The index of the property to constrain.
311 * @param[in] sources The sources of the input properties passed to func.
312 * @param[in] func The constraint function.
313 * @return A newly allocated active-constraint.
315 static ActiveConstraintBase* New( Property::Index targetIndex,
316 SourceContainer& sources,
317 ConstraintFunctionPtr func )
319 return new ActiveConstraint< float >( targetIndex, sources, sources.size(), func );
323 * Virtual destructor.
325 virtual ~ActiveConstraint()
327 // This is not responsible for removing constraints.
331 * @copydoc ActiveConstraintBase::Clone()
333 virtual ActiveConstraintBase* Clone()
335 ActiveConstraintBase* clone( NULL );
337 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
339 clone = new ActiveConstraint< float >( mTargetIndex,
344 clone->SetAlphaFunction(mAlphaFunction);
345 clone->SetRemoveAction(mRemoveAction);
346 clone->SetTag( mTag );
354 * Private constructor; see also ActiveConstraint::New().
356 ActiveConstraint( Property::Index targetIndex,
357 SourceContainer& sources,
358 unsigned int sourceCount,
359 ConstraintFunctionPtr& func )
360 : ActiveConstraintBase( targetIndex, sources, sourceCount ),
361 mTargetIndex( targetIndex ),
362 mUserFunction( func )
367 ActiveConstraint( const ActiveConstraint& );
370 ActiveConstraint& operator=( const ActiveConstraint& rhs );
373 * Create and connect a constraint for a scene-object.
375 void ConnectConstraint()
377 // Should not come here any objects have been destroyed
378 DALI_ASSERT_DEBUG( NULL != mTargetObject );
379 DALI_ASSERT_DEBUG( mSources.size() == mSourceCount );
381 // Guard against double connections
382 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
384 // Short-circuit until the target scene-object exists
385 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetObject->GetSceneObject() );
386 if ( NULL == targetObject )
391 // Build a container of property-owners, providing the scene-graph properties
392 SceneGraph::PropertyOwnerContainer propertyOwners;
393 propertyOwners.PushBack( targetObject );
395 // Build the constraint function; this requires a scene-graph property from each source
396 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
400 // Create the SceneGraphConstraint, and connect to the scene-graph
402 const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex );
404 // The targetProperty should exist, when targetObject exists
405 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
407 const int componentIndex = mTargetObject->GetPropertyComponentIndex( mTargetIndex );
409 SceneGraph::ConstraintBase* sceneGraphConstraint( NULL );
411 if ( Property::INVALID_COMPONENT_INDEX == componentIndex )
413 // Not a Vector3 or Vector4 component, expecting float type
414 DALI_ASSERT_DEBUG( PropertyTypes::Get< float >() == targetProperty->GetType() );
416 typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
418 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
425 // Expecting Vector3 or Vector4 type
427 if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
429 // Constrain float component of Vector3 property
431 if ( 0 == componentIndex )
433 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> > SceneGraphConstraint;
434 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
436 else if ( 1 == componentIndex )
438 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> > SceneGraphConstraint;
439 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
441 else if ( 2 == componentIndex )
443 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
444 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
447 else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
449 // Constrain float component of Vector4 property
451 if ( 0 == componentIndex )
453 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> > SceneGraphConstraint;
454 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
456 else if ( 1 == componentIndex )
458 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> > SceneGraphConstraint;
459 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
461 else if ( 2 == componentIndex )
463 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> > SceneGraphConstraint;
464 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
466 else if ( 3 == componentIndex )
468 typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
469 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mCustomWeight );
474 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
475 sceneGraphConstraint->SetInitialWeight( mOffstageWeight );
476 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
478 // object is being used in a separate thread; queue a message to apply the constraint
479 ApplyConstraintMessage( GetEventThreadServices(), *targetObject, *sceneGraphConstraint );
481 // Keep a raw-pointer to the scene-graph constraint
482 mSceneGraphConstraint = sceneGraphConstraint;
484 // Notify Object base-class that the scene-graph constraint has been added
490 * Helper for ConnectConstraint. Creates a connected constraint-function.
491 * Also populates the property-owner container, for each input connected to the constraint-function.
492 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
493 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
495 PropertyConstraintBase<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
497 PropertyConstraintBase<float>* func = mUserFunction->Clone();
498 bool usingComponentFunc( false );
500 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
502 Source& source = *iter;
504 PropertyInputImpl* inputProperty( NULL );
505 int componentIndex( Property::INVALID_COMPONENT_INDEX );
507 if ( OBJECT_PROPERTY == source.sourceType )
509 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
511 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
513 // The property owner will not exist, if the target object is off-stage
516 AddUnique( propertyOwners, owner );
517 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
518 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
520 // The scene-object property should exist, when the property owner exists
521 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
524 else if ( LOCAL_PROPERTY == source.sourceType )
526 DALI_ASSERT_ALWAYS( mTargetObject->IsPropertyAConstraintInput( source.propertyIndex ) );
528 inputProperty = const_cast< PropertyInputImpl* >( mTargetObject->GetSceneObjectInputProperty( source.propertyIndex ) );
529 componentIndex = mTargetObject->GetPropertyComponentIndex( source.propertyIndex );
531 // The target scene-object should provide this property
532 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
536 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
538 Object* objectParent = dynamic_cast< Actor& >( *mTargetObject ).GetParent();
540 // This will not exist, if the target object is off-stage
541 if ( NULL != objectParent )
543 DALI_ASSERT_ALWAYS( objectParent->IsPropertyAConstraintInput( source.propertyIndex ) );
545 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( objectParent->GetSceneObject() );
547 // The property owner will not exist, if the parent object is off-stage
550 AddUnique( propertyOwners, owner );
551 inputProperty = const_cast< PropertyInputImpl* >( objectParent->GetSceneObjectInputProperty( source.propertyIndex ) );
552 componentIndex = objectParent->GetPropertyComponentIndex( source.propertyIndex );
554 // The scene-object property should exist, when the property owner exists
555 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
560 if ( NULL == inputProperty )
565 // Exit if a scene-graph object is not available from one of the sources
568 else if ( Property::INVALID_COMPONENT_INDEX != componentIndex )
570 // Special case where component indices are required
571 if ( !usingComponentFunc )
573 PropertyConstraintBase<float>* componentFunc = func->CloneComponentFunc();
574 usingComponentFunc = true;
576 // Switch to function supporting component indices
578 func = componentFunc;
582 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
590 Property::Index mTargetIndex;
592 ConstraintFunctionPtr mUserFunction;
595 } // namespace Internal
599 #endif // __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__