[4.0] Changed Update to reset only target properties each frame 06/168606/1
authorDavid Steele <david.steele@samsung.com>
Wed, 24 Jan 2018 13:59:55 +0000 (13:59 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Mon, 29 Jan 2018 21:53:07 +0000 (21:53 +0000)
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>
(cherry picked from commit 39093bc48ee4ed2b4956c183faf59c36f3e9746c)

17 files changed:
dali/internal/event/animation/animator-connector.h
dali/internal/event/animation/constraint-impl.h
dali/internal/update/animation/property-accessor.h
dali/internal/update/animation/scene-graph-animator.h
dali/internal/update/animation/scene-graph-constraint-base.cpp
dali/internal/update/animation/scene-graph-constraint-base.h
dali/internal/update/common/animatable-property.h
dali/internal/update/common/property-owner.cpp
dali/internal/update/common/property-owner.h
dali/internal/update/common/property-resetter.h [new file with mode: 0644]
dali/internal/update/manager/update-algorithms.cpp
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h
dali/internal/update/render-tasks/scene-graph-render-task.cpp
dali/internal/update/render-tasks/scene-graph-render-task.h

index d672329..8119063 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -24,6 +24,7 @@
 #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
@@ -33,7 +34,8 @@ namespace Internal
 {
 
 /**
- * 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.
@@ -81,8 +83,8 @@ public:
       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;
@@ -141,7 +143,9 @@ private:
   }
 
    /**
-   * 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
    */
@@ -154,10 +158,12 @@ private:
     //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 )
     {
@@ -166,9 +172,9 @@ private:
 
     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 )
@@ -176,6 +182,7 @@ private:
         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
         {
@@ -185,15 +192,16 @@ private:
       }
       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
@@ -227,6 +235,11 @@ private:
               break;
             }
           }
+
+          if( mAnimator != nullptr )
+          {
+            resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
+          }
         }
 
         else if ( PropertyTypes::Get< Vector3 >() == baseProperty->GetType() )
@@ -256,10 +269,11 @@ private:
             {
               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 )
@@ -296,6 +310,11 @@ private:
                 break;
               }
             }
+
+            if( mAnimator != nullptr )
+            {
+              resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
+            }
           }
         }
         else if ( PropertyTypes::Get< Vector4 >() == baseProperty->GetType() )
@@ -352,6 +371,10 @@ private:
               break;
             }
           }
+          if( mAnimator != nullptr )
+          {
+            resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator );
+          }
         }
       }
     }
@@ -362,6 +385,12 @@ private:
     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:
index 2f9d65f..0fc820d 100644 (file)
@@ -2,7 +2,7 @@
 #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
 {
@@ -137,11 +139,11 @@ private:
   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
@@ -163,9 +165,10 @@ private:
 
     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" );
@@ -173,10 +176,12 @@ private:
       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
       {
@@ -185,9 +190,17 @@ private:
                                                            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 );
+      }
     }
   }
 
@@ -390,6 +403,7 @@ private:
       // 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" );
@@ -404,6 +418,7 @@ private:
         typedef SceneGraph::Constraint< float, PropertyAccessor<float> > SceneGraphConstraint;
 
         mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
+        resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
       }
       else
       {
@@ -423,6 +438,10 @@ private:
             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() )
         {
@@ -444,6 +463,7 @@ private:
               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
           {
@@ -462,6 +482,10 @@ private:
               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() )
@@ -488,6 +512,11 @@ private:
             typedef SceneGraph::Constraint< float, PropertyComponentAccessorW<Vector4> > SceneGraphConstraint;
             mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction );
           }
+
+          if( mSceneGraphConstraint )
+          {
+            resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint );
+          }
         }
       }
 
@@ -496,6 +525,10 @@ private:
         OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) );
         ApplyConstraintMessage( GetEventThreadServices(), *targetObject, transferOwnership );
       }
+      if( resetter != nullptr )
+      {
+        AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter );
+      }
     }
   }
 
index 31364cd..f745112 100644 (file)
@@ -2,7 +2,7 @@
 #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.
index aff2b2c..b8da716 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -65,10 +65,30 @@ public:
   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),
