Currently all default and custom animated properties are reset each frame.
This is wasteful, as unnecessary time is spent setting the same value again and again.
Instead, have added a new PropertyResetter, which is created when a property is being
animated or constrained. This is responsible for resetting the double buffered values
of that property.
Transform Manager properties are unaffected, as the reset is a single memset/memcpy
that handles all such properties at once, and is much faster than resetting properties
individually.
Added a PropertyResetter to animators.
Removed property reset from everything except transform manager.
Ensured property resetters die with animators
Added lifecycle observer to scene graph animators
Hooked up property resetter to observe animator destruction
Added aging to property resetter to ensure it resets for another frame after
animator death
Added constraint resetters
Changing connection to disconnection tracking fixes constraint velocity issue
Also changed Property::Bake to write to both buffer indexed values.
Ensured property resetters destroyed after animations ( animators have a resetter
observing destruction; order matters ).
Change-Id: Ia11f0e45744b09859ce1b87f306e1829efbb8fac
Signed-off-by: David Steele <david.steele@samsung.com>
#define __DALI_INTERNAL_ANIMATOR_CONNECTOR_H__
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
#include <dali/internal/update/common/property-owner.h>
#include <dali/internal/update/animation/property-accessor.h>
#include <dali/internal/update/animation/property-component-accessor.h>
+#include <dali/internal/update/common/property-resetter.h>
#include <dali/internal/update/manager/update-manager.h>
namespace Dali
{
/**
- * AnimatorConnector is used to connect SceneGraph::Animators for newly created scene-graph objects.
+ * AnimatorConnector is used to connect SceneGraph::Animators and
+ * PropertyResetters for newly created scene-graph objects.
*
* SceneGraph::Animators weakly reference scene objects, and are automatically deleted when orphaned.
* Therefore the AnimatorConnector is NOT responsible for disconnecting animators.
mObject->RemoveObserver( *this );
}
- //If there is not a SceneGraph::Animator, the AnimatorConnector is responsible for deleting the mAnimatorFunction
- //otherwise, the animator function ownership is transferred to the SceneGraph::Animator
+ // If there is not a SceneGraph::Animator, the AnimatorConnector is responsible for deleting the mAnimatorFunction
+ // otherwise, the animator function ownership is transferred to the SceneGraph::Animator
if( !mAnimator )
{
delete mAnimatorFunction;
}
/**
- * Helper function to create a Scenegraph::Animator and add it to its correspondent SceneGraph::Animation.
+ * Helper function to create a Scenegraph::Animator and PropertyResetter and add it to its correspondent
+ * SceneGraph::Animation.
+ *
* @note This function will only be called the first time the object is added to the scene or at creation time if
* the object was already in the scene
*/
//Get the PropertyOwner the animator is going to animate
const SceneGraph::PropertyOwner* propertyOwner = mObject->GetSceneObject();
- //Get SceneGraph::BaseProperty
+ // Get SceneGraph::BaseProperty
const SceneGraph::PropertyBase* baseProperty = mObject->GetSceneObjectAnimatableProperty( mPropertyIndex );
- //Check if property is a component of another property
+ OwnerPointer<SceneGraph::PropertyResetterBase> resetter;
+
+ // Check if property is a component of another property
const int componentIndex = mObject->GetPropertyComponentIndex( mPropertyIndex );
if( componentIndex != Property::INVALID_COMPONENT_INDEX )
{
if( mComponentIndex == Property::INVALID_COMPONENT_INDEX )
{
- ///Animating the whole property
+ // Animating the whole property
- //Cast to AnimatableProperty
+ // Cast to AnimatableProperty
const PropertyInterfaceType* animatableProperty = dynamic_cast< const PropertyInterfaceType* >( baseProperty );
if( animatableProperty == NULL )
if( baseProperty->IsTransformManagerProperty() )
{
mAnimator = SceneGraph::AnimatorTransformProperty< PropertyType,TransformManagerPropertyAccessor<PropertyType> >::New( *propertyOwner, *baseProperty, mAnimatorFunction, mAlphaFunction, mTimePeriod );
+ // Don't reset transform manager properties - TransformManager will do it more efficiently
}
else
{
}
else
{
- //Create the animator
- mAnimator = AnimatorType::New( *propertyOwner, *animatableProperty, mAnimatorFunction, mAlphaFunction, mTimePeriod );
+ // Create the animator and resetter
+ mAnimator = AnimatorType::New( *propertyOwner, *animatableProperty, mAnimatorFunction,
+ mAlphaFunction, mTimePeriod );
+ resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
}
-
}
else
{
{
- ///Animating a component of the property
+ // Animating a component of the property
if ( PropertyTypes::Get< Vector2 >() == baseProperty->GetType() )
{
// Animate float component of Vector2 property
break;
}
}
+
+ if( mAnimator != nullptr )
+ {
+ resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
+ }
}
else if ( PropertyTypes::Get< Vector3 >() == baseProperty->GetType() )
{
DALI_ASSERT_DEBUG( animatableProperty != NULL && "Animating non-animatable property" );
}
+ // Don't manually reset transform property - TransformManager will do it more efficiently
}
else
{
- //Dynamic cast will fail if BaseProperty is not a Vector3 AnimatableProperty
+ // Dynamic cast will fail if BaseProperty is not a Vector3 AnimatableProperty
DALI_ASSERT_DEBUG( animatableProperty != NULL && "Animating non-animatable property" );
switch( mComponentIndex )
break;
}
}
+
+ if( mAnimator != nullptr )
+ {
+ resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
+ }
}
}
else if ( PropertyTypes::Get< Vector4 >() == baseProperty->GetType() )
break;
}
}
+ if( mAnimator != nullptr )
+ {
+ resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
+ }
}
}
}
const SceneGraph::Animation* animation = mParent->GetSceneObject();
DALI_ASSERT_DEBUG( NULL != animation );
AddAnimatorMessage( mParent->GetEventThreadServices(), *animation, *mAnimator );
+
+ // Add the new SceneGraph::PropertyResetter to the update manager via message
+ if( resetter != nullptr )
+ {
+ AddResetterMessage( mParent->GetEventThreadServices().GetUpdateManager(), resetter );
+ }
}
protected:
#define __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
#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
{
Constraint& operator=( const Constraint& rhs );
/**
- * Create and connect a constraint for a scene-object.
+ * Create and connect a constraint and property resetter for a scene-graph property
*/
void ConnectConstraint()
{
- // Should not come here if target-object has been destroyed
+ // Should not come here if target object has been destroyed
DALI_ASSERT_DEBUG( NULL != mTargetObject );
// Guard against double connections
if ( func )
{
- // Create the SceneGraphConstraint, and connect to the scene-graph
+ // Create the SceneGraphConstraint and PropertyResetter, and connect them to the scene-graph
const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex );
+ OwnerPointer<SceneGraph::PropertyResetterBase> resetter;
// The targetProperty should exist, when targetObject exists
DALI_ASSERT_ALWAYS( NULL != 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 );
+ 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
{
propertyOwners,
func,
mRemoveAction );
+ // Connect the resetter
+ resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
+
}
OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) );
ApplyConstraintMessage( GetEventThreadServices(), *targetObject, transferOwnership );
+
+ if( resetter != nullptr )
+ {
+ AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter );
+ }
}
}
// Create the SceneGraphConstraint, and connect to the scene-graph
const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex );
+ OwnerPointer<SceneGraph::PropertyResetterBase> resetter;
// The targetProperty should exist, when targetObject exists
DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" );
typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
+ resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
}
else
{
typedef SceneGraph::Constraint< float, PropertyComponentAccessorY<Vector2> > SceneGraphConstraint;
mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
}
+ if( mSceneGraphConstraint )
+ {
+ resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
+ }
}
else if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() )
{
typedef SceneGraph::Constraint< float, TransformManagerPropertyComponentAccessor<Vector3,2> > SceneGraphConstraint;
mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
}
+ // Do not create a resetter for transform manager property
}
else
{
typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ<Vector3> > SceneGraphConstraint;
mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
}
+ if( mSceneGraphConstraint )
+ {
+ resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
+ }
}
}
else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() )
typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
}
+
+ if( mSceneGraphConstraint )
+ {
+ resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
+ }
}
}
OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) );
ApplyConstraintMessage( GetEventThreadServices(), *targetObject, transferOwnership );
}
+ if( resetter != nullptr )
+ {
+ AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter );
+ }
}
}
#define __DALI_INTERNAL_SCENE_GRAPH_PROPERTY_ACCESSOR_H__
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
#define __DALI_INTERNAL_SCENE_GRAPH_ANIMATOR_H__
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
typedef float (*AlphaFunc)(float progress); ///< Definition of an alpha function
/**
+ * Observer to determine when the animator is no longer present
+ */
+ class LifecycleObserver
+ {
+ public:
+ /**
+ * Called shortly before the animator is destroyed.
+ */
+ virtual void ObjectDestroyed() = 0;
+
+ protected:
+ /**
+ * Virtual destructor, no deletion through this interface
+ */
+ virtual ~LifecycleObserver() = default;
+ };
+
+
+ /**
* Constructor.
*/
AnimatorBase()
- : mDurationSeconds(1.0f),
+ : mLifecycleObserver(nullptr),
+ mDurationSeconds(1.0f),
mIntervalDelaySeconds(0.0f),
mSpeedFactor(1.0f),
mLoopCount(1),
*/
virtual ~AnimatorBase()
{
+ if( mLifecycleObserver != nullptr )
+ {
+ mLifecycleObserver->ObjectDestroyed();
+ }
+ }
+
+ void AddLifecycleObserver( LifecycleObserver& observer )
+ {
+ mLifecycleObserver = &observer;
+ }
+
+ void RemoveLifecycleObserver( LifecycleObserver& observer )
+ {
+ mLifecycleObserver = nullptr;
}
/**
return 3.0f*(1.0f-t)*(1.0f-t)*t*p0 + 3.0f*(1.0f-t)*tSquare*p1 + tSquare*t;
}
+ LifecycleObserver* mLifecycleObserver;
float mDurationSeconds;
float mIntervalDelaySeconds;
float mSpeedFactor;
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
: mRemoveAction( removeAction ),
mFirstApply( true ),
mDisconnected( true ),
- mObservedOwners( ownerSet )
+ mObservedOwners( ownerSet ),
+ mLifecycleObserver( nullptr )
{
#ifdef DEBUG_ENABLED
++mCurrentInstanceCount;
StopObservation();
}
+ if( mLifecycleObserver != nullptr )
+ {
+ mLifecycleObserver->ObjectDestroyed();
+ }
+
#ifdef DEBUG_ENABLED
--mCurrentInstanceCount;
#endif
}
-void ConstraintBase::ResetDefaultProperties( BufferIndex updateBufferIndex )
-{
- DALI_ASSERT_DEBUG( false );
-}
-
unsigned int ConstraintBase::GetCurrentInstanceCount()
{
#ifdef DEBUG_ENABLED
#define __DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H__
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
class ConstraintBase : public PropertyOwner::Observer
{
public:
+ /**
+ * Observer to determine when the constraint is no longer present
+ */
+ class LifecycleObserver
+ {
+ public:
+ /**
+ * Called shortly before the constraint is destroyed.
+ */
+ virtual void ObjectDestroyed() = 0;
+
+ protected:
+ /**
+ * Virtual destructor, no deletion through this interface
+ */
+ virtual ~LifecycleObserver() = default;
+ };
+
+public:
typedef Dali::Constraint::RemoveAction RemoveAction;
virtual ~ConstraintBase();
/**
+ * Property resetter observes the lifecycle of this object
+ */
+ void AddLifecycleObserver( LifecycleObserver& observer )
+ {
+ mLifecycleObserver = &observer;
+ }
+
+ /**
+ * Property resetter observers the lifecycle of this object
+ */
+ void RemoveLifecycleObserver( LifecycleObserver& observer )
+ {
+ mLifecycleObserver = nullptr;
+ }
+
+ /**
* Initialize the constraint.
* This should by called by a scene-object, when the constraint is connected.
*/
}
/**
- * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties()
- */
- virtual void ResetDefaultProperties( BufferIndex updateBufferIndex );
-
- /**
* Notify the derived class to disconnect from property owners
*/
virtual void OnDisconnect() = 0;
private:
PropertyOwnerContainer mObservedOwners; ///< A set of pointers to each observed object. Not owned.
+ LifecycleObserver* mLifecycleObserver; ///< Resetter observers this object
#ifdef DEBUG_ENABLED
static unsigned int mCurrentInstanceCount; ///< The current number of Constraint instances in existence.
#define __DALI_INTERNAL_SCENE_GRAPH_ANIMATABLE_PROPERTY_H__
/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
if( mBaseValue != value )
{
mBaseValue = value;
+ // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side
+ // has never been atomically safe.
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
OnBake();
}
void Bake(BufferIndex bufferIndex, int value)
{
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = mValue[bufferIndex];
OnBake();
*/
void Bake(BufferIndex bufferIndex, float value)
{
+ // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side
+ // has never been atomically safe.
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = mValue[bufferIndex];
OnBake();
*/
void Bake(BufferIndex bufferIndex, const Vector2& value)
{
+ // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side
+ // has never been atomically safe.
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = value;
OnBake();
void BakeX(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].x = value;
+ mValue[1-bufferIndex].x = value;
mBaseValue.x = value;
OnBake();
void BakeY(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].y = value;
+ mValue[1-bufferIndex].y = value;
mBaseValue.y = value;
OnBake();
void Bake(BufferIndex bufferIndex, const Vector3& value)
{
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = value;
OnBake();
void BakeX(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].x = value;
+ mValue[1-bufferIndex].x = value;
mBaseValue.x = value;
OnBake();
void BakeY(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].y = value;
+ mValue[1-bufferIndex].y = value;
mBaseValue.y = value;
OnBake();
void BakeZ(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].z = value;
+ mValue[1-bufferIndex].z = value;
mBaseValue.z = value;
OnBake();
void Bake(BufferIndex bufferIndex, const Vector4& value)
{
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = mValue[bufferIndex];
OnBake();
void BakeX(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].x = value;
+ mValue[1-bufferIndex].x = value;
mBaseValue.x = mValue[bufferIndex].x;
OnBake();
void BakeY(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].y = value;
+ mValue[1-bufferIndex].y = value;
mBaseValue.y = mValue[bufferIndex].y;
OnBake();
void BakeZ(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].z = value;
+ mValue[1-bufferIndex].z = value;
mBaseValue.z = mValue[bufferIndex].z;
OnBake();
void BakeW(BufferIndex bufferIndex, float value)
{
mValue[bufferIndex].w = value;
+ mValue[1-bufferIndex].w = value;
mBaseValue.w = mValue[bufferIndex].w;
OnBake();
*/
void Bake(BufferIndex bufferIndex, const Quaternion& value)
{
+ // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side
+ // has never been atomically safe.
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = value;
OnBake();
*/
void Bake(BufferIndex bufferIndex, const Matrix& value)
{
+ // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side
+ // has never been atomically safe.
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = mValue[bufferIndex];
OnBake();
*/
void Bake(BufferIndex bufferIndex, const Matrix3& value)
{
+ // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side
+ // has never been atomically safe.
mValue[bufferIndex] = value;
+ mValue[1-bufferIndex] = value;
mBaseValue = mValue[bufferIndex];
OnBake();
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
mCustomProperties.PushBack( property.Release() );
}
-void PropertyOwner::ResetToBaseValues( BufferIndex updateBufferIndex )
-{
- // Reset custom properties
- const OwnedPropertyIter endIter = mCustomProperties.End();
- for ( OwnedPropertyIter iter = mCustomProperties.Begin(); endIter != iter; ++iter )
- {
- (*iter)->ResetToBaseValue( updateBufferIndex );
- }
-
- // Notification for derived classes, to reset default properties
- ResetDefaultProperties( updateBufferIndex );
-}
ConstraintOwnerContainer& PropertyOwner::GetConstraints()
{
#define __DALI_INTERNAL_SCENE_GRAPH_PROPERTY_OWNER_H__
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
return mCustomProperties;
}
- /**
- * Reset animatable properties to the corresponding base values.
- * @param[in] currentBufferIndex The buffer to reset.
- * @post The ResetDefaultProperties method is called, during which derived classes can reset default properties.
- */
- void ResetToBaseValues( BufferIndex updateBufferIndex );
// Constraints
// Undefined
PropertyOwner& operator=(const PropertyOwner& rhs);
- /**
- * Called after ResetToBaseValues; derived classes should reset any default properties.
- * @param[in] currentBufferIndex The buffer to reset.
- */
- virtual void ResetDefaultProperties( BufferIndex updateBufferIndex ) {}
-
protected:
OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty()
--- /dev/null
+#ifndef DALI_INTERNAL_SCENEGRAPH_PROPERTY_RESETTER_H
+#define DALI_INTERNAL_SCENEGRAPH_PROPERTY_RESETTER_H
+
+/*
+ * Copyright (c) 2018 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/internal/update/animation/scene-graph-animator.h>
+#include <dali/internal/update/animation/scene-graph-constraint-base.h>
+#include <dali/internal/update/animation/property-accessor.h>
+#include <dali/internal/update/animation/property-component-accessor.h>
+#include <dali/internal/update/common/property-owner.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace SceneGraph
+{
+
+/**
+ * Class to reset the watched property to it's base value. Used by UpdateManager to
+ * reset animating and constrained properties. The derived classes AnimatorResetter and
+ * ConstraintResetter are designed to match the lifecycle of the SceneGraph::Animator
+ * and SceneGraph::Constraint respectively.
+ */
+class PropertyResetterBase : public PropertyOwner::Observer
+{
+public:
+ /**
+ * Virtual Destructor
+ */
+ virtual ~PropertyResetterBase()
+ {
+ if( mPropertyOwner != nullptr )
+ {
+ mPropertyOwner->RemoveObserver(*this);
+ }
+ }
+
+ /**
+ * Initialize.
+ *
+ * Watches the property owner to track if it's disconnected or not.
+ */
+ void Initialize()
+ {
+ mPropertyOwner->AddObserver(*this);
+ }
+
+ /**
+ * Reset the property to it's base value if the property owner is still alive and on stage
+ * @param[in] updateBufferIndex the current buffer index
+ */
+ void ResetToBaseValue( BufferIndex updateBufferIndex )
+ {
+ if( mPropertyOwner != nullptr && !mDisconnected )
+ {
+ mBaseProperty->ResetToBaseValue( updateBufferIndex );
+ }
+ };
+
+ /**
+ * Called when mPropertyOwner is connected to the scene graph.
+ *
+ * Note, this resetter object may be created after the property owner has been connected
+ * to the stage, so we track disconnection and re-connection instead of connection
+ *
+ * @param[in] owner The property owner
+ */
+ virtual void PropertyOwnerConnected( PropertyOwner& owner ) override
+ {
+ mDisconnected = false;
+ }
+
+ /**
+ * Called when mPropertyOwner is disconnected from the scene graph.
+ * @param[in] bufferIndex the current buffer index
+ * @param[in] owner The property owner
+ */
+ virtual void PropertyOwnerDisconnected( BufferIndex bufferIndex, PropertyOwner& owner ) override
+ {
+ mDisconnected = true;
+ }
+
+ /**
+ * Called shortly before the propertyOwner is destroyed
+ * @param[in] owner The property owner
+ */
+ virtual void PropertyOwnerDestroyed( PropertyOwner& owner ) override
+ {
+ mDisconnected = true;
+ mPropertyOwner = nullptr;
+
+ // Don't need to wait another frame as the property is being destroyed
+ mRunning = 0;
+ }
+
+ /**
+ * Determine if the resetter has finished.
+ *
+ * If an animation or constraint stops, then we need to reset the
+ * property in the next frame as well to ensure both property values
+ * are set appropriately.
+ *
+ * @return true if the resetter has finished.
+ */
+ virtual bool IsFinished()
+ {
+ bool finished = mRunning <= 0;
+ if( mRunning == 1 )
+ {
+ mRunning = 0;
+ }
+ return finished;
+ }
+
+protected:
+
+ /**
+ * Constructor
+ *
+ * @param[in] propertyOwner The property owner storing the base property
+ * @param[in] baseProperty The base property
+ */
+ PropertyResetterBase( PropertyOwner* propertyOwner,
+ PropertyBase* baseProperty )
+ : mPropertyOwner( propertyOwner ),
+ mBaseProperty( baseProperty ),
+ mRunning( 2 ),
+ mDisconnected( false )
+ {
+ }
+
+ PropertyOwner* mPropertyOwner; ///< The property owner
+ PropertyBase* mBaseProperty; ///< The base property being animated or constrained
+ int mRunning; ///< 2 if running, 1 if aging, 0 if stopped
+ bool mDisconnected; ///< True if the property owner has been disconnected
+};
+
+
+/**
+ * Specialization of Resetter based on templated modifier type (either Constraint or Animator)
+ */
+template< typename ModifierType>
+class Resetter : public PropertyResetterBase, public ModifierType::LifecycleObserver
+{
+public:
+
+ /**
+ * New method.
+ * @param[in] propertyOwner The owner of the property
+ * @param[in] baseProperty The property being animated
+ * @param[in] modifier The scene-graph animator/constraint of the property
+ * @return the new property resetter
+ */
+ static PropertyResetterBase* New( const PropertyOwner& propertyOwner,
+ const PropertyBase& baseProperty,
+ const ModifierType& modifier )
+ {
+ return new Resetter<ModifierType>( const_cast<PropertyOwner*>( &propertyOwner ),
+ const_cast<PropertyBase*>( &baseProperty ),
+ const_cast<ModifierType*>( &modifier ) );
+ }
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~Resetter()
+ {
+ // Disconnect from modifier object. Although this resetter should match the lifecycle of the modifier object,
+ // there are situations where it is deleted first (e.g. if the property owner is destroyed)
+ if( mModifier )
+ {
+ mModifier->RemoveLifecycleObserver(*this);
+ }
+ }
+
+private:
+ /**
+ * Constructor
+ * @param[in] propertyOwner The owner of the property
+ * @param[in] baseProperty The property being animated
+ * @param[in] modifier The scene-graph animator/constraint of the property
+ */
+ Resetter( PropertyOwner* propertyOwner,
+ PropertyBase* baseProperty,
+ ModifierType* modifier )
+ : PropertyResetterBase( propertyOwner, baseProperty ),
+ mModifier( modifier )
+ {
+ // Track the lifecycle of the modifying object
+ mModifier->AddLifecycleObserver(*this);
+ }
+
+ /**
+ * The Animator or Constraint is destroyed
+ */
+ virtual void ObjectDestroyed() override
+ {
+ // When the modifier is destroyed, reduce the running value to ensure we stay alive for
+ // another frame to reset the other buffer.
+ --mRunning;
+ mModifier = nullptr;
+ }
+
+ ModifierType* mModifier;
+};
+
+
+typedef Resetter<SceneGraph::AnimatorBase> AnimatorResetter;
+typedef Resetter<SceneGraph::ConstraintBase> ConstraintResetter;
+
+
+
+} // namespace SceneGraph
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif //DALI_INTERNAL_SCENEGRAPH_PROPERTY_RESETTER_H
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
* Constrain the local properties of the PropertyOwner.
* @param propertyOwner to constrain
* @param updateBufferIndex buffer index to use
- * @return The number of constraints that are still being applied
*/
void ConstrainPropertyOwner( PropertyOwner& propertyOwner, BufferIndex updateBufferIndex )
{
Layer& currentLayer,
int inheritedDrawMode )
{
- //Apply constraints to the node
+ // Apply constraints to the node
ConstrainPropertyOwner( node, updateBufferIndex );
// Short-circuit for invisible nodes
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
OwnerContainer< Camera* > cameras; ///< A container of cameras
OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
+ OwnerContainer< PropertyResetterBase* > propertyResetters; ///< A container of property resetters
AnimationContainer animations; ///< A container of owned animations
PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
-
OwnerContainer< Renderer* > renderers; ///< A container of owned renderers
OwnerContainer< TextureSet* > textureSets; ///< A container of owned texture sets
OwnerContainer< Shader* > shaders; ///< A container of owned shaders
return false;
}
+void UpdateManager::AddPropertyResetter( OwnerPointer<PropertyResetterBase>& propertyResetter )
+{
+ propertyResetter->Initialize();
+ mImpl->propertyResetters.PushBack( propertyResetter.Release() );
+}
+
void UpdateManager::AddPropertyNotification( OwnerPointer< PropertyNotification >& propertyNotification )
{
mImpl->propertyNotifications.PushBack( propertyNotification.Release() );
// Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
mImpl->animationFinishedDuringUpdate = false;
- // Animated properties have to be reset to their original value each frame
-
- // Reset root properties
- if ( mImpl->root )
+ // Reset all animating / constrained properties
+ std::vector<PropertyResetterBase*>toDelete;
+ for( auto&& element : mImpl->propertyResetters )
{
- mImpl->root->ResetToBaseValues( bufferIndex );
+ element->ResetToBaseValue( bufferIndex );
+ if( element->IsFinished() )
+ {
+ toDelete.push_back( element );
+ }
}
- if ( mImpl->systemLevelRoot )
+
+ // If a resetter is no longer required (the animator or constraint has been removed), delete it.
+ for( auto&& elementPtr : toDelete )
{
- mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex );
+ mImpl->propertyResetters.EraseObject( elementPtr );
}
- // Reset all the nodes
+ // Clear node dirty flags
Vector<Node*>::Iterator iter = mImpl->nodes.Begin()+1;
Vector<Node*>::Iterator endIter = mImpl->nodes.End();
for( ;iter != endIter; ++iter )
{
- (*iter)->ResetToBaseValues( bufferIndex );
+ (*iter)->ResetDirtyFlags( bufferIndex );
}
-
- // Reset system-level render-task list properties to base values
- ResetToBaseValues( mImpl->systemLevelTaskList.GetTasks(), bufferIndex );
-
- // Reset render-task list properties to base values.
- ResetToBaseValues( mImpl->taskList.GetTasks(), bufferIndex );
-
- // Reset custom object properties to base values
- ResetToBaseValues( mImpl->customObjects, bufferIndex );
-
- // Reset animatable renderer properties to base values
- ResetToBaseValues( mImpl->renderers, bufferIndex );
-
- // Reset animatable shader properties to base values
- ResetToBaseValues( mImpl->shaders, bufferIndex );
}
bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
//Update renderers and apply constraints
UpdateRenderers( bufferIndex );
- //Update the trnasformations of all the nodes
+ //Update the transformations of all the nodes
mImpl->transformManager.Update();
//Process Property Notifications
#define DALI_INTERNAL_SCENE_GRAPH_UPDATE_MANAGER_H
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
#include <dali/internal/common/shader-saver.h>
#include <dali/internal/event/common/event-thread-services.h>
#include <dali/internal/update/animation/scene-graph-animation.h>
+#include <dali/internal/update/common/property-resetter.h>
#include <dali/internal/update/common/scene-graph-buffers.h>
#include <dali/internal/update/common/scene-graph-property-notification.h>
#include <dali/internal/update/nodes/node.h>
*/
bool IsAnimationRunning() const;
+ /**
+ * Add a property resetter. UpdateManager takes ownership of the object.
+ * It will be killed by UpdateManager when the associated animator or
+ * constraint has finished; or the property owner of the property is destroyed.
+ */
+ void AddPropertyResetter( OwnerPointer<PropertyResetterBase>& propertyResetter );
+
// Property Notification
/**
new (slot) LocalType( &manager, &UpdateManager::SetDepthIndices, nodeDepths );
}
+inline void AddResetterMessage( UpdateManager& manager, OwnerPointer<PropertyResetterBase> resetter )
+{
+ typedef MessageValue1< UpdateManager, OwnerPointer<PropertyResetterBase> > LocalType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) LocalType( &manager, &UpdateManager::AddPropertyResetter, resetter );
+}
+
+
} // namespace SceneGraph
} // namespace Internal
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
return flags;
}
-void Node::ResetDefaultProperties( BufferIndex updateBufferIndex )
+void Node::ResetDirtyFlags( BufferIndex updateBufferIndex )
{
- mVisible.ResetToBaseValue( updateBufferIndex );
- mColor.ResetToBaseValue( updateBufferIndex );
-
mDirtyFlags = NothingFlag;
}
#define DALI_INTERNAL_SCENE_GRAPH_NODE_H
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
*/
void CreateTransform( SceneGraph::TransformManager* transformManager );
+ /**
+ * Reset dirty flags
+ */
+ void ResetDirtyFlags( BufferIndex updateBufferIndex );
+
protected:
/**
Node& operator=(const Node& rhs);
/**
- * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties()
- */
- virtual void ResetDefaultProperties( BufferIndex updateBufferIndex );
-
- /**
* Recursive helper to disconnect a Node and its children.
* Disconnected Nodes have no parent or children.
* @param[in] updateBufferIndex The current update buffer index.
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
mRequiresSync = requiresSync;
}
-void RenderTask::ResetDefaultProperties( BufferIndex updateBufferIndex )
-{
- // Reset default properties
- mViewportPosition.ResetToBaseValue( updateBufferIndex );
- mViewportSize.ResetToBaseValue( updateBufferIndex );
- mClearColor.ResetToBaseValue( updateBufferIndex );
-}
RenderTask::RenderTask()
: mViewportPosition( Vector2::ZERO),
#define DALI_INTERNAL_SCENE_GRAPH_RENDER_TASK_H
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
// Undefined
RenderTask& operator=(const RenderTask&);
-private: // PropertyOwner
-
- virtual void ResetDefaultProperties( BufferIndex currentBufferIndex );
public: // Animatable Properties
AnimatableProperty< Vector2 > mViewportPosition; ///< viewportPosition