1 #ifndef __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
2 #define __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
5 * Copyright (c) 2015 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 Vector2, 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 Vector2, Vector3 or Vector4 type
409 if ( PropertyTypes::Get< Vector2 >() == targetProperty->GetType() )
411 // Constrain float component of Vector2 property
413 if ( 0 == componentIndex )
415 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector2> > SceneGraphConstraint;
416 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
418 else if ( 1 == componentIndex )
420 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector2> > SceneGraphConstraint;
421 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
424 else if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
426 // Constrain float component of Vector3 property
428 if ( 0 == componentIndex )
430 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> > SceneGraphConstraint;
431 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
433 else if ( 1 == componentIndex )
435 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> > SceneGraphConstraint;
436 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
438 else if ( 2 == componentIndex )
440 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
441 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
444 else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
446 // Constrain float component of Vector4 property
448 if ( 0 == componentIndex )
450 typedef SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> > SceneGraphConstraint;
451 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
453 else if ( 1 == componentIndex )
455 typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> > SceneGraphConstraint;
456 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
458 else if ( 2 == componentIndex )
460 typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> > SceneGraphConstraint;
461 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
463 else if ( 3 == componentIndex )
465 typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
466 sceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func );
471 DALI_ASSERT_DEBUG( NULL != sceneGraphConstraint );
472 sceneGraphConstraint->SetRemoveAction( mRemoveAction );
474 // object is being used in a separate thread; queue a message to apply the constraint
475 ApplyConstraintMessage( GetEventThreadServices(), *targetObject, *sceneGraphConstraint );
477 // Keep a raw-pointer to the scene-graph constraint
478 mSceneGraphConstraint = sceneGraphConstraint;
483 * Helper for ConnectConstraint. Creates a connected constraint-function.
484 * Also populates the property-owner container, for each input connected to the constraint-function.
485 * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
486 * @return A connected constraint-function, or NULL if the scene-graph properties are not available.
488 PropertyConstraint<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
490 PropertyConstraint<float>* func = mUserFunction->Clone();
492 for ( SourceIter iter = mSources.begin(); mSources.end() != iter; ++iter )
494 Source& source = *iter;
496 PropertyInputImpl* inputProperty( NULL );
497 int componentIndex( Property::INVALID_COMPONENT_INDEX );
499 if ( OBJECT_PROPERTY == source.sourceType )
501 DALI_ASSERT_ALWAYS( source.object->IsPropertyAConstraintInput( source.propertyIndex ) );
503 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( source.object->GetSceneObject() );
505 // The property owner will not exist, if the target object is off-stage
508 AddUnique( propertyOwners, owner );
509 inputProperty = const_cast< PropertyInputImpl* >( source.object->GetSceneObjectInputProperty( source.propertyIndex ) );
510 componentIndex = source.object->GetPropertyComponentIndex( source.propertyIndex );
512 // The scene-object property should exist, when the property owner exists
513 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
516 else if ( LOCAL_PROPERTY == source.sourceType )
518 DALI_ASSERT_ALWAYS( mTargetObject->IsPropertyAConstraintInput( source.propertyIndex ) );
520 inputProperty = const_cast< PropertyInputImpl* >( mTargetObject->GetSceneObjectInputProperty( source.propertyIndex ) );
521 componentIndex = mTargetObject->GetPropertyComponentIndex( source.propertyIndex );
523 // The target scene-object should provide this property
524 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
528 DALI_ASSERT_ALWAYS( PARENT_PROPERTY == source.sourceType && "Constraint source property type is invalid" );
530 Object* objectParent = dynamic_cast< Actor& >( *mTargetObject ).GetParent();
532 // This will not exist, if the target object is off-stage
533 if ( NULL != objectParent )
535 DALI_ASSERT_ALWAYS( objectParent->IsPropertyAConstraintInput( source.propertyIndex ) );
537 SceneGraph::PropertyOwner* owner = const_cast< SceneGraph::PropertyOwner* >( objectParent->GetSceneObject() );
539 // The property owner will not exist, if the parent object is off-stage
542 AddUnique( propertyOwners, owner );
543 inputProperty = const_cast< PropertyInputImpl* >( objectParent->GetSceneObjectInputProperty( source.propertyIndex ) );
544 componentIndex = objectParent->GetPropertyComponentIndex( source.propertyIndex );
546 // The scene-object property should exist, when the property owner exists
547 DALI_ASSERT_ALWAYS( NULL != inputProperty && "Constraint source property does not exist" );
552 if ( NULL == inputProperty )
557 // Exit if a scene-graph object is not available from one of the sources
561 func->SetInput( ( iter - mSources.begin() ), componentIndex, *inputProperty );
569 Property::Index mTargetIndex;
571 ConstraintFunctionPtr mUserFunction;
574 } // namespace Internal
578 #endif // __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__