@@ -86,6 +106,20 @@ public:
    */
   virtual ~AnimatorBase()
   {
+    if( mLifecycleObserver != nullptr )
+    {
+      mLifecycleObserver->ObjectDestroyed();
+    }
+  }
+
+  void AddLifecycleObserver( LifecycleObserver& observer )
+  {
+    mLifecycleObserver = &observer;
+  }
+
+  void RemoveLifecycleObserver( LifecycleObserver& observer )
+  {
+    mLifecycleObserver = nullptr;
   }
 
   /**
@@ -403,6 +437,7 @@ protected:
     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;
index 9a692dd..7c39de9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -36,7 +36,8 @@ ConstraintBase::ConstraintBase( PropertyOwnerContainer& ownerSet, RemoveAction r
 : mRemoveAction( removeAction ),
   mFirstApply( true ),
   mDisconnected( true ),
-  mObservedOwners( ownerSet )
+  mObservedOwners( ownerSet ),
+  mLifecycleObserver( nullptr )
 {
 #ifdef DEBUG_ENABLED
   ++mCurrentInstanceCount;
@@ -51,16 +52,16 @@ ConstraintBase::~ConstraintBase()
     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
index a55bd2e..c816bcc 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -51,6 +51,25 @@ typedef PropertyOwnerContainer::Iterator PropertyOwnerIter;
 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;
 
@@ -67,6 +86,22 @@ public:
   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.
    */
@@ -190,11 +225,6 @@ private:
   }
 
   /**
-   * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties()
-   */
-  virtual void ResetDefaultProperties( BufferIndex updateBufferIndex );
-
-  /**
    * Notify the derived class to disconnect from property owners
    */
   virtual void OnDisconnect() = 0;
@@ -209,6 +239,7 @@ protected:
 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.
index a05d545..f82ed88 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -258,7 +258,10 @@ public:
     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();
     }
