-#ifndef __DALI_INTERNAL_CONSTRAINT_H__
-#define __DALI_INTERNAL_CONSTRAINT_H__
+#ifndef DALI_INTERNAL_ACTIVE_CONSTRAINT_H
+#define DALI_INTERNAL_ACTIVE_CONSTRAINT_H
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
// INTERNAL INCLUDES
-#include <dali/public-api/animation/active-constraint.h>
-#include <dali/public-api/animation/alpha-functions.h>
-#include <dali/public-api/animation/constraint.h>
-#include <dali/public-api/animation/time-period.h>
-#include <dali/public-api/object/base-object.h>
+#include <dali/internal/common/message.h>
+#include <dali/internal/event/common/event-thread-services.h>
+#include <dali/internal/event/common/object-impl.h>
+#include <dali/internal/event/common/thread-local-storage.h>
+#include <dali/internal/event/common/stage-impl.h>
+#include <dali/internal/event/animation/constraint-base.h>
#include <dali/internal/event/animation/constraint-source-impl.h>
+#include <dali/internal/event/animation/property-constraint-ptr.h>
+#include <dali/internal/update/common/animatable-property.h>
+#include <dali/internal/update/common/property-owner.h>
+#include <dali/internal/update/common/property-owner-messages.h>
+#include <dali/internal/update/common/property-resetter.h>
+#include <dali/internal/update/animation/scene-graph-constraint.h>
+#include <dali/internal/update/animation/property-accessor.h>
+#include <dali/internal/update/animation/property-component-accessor.h>
+#include <memory>
namespace Dali
{
namespace Internal
{
-class ActiveConstraintBase;
-class Object;
-
/**
- * Constraints are used to constrain a property of an object, after animations have been applied.
+ * Connects a constraint which takes another property as an input.
*/
-class Constraint : public BaseObject
+template < typename PropertyType >
+class Constraint : public ConstraintBase
{
public:
- typedef Any AnyFunction;
+ using ConstraintFunctionPtr = typename PropertyConstraintPtr<PropertyType>::Type;
/**
- * Construct a new constraint which targets a property.
- * @param [in] target The index of the property to constrain.
- * @param [in] targetType The type of the constrained property.
- * @param [in] sources The objects which provide parameters for func.
- * @param [in] func The constraint function.
+ * Construct a new constraint.
+ * @param[in] object The property-owning object.
+ * @param[in] targetIndex The index of the property to constrain.
+ * @param[in] sources The sources of the input properties passed to func.
+ * @param[in] func The constraint function.
+ * @return A newly allocated active-constraint.
*/
- Constraint( Property::Index target,
- Property::Type targetType,
- SourceContainer& sources,
- AnyFunction& func );
+ static ConstraintBase* New( Object& object,
+ Property::Index targetIndex,
+ SourceContainer& sources,
+ ConstraintFunctionPtr func )
+ {
+ return new Constraint( object, targetIndex, sources, func );
+ }
/**
- * @copydoc Dali::Constraint::SetApplyTime()
+ * Virtual destructor.
*/
- void SetApplyTime( TimePeriod timePeriod );
+ virtual ~Constraint()
+ {
+ // This is not responsible for removing constraints.
+ }
- /**
- * @copydoc Dali::Constraint::GetApplyTime()
- */
- TimePeriod GetApplyTime() const;
+private:
/**
- * @copydoc Dali::Constraint::SetAlphaFunction( AlphaFunction func )
+ * @copydoc ConstraintBase::DoClone()
*/
- void SetAlphaFunction( AlphaFunction func );
+ ConstraintBase* DoClone( Object& object ) override final
+ {
+ ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
+ return new Constraint( object,
+ mTargetPropertyIndex,
+ mSources,
+ funcPtr );
+ }
/**
- * @copydoc Dali::Constraint::GetAlphaFunction()
+ * Private constructor; see also Constraint::New().
*/
- AlphaFunction GetAlphaFunction() const;
+ Constraint( Object& object,
+ Property::Index targetIndex,
+ SourceContainer& sources,
+ ConstraintFunctionPtr& func )
+ : ConstraintBase( object, targetIndex, sources ),
+ mUserFunction( func )
+ {
+ }
- /**
- * @copydoc Dali::Constraint::SetRemoveAction()
- */
- void SetRemoveAction(Dali::Constraint::RemoveAction action);
+ // Undefined
+ Constraint() = delete;
+ Constraint( const Constraint& ) = delete;
+ Constraint& operator=( const Constraint& rhs ) = delete;
- /**
- * @copydoc Dali::Constraint::GetRemoveAction()
- */
- Dali::Constraint::RemoveAction GetRemoveAction() const;
/**
- * @copydoc Dali::Constraint::SetTag()
+ * @copydoc ConstraintBase::ConnectConstraint()
*/
- void SetTag( const unsigned int tag);
+ void ConnectConstraint() override final
+ {
+ // Should not come here if target object has been destroyed
+ DALI_ASSERT_DEBUG( nullptr != mTargetObject );
+
+ // Guard against double connections
+ DALI_ASSERT_DEBUG( nullptr == mSceneGraphConstraint );
+
+ SceneGraph::PropertyOwner& targetObject = const_cast< SceneGraph::PropertyOwner& >( mTargetObject->GetSceneObject() );
+
+ // Build a container of property-owners, providing the scene-graph properties
+ SceneGraph::PropertyOwnerContainer propertyOwners;
+ propertyOwners.PushBack( &targetObject );
+
+ // Build the constraint function; this requires a scene-graph property from each source
+ ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
+
+ if ( func )
+ {
+ OwnerPointer<SceneGraph::PropertyResetterBase> resetter;
+ // Create the SceneGraphConstraint and PropertyResetter, and connect them to the scene-graph
+ const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetPropertyIndex );
+ DALI_ASSERT_ALWAYS( targetProperty && "Constraint target property does not exist" );
+ if( targetProperty->IsTransformManagerProperty() ) //It is a property managed by the transform manager
+ {
+ // Connect the constraint
+ mSceneGraphConstraint = SceneGraph::Constraint< PropertyType, TransformManagerPropertyAccessor<PropertyType> >::New( *targetProperty,
+ propertyOwners,
+ func,
+ mRemoveAction );
+ // Don't create a resetter for transform manager property, it's less efficient
+ }
+ else //SceneGraph property
+ {
+ // Connect the constraint
+ mSceneGraphConstraint = SceneGraph::Constraint< PropertyType, PropertyAccessor<PropertyType> >::New( *targetProperty,
+ propertyOwners,
+ func,
+ mRemoveAction );
+ resetter = SceneGraph::ConstraintResetter::New( targetObject, *targetProperty, *mSceneGraphConstraint );
+ }
+ OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) );
+ ApplyConstraintMessage( GetEventThreadServices(), targetObject, transferOwnership );
+ if( resetter )
+ {
+ AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter );
+ }
+ }
+ }
/**
- * @copydoc Dali::Constraint::GetTag()
+ * Helper for ConnectConstraint. Creates a connected constraint-function.
+ * Also populates the property-owner container, for each input connected to the constraint-function.
+ * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
+ * @return A connected constraint-function, or nullptr if the scene-graph properties are not available.
*/
- unsigned int GetTag() const;
+ PropertyConstraint<PropertyType>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
+ {
+ PropertyConstraint<PropertyType>* func = mUserFunction->Clone();
+ for ( auto&& source : mSources )
+ {
+ int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
+ PropertyInputImpl* inputProperty = AddInputProperty( source, propertyOwners, componentIndex );
+ if ( nullptr == inputProperty )
+ {
+ delete func;
+ func = nullptr;
+ // Exit if a scene-graph object is not available from one of the sources
+ break;
+ }
- /**
- * Create an active constraint.
- * An active constraint is created each time the constraint is applied to an object.
- * @return A newly allocated active-constraint.
- */
- ActiveConstraintBase* CreateActiveConstraint();
+ func->AddInput( inputProperty, componentIndex );
+ }
+
+ return func;
+ }
protected:
+ ConstraintFunctionPtr mUserFunction;
+
+};
+
+/**
+ * Variant which allows float components to be constrained individually.
+ */
+template <>
+class Constraint<float> : public ConstraintBase
+{
+public:
+
+ using ConstraintFunctionPtr = typename PropertyConstraintPtr<float>::Type;
+
+ /**
+ * Construct a new constraint.
+ * @param[in] object The property-owning object.
+ * @param[in] targetIndex The index of the property to constrain.
+ * @param[in] sources The sources of the input properties passed to func.
+ * @param[in] func The constraint function.
+ * @return A newly allocated constraint.
+ */
+ static ConstraintBase* New( Object& object,
+ Property::Index targetIndex,
+ SourceContainer& sources,
+ ConstraintFunctionPtr func )
+ {
+ return new Constraint( object, targetIndex, sources, func );
+ }
+
/**
- * A reference counted object may only be deleted by calling Unreference()
+ * Virtual destructor.
*/
- virtual ~Constraint();
+ virtual ~Constraint()
+ {
+ // This is not responsible for removing constraints.
+ }
private:
- // Undefined
- Constraint(const Constraint&);
+ /**
+ * @copydoc ConstraintBase::DoClone()
+ */
+ virtual ConstraintBase* DoClone( Object& object ) override final
+ {
+ ConstraintFunctionPtr funcPtr( mUserFunction->Clone() );
+ return new Constraint( object,
+ mTargetPropertyIndex,
+ mSources,
+ funcPtr );
+ }
+
+ /**
+ * Private constructor; see also Constraint::New().
+ */
+ Constraint( Object& object,
+ Property::Index targetIndex,
+ SourceContainer& sources,
+ ConstraintFunctionPtr& func )
+ : ConstraintBase( object, targetIndex, sources ),
+ mUserFunction( func )
+ {
+ }
// Undefined
- Constraint& operator=(const Constraint& rhs);
+ Constraint() = delete;
+ Constraint( const Constraint& ) = delete;
+ Constraint& operator=( const Constraint& rhs ) = delete;
-protected:
+ /**
+ * @copydoc ConstraintBase::ConnectConstraint()
+ */
+ void ConnectConstraint() override final
+ {
+ // Should not come here if target object has been destroyed
+ DALI_ASSERT_DEBUG( nullptr != mTargetObject );
+ // Guard against double connections
+ DALI_ASSERT_DEBUG( nullptr == mSceneGraphConstraint );
+
+ SceneGraph::PropertyOwner& targetObject = const_cast< SceneGraph::PropertyOwner& >( mTargetObject->GetSceneObject() );
+
+ // Build a container of property-owners, providing the scene-graph properties
+ SceneGraph::PropertyOwnerContainer propertyOwners;
+ propertyOwners.PushBack( &targetObject );
+
+ // Build the constraint function; this requires a scene-graph property from each source
+ ConstraintFunctionPtr func( ConnectConstraintFunction( propertyOwners ) );
+
+ if ( func )
+ {
+ // Create the SceneGraphConstraint, and connect to the scene-graph
+ bool resetterRequired = false;
+ const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetPropertyIndex );
+ // The targetProperty should exist, when targetObject exists
+ DALI_ASSERT_ALWAYS( nullptr != targetProperty && "Constraint target property does not exist" );
+ const int32_t componentIndex = mTargetObject->GetPropertyComponentIndex( mTargetPropertyIndex );
+ if ( Property::INVALID_COMPONENT_INDEX == componentIndex )
+ {
+ // Not a Vector2, Vector3 or Vector4 component, expecting float type
+ DALI_ASSERT_DEBUG( PropertyTypes::Get< float >() == targetProperty->GetType() );
+
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyAccessor<float> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ resetterRequired = true;
+ }
+ else
+ {
+ // Expecting Vector2, Vector3 or Vector4 type
+ if ( PropertyTypes::Get< Vector2 >() == targetProperty->GetType() )
+ {
+ // Constrain float component of Vector2 property
+ if ( 0 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector2> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ else if ( 1 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector2> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ resetterRequired = (mSceneGraphConstraint != nullptr);
+ }
+ else if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
+ {
+ // Constrain float component of Vector3 property
+ if( targetProperty->IsTransformManagerProperty() )
+ {
+ if ( 0 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, TransformManagerPropertyComponentAccessor<Vector3,0> >::New( *targetProperty,
+ propertyOwners,
+ func,
+ mRemoveAction );
+ }
+ else if ( 1 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, TransformManagerPropertyComponentAccessor<Vector3,1> >::New( *targetProperty,
+ propertyOwners,
+ func,
+ mRemoveAction );
+ }
+ else if ( 2 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, TransformManagerPropertyComponentAccessor<Vector3,2> >::New( *targetProperty,
+ propertyOwners,
+ func,
+ mRemoveAction );
+ }
+ // Do not create a resetter for transform manager property
+ }
+ else
+ {
+ if ( 0 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector3> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ else if ( 1 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector3> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ else if ( 2 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ resetterRequired = (mSceneGraphConstraint != nullptr);
+ }
+ }
+ else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
+ {
+ // Constrain float component of Vector4 property
+ if ( 0 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorX<Vector4> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ else if ( 1 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector4> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ else if ( 2 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector4> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+ else if ( 3 == componentIndex )
+ {
+ mSceneGraphConstraint = SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> >::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ }
+
+ resetterRequired = (mSceneGraphConstraint != nullptr);
+ }
+ }
+ if( mSceneGraphConstraint )
+ {
+ OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) );
+ ApplyConstraintMessage( GetEventThreadServices(), targetObject, transferOwnership );
+ if( resetterRequired )
+ {
+ OwnerPointer<SceneGraph::PropertyResetterBase> resetter = SceneGraph::ConstraintResetter::New( targetObject, *targetProperty, *mSceneGraphConstraint );
+ AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter );
+ }
+ }
+ }
+ }
- Dali::ActiveConstraint mActiveConstraintTemplate; ///< Used to create active constraints
+ /**
+ * Helper for ConnectConstraint. Creates a connected constraint-function.
+ * Also populates the property-owner container, for each input connected to the constraint-function.
+ * @param[out] propertyOwners The container of property-owners providing the scene-graph properties.
+ * @return A connected constraint-function, or nullptr if the scene-graph properties are not available.
+ */
+ PropertyConstraint<float>* ConnectConstraintFunction( SceneGraph::PropertyOwnerContainer& propertyOwners )
+ {
+ PropertyConstraint<float>* func = mUserFunction->Clone();
- TimePeriod mApplyTime;
-};
+ for ( auto&& source : mSources )
+ {
+ int32_t componentIndex = Property::INVALID_COMPONENT_INDEX;
+ PropertyInputImpl* inputProperty = AddInputProperty( source, propertyOwners, componentIndex );
-} // namespace Internal
+ if ( nullptr == inputProperty )
+ {
+ delete func;
+ func = nullptr;
-// Helpers for public-api forwarding methods
+ // Exit if a scene-graph object is not available from one of the sources
+ break;
+ }
-inline Internal::Constraint& GetImplementation(Dali::Constraint& constraint)
-{
- DALI_ASSERT_ALWAYS( constraint && "Constraint handle is empty" );
+ func->AddInput( inputProperty, componentIndex );
+ }
- BaseObject& handle = constraint.GetBaseObject();
+ return func;
+ }
- return static_cast<Internal::Constraint&>(handle);
-}
+protected:
-inline const Internal::Constraint& GetImplementation(const Dali::Constraint& constraint)
-{
- DALI_ASSERT_ALWAYS( constraint && "Constraint handle is empty" );
+ ConstraintFunctionPtr mUserFunction;
- const BaseObject& handle = constraint.GetBaseObject();
+};
- return static_cast<const Internal::Constraint&>(handle);
-}
+} // namespace Internal
} // namespace Dali
-#endif // __DALI_INTERNAL_CONSTRAINT_H__
+#endif // DALI_INTERNAL_ACTIVE_CONSTRAINT_H