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 <dali/internal/common/message.h>
23 #include <dali/internal/event/common/event-thread-services.h>
24 #include <dali/internal/event/common/object-impl.h>
25 #include <dali/internal/event/common/thread-local-storage.h>
26 #include <dali/internal/event/common/stage-impl.h>
27 #include <dali/internal/event/animation/constraint-base.h>
28 #include <dali/internal/event/animation/constraint-source-impl.h>
29 #include <dali/internal/event/animation/property-constraint-ptr.h>
30 #include <dali/internal/update/common/animatable-property.h>
31 #include <dali/internal/update/common/property-owner.h>
32 #include <dali/internal/update/common/property-owner-messages.h>
33 #include <dali/internal/update/animation/scene-graph-constraint.h>
34 #include <dali/internal/update/animation/property-accessor.h>
35 #include <dali/internal/update/animation/property-component-accessor.h>
44 * Helper to add only unique entries to the propertyOwner container
45 * @param propertyOwners to add the entries to
46 * @param object to add
48 inline void AddUnique( SceneGraph::PropertyOwnerContainer& propertyOwners, SceneGraph::PropertyOwner* object )
50 const SceneGraph::PropertyOwnerIter iter = std::find( propertyOwners.Begin(), propertyOwners.End(), object );
51 if( iter == propertyOwners.End() )
53 // each owner should only be added once
54 propertyOwners.PushBack( object );
59 * Connects a constraint which takes another property as an input.
61 template < typename PropertyType >
62 class Constraint : public ConstraintBase
66 typedef SceneGraph::Constraint< PropertyType, PropertyAccessor<PropertyType> > SceneGraphConstraint;
67 typedef const SceneGraph::AnimatableProperty<PropertyType>* ScenePropertyPtr;
68 typedef typename PropertyConstraintPtr<PropertyType>::Type ConstraintFunctionPtr;
71 * Construct a new constraint.
72 * @param[in] object The property-owning object.
73 * @param[in] targetIndex The index of the property to constrain.
74 * @param[in] sources The sources of the input properties passed to func.
75 * @param[in] func The constraint function.
76 * @return A newly allocated active-constraint.
78 static ConstraintBase* New( Object& object,
79 Property::Index targetIndex,
80 SourceContainer& sources,
81 ConstraintFunctionPtr func )
83 return new Constraint< PropertyType >( object, targetIndex, sources, func );
87 * @copydoc ConstraintBase::Clone()
89 virtual ConstraintBase* Clone( Object& object )
91 DALI_ASSERT_ALWAYS( !mSourceDestroyed && "An input source object has been destroyed" );
93 ConstraintBase* clone( NULL );
95 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
97 clone = new Constraint< PropertyType >( object,
102 clone->SetRemoveAction(mRemoveAction);
103 clone->SetTag( mTag );
110 * Virtual destructor.
112 virtual ~Constraint()
114 // This is not responsible for removing constraints.
120 * Private constructor; see also Constraint::New().
122 Constraint( Object& object,
123 Property::Index targetIndex,
124 SourceContainer& sources,
125 ConstraintFunctionPtr& func )
126 : ConstraintBase( object, targetIndex, sources ),
127 mTargetIndex( targetIndex ),
128 mUserFunction( func )
133 Constraint( const Constraint& );
136 Constraint& operator=( const Constraint& rhs );
139 * Create and connect a constraint for a scene-object.
141 void ConnectConstraint()
143 // Should not come here if target-object has been destroyed
144 DALI_ASSERT_DEBUG( NULL != mTargetObject );
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,
176 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
177 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
179 // object is being used in a separate thread; queue a message to apply the constraint
180 ApplyConstraintMessage( GetEventThreadServices(), *targetObject, *sceneGraphConstraint );
182 // Keep a raw-pointer to the scene-graph constraint
183 mSceneGraphConstraint = sceneGraphConstraint;
188 * Helper for ConnectConstraint. Creates a connected constraint-function.
189 * Also populates the property-owner container, for each input connected to the constraint-function.
190 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
191 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
193 PropertyConstraint<PropertyType>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
195 PropertyConstraint<PropertyType>* func = mUserFunction->Clone();
197 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
199 Source& source = *iter;
201 PropertyInputImpl* inputProperty( NULL );
202 int componentIndex( Property::INVALID_COMPONENT_INDEX );
204 if ( OBJECT_PROPERTY == source.sourceType )
206 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
208 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
210 // The property owner will not exist, if the target object is off-stage
213 AddUnique( propertyOwners, owner );
214 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
215 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
217 // The scene-object property should exist, when the property owner exists
218 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
221 else if ( LOCAL_PROPERTY == source.sourceType )
223 DALI_ASSERT_ALWAYS( mTargetObject->IsPropertyAConstraintInput( source.propertyIndex ) );
225 inputProperty = const_cast< PropertyInputImpl* >( mTargetObject->GetSceneObjectInputProperty( source.propertyIndex ) );
226 componentIndex = mTargetObject->GetPropertyComponentIndex( source.propertyIndex );
228 // The target scene-object should provide this property
229 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
233 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
235 Object* objectParent = dynamic_cast< Actor& >( *mTargetObject ).GetParent();
237 // This will not exist, if the target object is off-stage
238 if ( NULL != objectParent )
240 DALI_ASSERT_ALWAYS( objectParent->IsPropertyAConstraintInput( source.propertyIndex ) );
242 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( objectParent->GetSceneObject() );
244 // The property owner will not exist, if the parent object is off-stage
247 AddUnique( propertyOwners, owner );
248 inputProperty = const_cast< PropertyInputImpl* >( objectParent->GetSceneObjectInputProperty( source.propertyIndex ) );
249 componentIndex = objectParent->GetPropertyComponentIndex( source.propertyIndex );
251 // The scene-object property should exist, when the property owner exists
252 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
257 if ( NULL == inputProperty )
262 // Exit if a scene-graph object is not available from one of the sources
266 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
274 Property::Index mTargetIndex;
276 ConstraintFunctionPtr mUserFunction;
280 * Variant which allows float components to be animated individually.
283 class Constraint<float> : public ConstraintBase
287 typedef typename PropertyConstraintPtr<float>::Type ConstraintFunctionPtr;
290 * Construct a new constraint.
291 * @param[in] object The property-owning object.
292 * @param[in] targetIndex The index of the property to constrain.
293 * @param[in] sources The sources of the input properties passed to func.
294 * @param[in] func The constraint function.
295 * @return A newly allocated constraint.
297 static ConstraintBase* New( Object& object,
298 Property::Index targetIndex,
299 SourceContainer& sources,
300 ConstraintFunctionPtr func )
302 return new Constraint< float >( object, targetIndex, sources, func );
306 * @copydoc ConstraintBase::Clone()
308 virtual ConstraintBase* Clone( Object& object )
310 DALI_ASSERT_ALWAYS( !mSourceDestroyed && "An input source object has been destroyed" );
312 ConstraintBase* clone( NULL );
314 ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
316 clone = new Constraint< float >( object,
321 clone->SetRemoveAction(mRemoveAction);
322 clone->SetTag( mTag );
328 * Virtual destructor.
330 virtual ~Constraint()
332 // This is not responsible for removing constraints.
338 * Private constructor; see also Constraint::New().
340 Constraint( Object& object,
341 Property::Index targetIndex,
342 SourceContainer& sources,
343 ConstraintFunctionPtr& func )
344 : ConstraintBase( object, targetIndex, sources ),
345 mTargetIndex( targetIndex ),
346 mUserFunction( func )
351 Constraint( const Constraint& );
354 Constraint& operator=( const Constraint& rhs );
357 * Create and connect a constraint for a scene-object.
359 void ConnectConstraint()
361 // Should not come here if target-object has been destroyed
362 DALI_ASSERT_DEBUG( NULL != mTargetObject );
364 // Guard against double connections
365 DALI_ASSERT_DEBUG( NULL == mSceneGraphConstraint );
367 // Short-circuit until the target scene-object exists
368 SceneGraph::PropertyOwner* targetObject = const_cast< SceneGraph::PropertyOwner* >( mTargetObject->GetSceneObject() );
369 if ( NULL == targetObject )
374 // Build a container of property-owners, providing the scene-graph properties
375 SceneGraph::PropertyOwnerContainer propertyOwners;
376 propertyOwners.PushBack( targetObject );
378 // Build the constraint function; this requires a scene-graph property from each source
379 ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
383 // Create the SceneGraphConstraint, and connect to the scene-graph
385 const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex );
387 // The targetProperty should exist, when targetObject exists
388 DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
390 const int componentIndex = mTargetObject->GetPropertyComponentIndex( mTargetIndex );
392 SceneGraph::ConstraintBase* sceneGraphConstraint( NULL );
394 if ( Property::INVALID_COMPONENT_INDEX == componentIndex )
396 // Not a Vector3 or Vector4 component, expecting float type
397 DALI_ASSERT_DEBUG( PropertyTypes::Get< float >() == targetProperty->GetType() );
399 typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
401 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty,
407 // Expecting Vector3 or Vector4 type
409 if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
411 // Constrain float component of Vector3 property
413 if ( 0 == componentIndex )
415 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> > SceneGraphConstraint;
416 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
418 else if ( 1 == componentIndex )
420 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> > SceneGraphConstraint;
421 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
423 else if ( 2 == componentIndex )
425 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
426 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
429 else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
431 // Constrain float component of Vector4 property
433 if ( 0 == componentIndex )
435 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> > SceneGraphConstraint;
436 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
438 else if ( 1 == componentIndex )
440 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> > SceneGraphConstraint;
441 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
443 else if ( 2 == componentIndex )
445 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> > SceneGraphConstraint;
446 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
448 else if ( 3 == componentIndex )
450 typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
451 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
456 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
457 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
459 // object is being used in a separate thread; queue a message to apply the constraint
460 ApplyConstraintMessage( GetEventThreadServices(), *targetObject, *sceneGraphConstraint );
462 // Keep a raw-pointer to the scene-graph constraint
463 mSceneGraphConstraint = sceneGraphConstraint;
468 * Helper for ConnectConstraint. Creates a connected constraint-function.
469 * Also populates the property-owner container, for each input connected to the constraint-function.
470 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
471 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
473 PropertyConstraint<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
475 PropertyConstraint<float>* func = mUserFunction->Clone();
477 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
479 Source& source = *iter;
481 PropertyInputImpl* inputProperty( NULL );
482 int componentIndex( Property::INVALID_COMPONENT_INDEX );
484 if ( OBJECT_PROPERTY == source.sourceType )
486 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
488 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
490 // The property owner will not exist, if the target object is off-stage
493 AddUnique( propertyOwners, owner );
494 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
495 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
497 // The scene-object property should exist, when the property owner exists
498 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
501 else if ( LOCAL_PROPERTY == source.sourceType )
503 DALI_ASSERT_ALWAYS( mTargetObject->IsPropertyAConstraintInput( source.propertyIndex ) );
505 inputProperty = const_cast< PropertyInputImpl* >( mTargetObject->GetSceneObjectInputProperty( source.propertyIndex ) );
506 componentIndex = mTargetObject->GetPropertyComponentIndex( source.propertyIndex );
508 // The target scene-object should provide this property
509 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
513 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
515 Object* objectParent = dynamic_cast< Actor& >( *mTargetObject ).GetParent();
517 // This will not exist, if the target object is off-stage
518 if ( NULL != objectParent )
520 DALI_ASSERT_ALWAYS( objectParent->IsPropertyAConstraintInput( source.propertyIndex ) );
522 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( objectParent->GetSceneObject() );
524 // The property owner will not exist, if the parent object is off-stage
527 AddUnique( propertyOwners, owner );
528 inputProperty = const_cast< PropertyInputImpl* >( objectParent->GetSceneObjectInputProperty( source.propertyIndex ) );
529 componentIndex = objectParent->GetPropertyComponentIndex( source.propertyIndex );
531 // The scene-object property should exist, when the property owner exists
532 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
537 if ( NULL == inputProperty )
542 // Exit if a scene-graph object is not available from one of the sources
546 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
554 Property::Index mTargetIndex;
556 ConstraintFunctionPtr mUserFunction;
559 } // namespace Internal
563 #endif // __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__