@@ -416,6 +419,7 @@ public:
   void Bake(BufferIndex bufferIndex, int value)
   {
     mValue[bufferIndex] = value;
+    mValue[1-bufferIndex] = value;
     mBaseValue = mValue[bufferIndex];
 
     OnBake();
@@ -595,7 +599,10 @@ public:
    */
   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();
@@ -824,7 +831,10 @@ public:
    */
   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();
@@ -838,6 +848,7 @@ public:
   void BakeX(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].x = value;
+    mValue[1-bufferIndex].x = value;
     mBaseValue.x = value;
 
     OnBake();
@@ -851,6 +862,7 @@ public:
   void BakeY(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].y = value;
+    mValue[1-bufferIndex].y = value;
     mBaseValue.y = value;
 
     OnBake();
@@ -1117,6 +1129,7 @@ public:
   void Bake(BufferIndex bufferIndex, const Vector3& value)
   {
     mValue[bufferIndex] = value;
+    mValue[1-bufferIndex] = value;
     mBaseValue = value;
 
     OnBake();
@@ -1130,6 +1143,7 @@ public:
   void BakeX(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].x = value;
+    mValue[1-bufferIndex].x = value;
     mBaseValue.x = value;
 
     OnBake();
@@ -1143,6 +1157,7 @@ public:
   void BakeY(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].y = value;
+    mValue[1-bufferIndex].y = value;
     mBaseValue.y = value;
 
     OnBake();
@@ -1156,6 +1171,7 @@ public:
   void BakeZ(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].z = value;
+    mValue[1-bufferIndex].z = value;
     mBaseValue.z = value;
 
     OnBake();
@@ -1464,6 +1480,7 @@ public:
   void Bake(BufferIndex bufferIndex, const Vector4& value)
   {
     mValue[bufferIndex] = value;
+    mValue[1-bufferIndex] = value;
     mBaseValue = mValue[bufferIndex];
 
     OnBake();
@@ -1477,6 +1494,7 @@ public:
   void BakeX(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].x = value;
+    mValue[1-bufferIndex].x = value;
     mBaseValue.x = mValue[bufferIndex].x;
 
     OnBake();
@@ -1490,6 +1508,7 @@ public:
   void BakeY(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].y = value;
+    mValue[1-bufferIndex].y = value;
     mBaseValue.y = mValue[bufferIndex].y;
 
     OnBake();
@@ -1503,6 +1522,7 @@ public:
   void BakeZ(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].z = value;
+    mValue[1-bufferIndex].z = value;
     mBaseValue.z = mValue[bufferIndex].z;
 
     OnBake();
@@ -1516,6 +1536,7 @@ public:
   void BakeW(BufferIndex bufferIndex, float value)
   {
     mValue[bufferIndex].w = value;
+    mValue[1-bufferIndex].w = value;
     mBaseValue.w = mValue[bufferIndex].w;
 
     OnBake();
@@ -1743,7 +1764,10 @@ public:
    */
   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();
@@ -1901,7 +1925,10 @@ public:
    */
   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();
@@ -2059,7 +2086,10 @@ public:
    */
   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();
index aa666ef..fb655e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -115,18 +115,6 @@ void PropertyOwner::InstallCustomProperty( OwnerPointer<PropertyBase>& property
   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()
 {
index 51d3664..ec5a862 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -162,12 +162,6 @@ public:
     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
 
@@ -230,12 +224,6 @@ private:
   // 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()
diff --git a/dali/internal/update/common/property-resetter.h b/dali/internal/update/common/property-resetter.h
new file mode 100644 (file)
index 0000000..c28322f
--- /dev/null
@@ -0,0 +1,234 @@
+#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
index d7f9759..ead7154 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -54,7 +54,6 @@ Debug::Filter* gUpdateFilter = Debug::Filter::New(Debug::Concise, false, "LOG_UP
  * 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 )
 {
@@ -109,7 +108,7 @@ inline int UpdateNodes( Node& node,
                         Layer& currentLayer,
                         int inheritedDrawMode )
 {
-  //Apply constraints to the node
+  // Apply constraints to the node
   ConstrainPropertyOwner( node, updateBufferIndex );
 
   // Short-circuit for invisible nodes
index c509ec6..6ef46be 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -285,9 +285,9 @@ struct UpdateManager::Impl
   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
@@ -481,6 +481,12 @@ bool UpdateManager::IsAnimationRunning() const
   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() );
@@ -606,40 +612,30 @@ void UpdateManager::ResetProperties( BufferIndex bufferIndex )
   // 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 )
@@ -875,7 +871,7 @@ unsigned int UpdateManager::Update( float elapsedSeconds,
     //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
index d603eb6..ccecef8 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -27,6 +27,7 @@
 #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>
@@ -238,6 +239,13 @@ public:
    */
   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
 
   /**
@@ -1294,6 +1302,18 @@ inline void SetDepthIndicesMessage( UpdateManager& manager, OwnerPointer< NodeDe
   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
index 5030a03..aa7f777 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -310,11 +310,8 @@ int Node::GetDirtyFlags() const
   return flags;
 }
 
-void Node::ResetDefaultProperties( BufferIndex updateBufferIndex )
+void Node::ResetDirtyFlags( BufferIndex updateBufferIndex )
 {
-  mVisible.ResetToBaseValue( updateBufferIndex );
-  mColor.ResetToBaseValue( updateBufferIndex );
-
   mDirtyFlags = NothingFlag;
 }
 
index 93e6a3f..71102fb 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -768,6 +768,11 @@ public:
    */
   void CreateTransform( SceneGraph::TransformManager* transformManager );
 
+  /**
+   * Reset dirty flags
+   */
+  void ResetDirtyFlags( BufferIndex updateBufferIndex );
+
 protected:
 
   /**
@@ -833,11 +838,6 @@ private:
   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.
index 007d341..7d2ced8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -451,13 +451,6 @@ void RenderTask::SetSyncRequired( bool requiresSync )
   mRequiresSync = requiresSync;
 }
 
-void RenderTask::ResetDefaultProperties( BufferIndex updateBufferIndex )
-{
-  // Reset default properties
-  mViewportPosition.ResetToBaseValue( updateBufferIndex );
-  mViewportSize.ResetToBaseValue( updateBufferIndex );
-  mClearColor.ResetToBaseValue( updateBufferIndex );
-}
 
 RenderTask::RenderTask()
 : mViewportPosition( Vector2::ZERO),
index 0797dd3..b66077e 100644 (file)
@@ -2,7 +2,7 @@
 #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.
@@ -339,9 +339,6 @@ private:
   // Undefined
   RenderTask& operator=(const RenderTask&);
 
-private: // PropertyOwner
-
-  virtual void ResetDefaultProperties( BufferIndex currentBufferIndex );
 
 public: // Animatable Properties
   AnimatableProperty< Vector2 >   mViewportPosition;    ///< viewportPosition