Ensure cached values of properties animated using AnimateTo are updated
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
index b49b7ce..344e72c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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/animation/scene-graph-constraint-base.h>
 #include <dali/internal/update/common/animatable-property.h>
 #include <dali/internal/update/common/property-owner-messages.h>
-#include <dali/internal/event/animation/active-constraint-base.h>
+#include <dali/internal/update/common/uniform-map.h>
 #include <dali/internal/event/animation/constraint-impl.h>
 #include <dali/internal/event/common/stage-impl.h>
 #include <dali/internal/event/common/property-notification-impl.h>
-#include <dali/internal/event/common/property-index-ranges.h>
 #include <dali/internal/event/common/type-registry-impl.h>
 
 using Dali::Internal::SceneGraph::AnimatableProperty;
@@ -51,10 +50,13 @@ typedef Dali::Vector<Object::Observer*>::ConstIterator ConstObserverIter;
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
 #endif
+
+
 } // unnamed namespace
 
 Object::Object()
-: mTypeInfo( NULL ),
+: mEventThreadServices( *Stage::GetCurrent() ),
+  mTypeInfo( NULL ),
   mConstraints( NULL ),
   mPropertyNotifications( NULL )
 {
@@ -86,17 +88,6 @@ void Object::RemoveObserver(Observer& observer)
 
 void Object::OnSceneObjectAdd()
 {
-  // Notification for this object's constraints
-  if( mConstraints )
-  {
-    const ActiveConstraintConstIter endIter = mConstraints->end();
-    for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
-    {
-      ActiveConstraintBase& baseConstraint = GetImplementation( *iter );
-      baseConstraint.OnParentSceneObjectAdded();
-    }
-  }
-
   // Notification for observers
   for( ConstObserverIter iter = mObservers.Begin(),  endIter =  mObservers.End(); iter != endIter; ++iter)
   {
@@ -109,17 +100,6 @@ void Object::OnSceneObjectAdd()
 
 void Object::OnSceneObjectRemove()
 {
-  // Notification for this object's constraints
-  if( mConstraints )
-  {
-    const ActiveConstraintConstIter endIter = mConstraints->end();
-    for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
-    {
-      ActiveConstraintBase& baseConstraint = GetImplementation( *iter );
-      baseConstraint.OnParentSceneObjectRemoved();
-    }
-  }
-
   // Notification for observers
   for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
   {
@@ -132,7 +112,21 @@ void Object::OnSceneObjectRemove()
 
 int Object::GetPropertyComponentIndex( Property::Index index ) const
 {
-  return Property::INVALID_COMPONENT_INDEX;
+  int componentIndex = Property::INVALID_COMPONENT_INDEX;
+
+  const TypeInfo* typeInfo( GetTypeInfo() );
+  if ( typeInfo )
+  {
+    componentIndex = typeInfo->GetComponentIndex(index);
+  }
+
+  // For animatable property, check whether it is registered already and register it if not yet.
+  if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) && ( NULL == RegisterAnimatableProperty(index) ) )
+  {
+    componentIndex = Property::INVALID_COMPONENT_INDEX;
+  }
+
+  return componentIndex;
 }
 
 bool Object::Supports( Capability capability ) const
@@ -170,10 +164,18 @@ std::string Object::GetPropertyName( Property::Index index ) const
 
   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
   {
-    return GetDefaultPropertyName( index );
+    std::string string;
+
+    const char * propertyName = GetDefaultPropertyName( index );
+    if( propertyName )
+    {
+      string = propertyName;
+    }
+    return string;
   }
 
-  if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+  if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+    || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
   {
     const TypeInfo* typeInfo( GetTypeInfo() );
     if ( typeInfo )
@@ -186,7 +188,7 @@ std::string Object::GetPropertyName( Property::Index index ) const
     }
   }
 
-  CustomProperty* custom = FindCustomProperty( index );
+  CustomPropertyMetadata* custom = FindCustomProperty( index );
   if( custom )
   {
     return custom->name;
@@ -198,25 +200,71 @@ Property::Index Object::GetPropertyIndex(const std::string& name) const
 {
   Property::Index index = GetDefaultPropertyIndex( name );
 
-  if ( index == Property::INVALID_INDEX )
+  if(index == Property::INVALID_INDEX)
   {
     const TypeInfo* typeInfo( GetTypeInfo() );
     if ( typeInfo )
     {
       index = typeInfo->GetPropertyIndex( name );
+      if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
+      {
+        // check whether the animatable property is registered already, if not then register one.
+        if ( NULL == RegisterAnimatableProperty(index) )
+        {
+          index = Property::INVALID_INDEX;
+        }
+      }
     }
   }
 
-  if( ( index == Property::INVALID_INDEX )&&( mCustomProperties.Count() > 0 ) )
+  if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
   {
     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
-    const CustomPropertyLookup::ConstIterator end = mCustomProperties.End();
-    for( CustomPropertyLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
+    const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
+    for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
     {
-      CustomProperty* custom = *iter;
+      CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
       if ( custom->name == name )
       {
-        index = count;
+        if ( custom->childPropertyIndex != Property::INVALID_INDEX )
+        {
+          // If it is a child property, return the child property index
+          index = custom->childPropertyIndex;
+        }
+        else
+        {
+          index = count;
+        }
+        break;
+      }
+    }
+  }
+
+  return index;
+}
+
+Property::Index Object::GetPropertyIndex( Property::Index key ) const
+{
+  Property::Index index = Property::INVALID_INDEX;
+
+  if( mCustomProperties.Count() > 0 )
+  {
+    Property::Index count = PROPERTY_CUSTOM_START_INDEX;
+    const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
+    for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
+    {
+      CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
+      if( custom->key == key )
+      {
+        if( custom->childPropertyIndex != Property::INVALID_INDEX )
+        {
+          // If it is a child property, return the child property index
+          index = custom->childPropertyIndex;
+        }
+        else
+        {
+          index = count;
+        }
         break;
       }
     }
@@ -225,81 +273,122 @@ Property::Index Object::GetPropertyIndex(const std::string& name) const
   return index;
 }
 
+Property::Index Object::GetPropertyIndex( Property::Key key ) const
+{
+  Property::Index index = Property::INVALID_INDEX;
+  if( key.type == Property::Key::INDEX )
+  {
+    index = GetPropertyIndex( key.indexKey );
+  }
+  else
+  {
+    index = GetPropertyIndex( key.stringKey );
+  }
+  return index;
+}
+
 bool Object::IsPropertyWritable( Property::Index index ) const
 {
   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
 
+  bool writable = false;
+
   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
   {
-    return IsDefaultPropertyWritable( index );
+    writable = IsDefaultPropertyWritable( index );
   }
-
-  if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+  else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
     const TypeInfo* typeInfo( GetTypeInfo() );
     if ( typeInfo )
     {
-      return typeInfo->IsPropertyWritable( index );
+      writable = typeInfo->IsPropertyWritable( index );
     }
     else
     {
       DALI_ASSERT_ALWAYS( ! "Invalid property index" );
     }
   }
-
-  CustomProperty* custom = FindCustomProperty( index );
-  if( custom )
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
-    return custom->IsWritable();
+    // Type Registry scene-graph properties are writable.
+    writable = true;
+  }
+  else
+  {
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+    if( custom )
+    {
+      writable = custom->IsWritable();
+    }
   }
-  return false;
+
+  return writable;
 }
 
 bool Object::IsPropertyAnimatable( Property::Index index ) const
 {
   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
 
+  bool animatable = false;
+
   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
   {
-    return IsDefaultPropertyAnimatable( index );
+    animatable = IsDefaultPropertyAnimatable( index );
   }
-
-  if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+  else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
     // Type Registry event-thread only properties are not animatable.
-    return false;
+    animatable = false;
   }
-
-  CustomProperty* custom = FindCustomProperty( index );
-  if( custom )
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
+  {
+    // Type Registry scene-graph properties are animatable.
+    animatable = true;
+  }
+  else
   {
-    return custom->IsAnimatable();
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+    if( custom )
+    {
+      animatable = custom->IsAnimatable();
+    }
   }
-  return false;
+
+  return animatable;
 }
 
 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
 {
   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
 
+  bool isConstraintInput = false;
+
   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
   {
-    return IsDefaultPropertyAConstraintInput( index );
+    isConstraintInput = IsDefaultPropertyAConstraintInput( index );
   }
-
-  if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+  else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
     // Type Registry event-thread only properties cannot be used as an input to a constraint.
-    return false;
+    isConstraintInput = false;
   }
-
-  CustomProperty* custom = FindCustomProperty( index );
-  if( custom )
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
+  {
+    // scene graph properties can be used as input to a constraint.
+    isConstraintInput = true;
+  }
+  else
   {
-    // ... custom properties can be used as input to a constraint.
-    return true;
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+    if( custom )
+    {
+      // ... custom properties can be used as input to a constraint.
+      isConstraintInput = true;
+    }
   }
-  return false;
+
+  return isConstraintInput;
 }
 
 Property::Type Object::GetPropertyType( Property::Index index ) const
@@ -311,7 +400,8 @@ Property::Type Object::GetPropertyType( Property::Index index ) const
     return GetDefaultPropertyType( index );
   }
 
-  if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+  if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+    || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
   {
     const TypeInfo* typeInfo( GetTypeInfo() );
     if ( typeInfo )
@@ -324,11 +414,12 @@ Property::Type Object::GetPropertyType( Property::Index index ) const
     }
   }
 
-  CustomProperty* custom = FindCustomProperty( index );
+  CustomPropertyMetadata* custom = FindCustomProperty( index );
   if( custom )
   {
-    return custom->type;
+    return custom->GetType();
   }
+
   return Property::NONE;
 }
 
@@ -336,6 +427,8 @@ void Object::SetProperty( Property::Index index, const Property::Value& property
 {
   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
 
+  bool propertySet( true );
+
   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
   {
     SetDefaultProperty( index, propertyValue );
@@ -349,24 +442,88 @@ void Object::SetProperty( Property::Index index, const Property::Value& property
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
+      DALI_LOG_ERROR("Cannot find property index\n");
+      propertySet = false;
     }
   }
-  else
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
-    CustomProperty* custom = FindCustomProperty( index );
-    DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
-    if( custom->IsAnimatable() )
+    // check whether the animatable property is registered already, if not then register one.
+    AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
+    if(!animatableProperty)
     {
+      DALI_LOG_ERROR("Cannot find property index\n");
+      propertySet = false;
+    }
+    else
+    {
+      // update the cached property value
+      animatableProperty->SetPropertyValue( propertyValue );
+
       // set the scene graph property value
-      SetSceneGraphProperty( index, *custom, propertyValue );
+      SetSceneGraphProperty( index, *animatableProperty, propertyValue );
+    }
+  }
+  else
+  {
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+
+    if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
+    {
+      if( !custom )
+      {
+        // If the child property is not registered yet, register it.
+        custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
+        mCustomProperties.PushBack( custom );
+      }
+
+      custom->childPropertyIndex = index;
+
+      // Resolve name for the child property
+      Object* parent = GetParentObject();
+      if( parent )
+      {
+        const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
+        if( parentTypeInfo )
+        {
+          custom->name = parentTypeInfo->GetChildPropertyName( index );
+        }
+      }
+    }
+
+    if( custom )
+    {
+      if( custom->IsAnimatable() )
+      {
+        // update the cached property value
+        custom->SetPropertyValue( propertyValue );
+
+        // set the scene graph property value
+        SetSceneGraphProperty( index, *custom, propertyValue );
+      }
+      else if( custom->IsWritable() )
+      {
+        // update the cached property value
+        custom->SetPropertyValue( propertyValue );
+      }
+      else
+      {
+        // trying to set value on read only property is no-op
+        propertySet = false;
+      }
     }
-    else if( custom->IsWritable() )
+    else
     {
-      custom->value = propertyValue;
-      OnPropertySet(index, propertyValue);
+      DALI_LOG_ERROR("Invalid property index\n");
+      propertySet = false;
     }
-    // trying to set value on read only property is no-op
+  }
+
+  // Let derived classes know that a property has been set
+  // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
+  if ( propertySet )
+  {
+    OnPropertySet(index, propertyValue);
   }
 }
 
@@ -389,113 +546,88 @@ Property::Value Object::GetProperty(Property::Index index) const
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
+      DALI_LOG_ERROR("Cannot find property index\n");
     }
   }
-  else if( mCustomProperties.Count() > 0 )
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
-    CustomProperty* custom = FindCustomProperty( index );
-    DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
-
-    if( !custom->IsAnimatable() )
+    // check whether the animatable property is registered already, if not then register one.
+    AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
+    if(!animatableProperty)
     {
-      value = custom->value;
+      DALI_LOG_ERROR("Cannot find property index\n");
     }
     else
     {
-      BufferIndex bufferIndex( Stage::GetCurrent()->GetEventBufferIndex() );
-
-      switch ( custom->type )
-      {
-        case Property::BOOLEAN:
-        {
-          const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::FLOAT:
-        {
-          const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::INTEGER:
-        {
-          const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::VECTOR2:
-        {
-          const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::VECTOR3:
-        {
-          const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::VECTOR4:
-        {
-          const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::MATRIX:
-        {
-          const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
-
-        case Property::MATRIX3:
-        {
-          const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
-
-          value = (*property)[ bufferIndex ];
-          break;
-        }
+      // get the cached animatable property value
+      value = animatableProperty->GetPropertyValue();
+    }
+  }
+  else if(mCustomProperties.Count() > 0)
+  {
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+    if(custom)
+    {
+      // get the cached custom property value
+      value = custom->GetPropertyValue();
+    }
+    else
+    {
+      DALI_LOG_ERROR("Invalid property index\n");
+    }
+  } // if custom
 
-        case Property::ROTATION:
-        {
-          const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( custom->GetSceneGraphProperty() );
-          DALI_ASSERT_DEBUG( NULL != property );
+  return value;
+}
 
-          value = (*property)[ bufferIndex ];
-          break;
-        }
+Property::Value Object::GetCurrentProperty( Property::Index index ) const
+{
+  DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
 
-        default:
-        {
-          DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
-          break;
-        }
-      } // switch(type)
-    } // if animatable
+  Property::Value value;
 
+  if ( index < DEFAULT_PROPERTY_MAX_COUNT )
+  {
+    value = GetDefaultPropertyCurrentValue( index );
+  }
+  else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
+  {
+    const TypeInfo* typeInfo( GetTypeInfo() );
+    if ( typeInfo )
+    {
+      value = typeInfo->GetProperty( this, index );
+    }
+    else
+    {
+      DALI_LOG_ERROR("Cannot find property index\n");
+    }
+  }
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
+  {
+    // check whether the animatable property is registered already, if not then register one.
+    AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
+    if(!animatableProperty)
+    {
+      DALI_LOG_ERROR("Cannot find property index\n");
+    }
+    else
+    {
+      // get the animatable property value
+      value = GetCurrentPropertyValue( animatableProperty );
+    }
+  }
+  else if(mCustomProperties.Count() > 0)
+  {
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+    if(custom)
+    {
+      // get the custom property value
+      value = GetCurrentPropertyValue( custom );
+    }
+    else
+    {
+      DALI_LOG_ERROR("Invalid property index\n");
+    }
   } // if custom
 
   return value;
@@ -503,7 +635,7 @@ Property::Value Object::GetProperty(Property::Index index) const
 
 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
 {
-  indices.clear();
+  indices.Clear();
 
   // Default Properties
   GetDefaultPropertyIndices( indices );
@@ -518,19 +650,28 @@ void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
   // Custom Properties
   if ( mCustomProperties.Count() > 0 )
   {
-    indices.reserve( indices.size() + mCustomProperties.Count() );
+    indices.Reserve( indices.Size() + mCustomProperties.Count() );
 
-    CustomPropertyLookup::ConstIterator iter = mCustomProperties.Begin();
-    const CustomPropertyLookup::ConstIterator endIter = mCustomProperties.End();
+    PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
+    const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
     int i=0;
     for ( ; iter != endIter; ++iter, ++i )
     {
-      indices.push_back( PROPERTY_CUSTOM_START_INDEX + i );
+      CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
+      if ( custom->childPropertyIndex != Property::INVALID_INDEX )
+      {
+        // If it is a child property, add the child property index
+        indices.PushBack( custom->childPropertyIndex );
+      }
+      else
+      {
+        indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
+      }
     }
   }
 }
 
-Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue)
+Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index key, Property::Index index, const Property::Value& propertyValue) const
 {
   // Create a new property
   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
@@ -543,15 +684,15 @@ Property::Index Object::RegisterProperty( const std::string& name, const Propert
       break;
     }
 
-    case Property::FLOAT:
+    case Property::INTEGER:
     {
-      newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
+      newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
       break;
     }
 
-    case Property::INTEGER:
+    case Property::FLOAT:
     {
-      newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
+      newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
       break;
     }
 
@@ -591,64 +732,117 @@ Property::Index Object::RegisterProperty( const std::string& name, const Propert
       break;
     }
 
-    case Property::UNSIGNED_INTEGER:
     case Property::RECTANGLE:
     case Property::STRING:
     case Property::ARRAY:
     case Property::MAP:
+    case Property::NONE:
     {
-      DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
       break;
     }
-
-    default:
-    {
-      DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
-      DALI_ASSERT_ALWAYS( !"PropertyType enumeration is out of bounds" );
-      break;
-    }
   }
 
   // get the scene property owner from derived class
   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
-  Property::Index index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
   // we can only pass properties to scene graph side if there is a scene object
   if( scenePropertyOwner )
   {
     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
     const PropertyBase* property = newProperty.Get();
-    mCustomProperties.PushBack( new CustomProperty( name, propertyValue.GetType(), property ) );
+    if(index >= PROPERTY_CUSTOM_START_INDEX)
+    {
+      DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
+
+      mCustomProperties.PushBack( new CustomPropertyMetadata( name, key, propertyValue, property ) );
+    }
+    else
+    {
+      mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue, property ) );
+    }
 
     // queue a message to add the property
-    InstallCustomPropertyMessage( Stage::GetCurrent()->GetUpdateInterface(), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
+    InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
 
     // notify the derived class (optional) method in case it needs to do some more work on the new property
     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
     NotifyScenePropertyInstalled( *property, name, index );
+
+    return index;
   }
   else
   {
     // property was orphaned and killed so return invalid index
-    index = Property::INVALID_INDEX;
+    return Property::INVALID_INDEX;
   }
+}
 
-  return index;
+Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
+{
+  return RegisterProperty( name, Property::INVALID_KEY, propertyValue, Property::ANIMATABLE );
 }
 
-Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode)
+Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue )
 {
-  Property::Index index = Property::INVALID_INDEX;
+  return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
+}
 
-  if(Property::ANIMATABLE == accessMode)
-  {
-    index = RegisterProperty(name, propertyValue);
-  }
-  else
-  {
-    // Add entry to the property lookup
-    index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
-    mCustomProperties.PushBack( new CustomProperty( name, propertyValue, accessMode ) );
+Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
+{
+  return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
+}
+
+Property::Index Object::RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue, Property::AccessMode accessMode )
+{
+  // If property with the required key already exists, then just set it.
+  Property::Index index = Property::INVALID_INDEX;
+  if( key != Property::INVALID_KEY ) // Try integer key first if it's valid
+  {
+    index = GetPropertyIndex( key );
+  }
+  if( index == Property::INVALID_INDEX ) // If it wasn't valid, or doesn't exist, try name
+  {
+    index = GetPropertyIndex( name );
+  }
+
+  if( index != Property::INVALID_INDEX ) // If there was a valid index found by either key, set it.
+  {
+    SetProperty( index, propertyValue );
+  }
+  else
+  {
+    // Otherwise register the property
+
+    if( Property::ANIMATABLE == accessMode )
+    {
+      index = RegisterSceneGraphProperty( name, key, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue );
+      AddUniformMapping( index, name );
+    }
+    else
+    {
+      // Add entry to the property lookup
+      index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
+
+      CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
+
+      // Resolve index for the child property
+      Object* parent = GetParentObject();
+      if( parent )
+      {
+        const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
+        if( parentTypeInfo )
+        {
+          Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
+          if( childPropertyIndex != Property::INVALID_INDEX )
+          {
+            customProperty->childPropertyIndex = childPropertyIndex;
+            index = childPropertyIndex;
+          }
+        }
+      }
+
+      mCustomProperties.PushBack( customProperty );
+    }
   }
 
   return index;
@@ -662,11 +856,17 @@ Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index
   {
     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
     {
-      DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
+      DALI_ABORT( "Property notification added to event side only property." );
+    }
+    else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
+    {
+      // check whether the animatable property is registered already, if not then register one.
+      AnimatablePropertyMetadata* animatable = RegisterAnimatableProperty( index );
+      DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
     }
     else if ( mCustomProperties.Count() > 0 )
     {
-      CustomProperty* custom = FindCustomProperty( index );
+      CustomPropertyMetadata* custom = FindCustomProperty( index );
       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
     }
@@ -724,6 +924,32 @@ void Object::RemovePropertyNotifications()
   }
 }
 
+void Object::NotifyPropertyAnimation( Animation& animation, Property::Index index, const Property::Value& value )
+{
+  if ( index < DEFAULT_PROPERTY_MAX_COUNT )
+  {
+    OnNotifyDefaultPropertyAnimation( animation, index, value );
+  }
+  else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
+  {
+    AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
+    if( animatableProperty )
+    {
+      // update the cached property value
+      animatableProperty->SetPropertyValue( value );
+    }
+  }
+  else
+  {
+    CustomPropertyMetadata* custom = FindCustomProperty( index );
+    if( custom && custom->IsAnimatable() )
+    {
+      // update the cached property value
+      custom->SetPropertyValue( value );
+    }
+  }
+}
+
 void Object::EnablePropertyNotifications()
 {
   if( mPropertyNotifications )
@@ -752,48 +978,208 @@ void Object::DisablePropertyNotifications()
   }
 }
 
-Dali::ActiveConstraint Object::ApplyConstraint( Constraint& constraint )
+void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
 {
-  return Dali::ActiveConstraint( DoApplyConstraint( constraint, Dali::Constrainable() ) );
+  // Get the address of the property if it's a scene property
+  const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
+
+  // Check instead for newly registered properties
+  if( propertyPtr == NULL )
+  {
+    PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
+    if( animatable != NULL )
+    {
+      propertyPtr = animatable->GetSceneGraphProperty();
+    }
+  }
+
+  if( propertyPtr == NULL )
+  {
+    PropertyMetadata* custom = FindCustomProperty( propertyIndex );
+    if( custom != NULL )
+    {
+      propertyPtr = custom->GetSceneGraphProperty();
+    }
+  }
+
+  if( propertyPtr != NULL )
+  {
+    const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
+
+    if( sceneObject != NULL )
+    {
+      SceneGraph::UniformPropertyMapping* map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
+      // Message takes ownership of Uniform map (and will delete it after copy)
+      AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map);
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
+    }
+  }
 }
 
-Dali::ActiveConstraint Object::ApplyConstraint( Constraint& constraint, Dali::Constrainable weightObject )
+void Object::RemoveUniformMapping( const std::string& uniformName )
 {
-  return Dali::ActiveConstraint( DoApplyConstraint( constraint, weightObject ) );
+  const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
+  RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
 }
 
-ActiveConstraintBase* Object::DoApplyConstraint( Constraint& constraint, Dali::Constrainable weightObject )
+Property::Value Object::GetCurrentPropertyValue( const PropertyMetadata* entry ) const
 {
-  ActiveConstraintBase* activeConstraintImpl = constraint.CreateActiveConstraint();
-  DALI_ASSERT_DEBUG( NULL != activeConstraintImpl );
+  Property::Value value;
 
-  Dali::ActiveConstraint activeConstraint( activeConstraintImpl );
+  DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
 
-  if( weightObject )
+  if( !entry->IsAnimatable() )
+  {
+    value = entry->GetPropertyValue();
+  }
+  else
   {
-    Object& weightObjectImpl = GetImplementation( weightObject );
-    Property::Index weightIndex = weightObjectImpl.GetPropertyIndex( "weight" );
+    BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
 
-    if( Property::INVALID_INDEX != weightIndex )
+    switch ( entry->GetType() )
     {
-      activeConstraintImpl->SetCustomWeightObject( weightObjectImpl, weightIndex );
-    }
-  }
+      case Property::BOOLEAN:
+      {
+        const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
 
-  if( !mConstraints )
-  {
-    mConstraints = new ActiveConstraintContainer;
-  }
-  mConstraints->push_back( activeConstraint );
+        value = (*property)[ bufferIndex ];
+        break;
+      }
+
+      case Property::INTEGER:
+      {
+        const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        value = (*property)[ bufferIndex ];
+        break;
+      }
+
+      case Property::FLOAT:
+      {
+        const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        value = (*property)[ bufferIndex ];
+        break;
+      }
+
+      case Property::VECTOR2:
+      {
+        const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        if(entry->componentIndex == 0)
+        {
+          value = (*property)[ bufferIndex ].x;
+        }
+        else if(entry->componentIndex == 1)
+        {
+          value = (*property)[ bufferIndex ].y;
+        }
+        else
+        {
+          value = (*property)[ bufferIndex ];
+        }
+        break;
+      }
+
+      case Property::VECTOR3:
+      {
+        const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        if(entry->componentIndex == 0)
+        {
+          value = (*property)[ bufferIndex ].x;
+        }
+        else if(entry->componentIndex == 1)
+        {
+          value = (*property)[ bufferIndex ].y;
+        }
+        else if(entry->componentIndex == 2)
+        {
+          value = (*property)[ bufferIndex ].z;
+        }
+        else
+        {
+          value = (*property)[ bufferIndex ];
+        }
+        break;
+      }
+
+      case Property::VECTOR4:
+      {
+        const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        if(entry->componentIndex == 0)
+        {
+          value = (*property)[ bufferIndex ].x;
+        }
+        else if(entry->componentIndex == 1)
+        {
+          value = (*property)[ bufferIndex ].y;
+        }
+        else if(entry->componentIndex == 2)
+        {
+          value = (*property)[ bufferIndex ].z;
+        }
+        else if(entry->componentIndex == 3)
+        {
+          value = (*property)[ bufferIndex ].w;
+        }
+        else
+        {
+          value = (*property)[ bufferIndex ];
+        }
+        break;
+      }
+
+      case Property::MATRIX:
+      {
+        const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        value = (*property)[ bufferIndex ];
+        break;
+      }
+
+      case Property::MATRIX3:
+      {
+        const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
+
+        value = (*property)[ bufferIndex ];
+        break;
+      }
 
-  activeConstraintImpl->FirstApply( *this, constraint.GetApplyTime() );
+      case Property::ROTATION:
+      {
+        const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
+        DALI_ASSERT_DEBUG( NULL != property );
 
-  return activeConstraintImpl;
+        value = (*property)[ bufferIndex ];
+        break;
+      }
+
+      default:
+      {
+        // unreachable code due to higher level logic
+      }
+    } // switch(type)
+  } // if animatable
+
+  return value;
 }
 
-void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty& entry, const Property::Value& value )
+void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
 {
-  switch ( entry.type )
+  switch ( entry.GetType() )
   {
     case Property::BOOLEAN:
     {
@@ -801,27 +1187,27 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<bool>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<bool>() );
+      BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
       break;
     }
 
-    case Property::FLOAT:
+    case Property::INTEGER:
     {
-      const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
+      const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<float>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<float>() );
+      BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
       break;
     }
 
-    case Property::INTEGER:
+    case Property::FLOAT:
     {
-      const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
+      const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<int>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<int>() );
+      BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
       break;
     }
 
@@ -831,7 +1217,18 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Vector2>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<Vector2>() );
+      if(entry.componentIndex == 0)
+      {
+        SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else if(entry.componentIndex == 1)
+      {
+        SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else
+      {
+        BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
+      }
       break;
     }
 
@@ -841,7 +1238,23 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Vector3>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<Vector3>() );
+      if(entry.componentIndex == 0)
+      {
+        SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else if(entry.componentIndex == 1)
+      {
+        SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else if(entry.componentIndex == 2)
+      {
+        SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else
+      {
+        BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
+      }
+
       break;
     }
 
@@ -851,7 +1264,26 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Vector4>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<Vector4>() );
+      if(entry.componentIndex == 0)
+      {
+        SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else if(entry.componentIndex == 1)
+      {
+        SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else if(entry.componentIndex == 2)
+      {
+        SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else if(entry.componentIndex == 3)
+      {
+        SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
+      }
+      else
+      {
+        BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
+      }
       break;
     }
 
@@ -861,7 +1293,7 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Quaternion>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<Quaternion>() );
+      BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
       break;
     }
 
@@ -871,7 +1303,7 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Matrix>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<Matrix>() );
+      BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
       break;
     }
 
@@ -881,7 +1313,7 @@ void Object::SetSceneGraphProperty( Property::Index index, const CustomProperty&
       DALI_ASSERT_DEBUG( NULL != property );
 
       // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Matrix3>( Stage::GetCurrent()->GetUpdateInterface(), *property, value.Get<Matrix3>() );
+      BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
       break;
     }
 
@@ -909,32 +1341,46 @@ const TypeInfo* Object::GetTypeInfo() const
   return mTypeInfo;
 }
 
-void Object::RemoveConstraint( ActiveConstraint& constraint, bool isInScenegraph )
+void Object::ApplyConstraint( ConstraintBase& constraint )
 {
-  // guard against constraint sending messages during core destruction
-  if ( Stage::IsInstalled() )
+  if( !mConstraints )
+  {
+    mConstraints = new ConstraintContainer;
+  }
+  mConstraints->push_back( Dali::Constraint( &constraint ) );
+}
+
+void Object::RemoveConstraint( ConstraintBase& constraint )
+{
+  // NULL if the Constraint sources are destroyed before Constraint::Apply()
+  if( mConstraints )
   {
-    if( isInScenegraph )
+    ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
+    if( it != mConstraints->end() )
     {
-      ActiveConstraintBase& baseConstraint = GetImplementation( constraint );
-      baseConstraint.BeginRemove();
+      mConstraints->erase( it );
     }
   }
 }
 
-void Object::RemoveConstraint( Dali::ActiveConstraint activeConstraint )
+void Object::RemoveConstraints()
 {
   // guard against constraint sending messages during core destruction
   if( mConstraints && Stage::IsInstalled() )
   {
-    bool isInSceneGraph( NULL != GetSceneObject() );
-
-    ActiveConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), activeConstraint ) );
-    if( it !=  mConstraints->end() )
+    // If we have nothing in the scene-graph, just clear constraint containers
+    const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
+    if ( NULL != propertyOwner )
     {
-      RemoveConstraint( *it, isInSceneGraph );
-      mConstraints->erase( it );
+      const ConstraintConstIter endIter = mConstraints->end();
+      for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
+      {
+        GetImplementation( *iter ).RemoveInternal();
+      }
     }
+
+    delete mConstraints;
+    mConstraints = NULL;
   }
 }
 
@@ -943,15 +1389,13 @@ void Object::RemoveConstraints( unsigned int tag )
   // guard against constraint sending messages during core destruction
   if( mConstraints && Stage::IsInstalled() )
   {
-    bool isInSceneGraph( NULL != GetSceneObject() );
-
-    ActiveConstraintIter iter( mConstraints->begin() );
+    ConstraintIter iter( mConstraints->begin() );
     while(iter != mConstraints->end() )
     {
-      ActiveConstraintBase& constraint = GetImplementation( *iter );
+      ConstraintBase& constraint = GetImplementation( *iter );
       if( constraint.GetTag() == tag )
       {
-        RemoveConstraint( *iter, isInSceneGraph );
+        GetImplementation( *iter ).RemoveInternal();
         iter = mConstraints->erase( iter );
       }
       else
@@ -959,27 +1403,12 @@ void Object::RemoveConstraints( unsigned int tag )
         ++iter;
       }
     }
-  }
-}
 
-void Object::RemoveConstraints()
-{
-  // guard against constraint sending messages during core destruction
-  if( mConstraints && Stage::IsInstalled() )
-  {
-    // If we have nothing in the scene-graph, just clear constraint containers
-    const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
-    if ( NULL != propertyOwner )
+    if ( mConstraints->empty() )
     {
-      const ActiveConstraintConstIter endIter = mConstraints->end();
-      for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
-      {
-        RemoveConstraint( *iter, true );
-      }
+      delete mConstraints;
+      mConstraints = NULL;
     }
-
-    delete mConstraints;
-    mConstraints = NULL;
   }
 }
 
@@ -990,18 +1419,6 @@ void Object::SetTypeInfo( const TypeInfo* typeInfo )
 
 Object::~Object()
 {
-  // Notification for this object's constraints
-  // (note that the ActiveConstraint handles may outlive the Object)
-  if( mConstraints )
-  {
-    const ActiveConstraintConstIter endIter = mConstraints->end();
-    for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
-    {
-      ActiveConstraintBase& baseConstraint = GetImplementation( *iter );
-      baseConstraint.OnParentDestroyed();
-    }
-  }
-
   // Notification for observers
   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
   {
@@ -1012,20 +1429,134 @@ Object::~Object()
   delete mPropertyNotifications;
 }
 
-CustomProperty* Object::FindCustomProperty( Property::Index index ) const
+CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
 {
-  CustomProperty* property( NULL );
-  int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
-  if( arrayIndex >= 0 )
+  CustomPropertyMetadata* property( NULL );
+  if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
   {
-    if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
+    for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
     {
-      property = mCustomProperties[ arrayIndex ];
+      CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
+      if( custom->childPropertyIndex == index )
+      {
+        property = custom;
+      }
+    }
+  }
+  else
+  {
+    int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
+    if( arrayIndex >= 0 )
+    {
+      if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
+      {
+        property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
+      }
     }
   }
   return property;
 }
 
+AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
+{
+  for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
+  {
+    AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
+    if( property->index == index )
+    {
+      return property;
+    }
+  }
+  return NULL;
+}
+
+AnimatablePropertyMetadata* Object::RegisterAnimatableProperty(Property::Index index) const
+{
+  DALI_ASSERT_ALWAYS( (( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ))
+                      && "Property index is out of bounds" );
+
+  // check whether the animatable property is registered already, if not then register one.
+  AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
+  if( !animatableProperty )
+  {
+    const TypeInfo* typeInfo( GetTypeInfo() );
+    if( typeInfo )
+    {
+      Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
+      if( basePropertyIndex == Property::INVALID_INDEX )
+      {
+        // If the property is not a component of a base property, register the whole property itself.
+        const  std::string& propertyName = typeInfo->GetPropertyName(index);
+        RegisterSceneGraphProperty(propertyName, Property::INVALID_KEY, index, typeInfo->GetPropertyDefaultValue(index));
+        AddUniformMapping( index, propertyName );
+      }
+      else
+      {
+        // Since the property is a component of a base property, check whether the base property is registered.
+        animatableProperty = FindAnimatableProperty( basePropertyIndex );
+        if( !animatableProperty )
+        {
+          // If the base property is not registered yet, register the base property first.
+          const  std::string& basePropertyName = typeInfo->GetPropertyName(basePropertyIndex);
+
+          if( Property::INVALID_INDEX != RegisterSceneGraphProperty( basePropertyName, Property::INVALID_KEY, basePropertyIndex, typeInfo->GetPropertyDefaultValue( basePropertyIndex ) ) )
+          {
+            animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
+            AddUniformMapping( basePropertyIndex, basePropertyName );
+          }
+        }
+
+        if(animatableProperty)
+        {
+          // Create the metadata for the property component.
+          mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->value, animatableProperty->GetSceneGraphProperty() ) );
+        }
+      }
+
+      // The metadata has just been added and therefore should be in the end of the vector.
+      animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
+    }
+  }
+
+  return animatableProperty;
+}
+
+void Object::ResolveChildProperties()
+{
+  // Resolve index for the child property
+  Object* parent = GetParentObject();
+  if( parent )
+  {
+    const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
+    if( parentTypeInfo )
+    {
+      // Go through each custom property
+      for ( int arrayIndex = 0; arrayIndex < (int)mCustomProperties.Count(); arrayIndex++ )
+      {
+        CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
+
+        if( customProperty->name == "" )
+        {
+          if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
+          {
+            // Resolve name for any child property with no name
+            customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
+          }
+        }
+        else
+        {
+          Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
+          if( childPropertyIndex != Property::INVALID_INDEX )
+          {
+            // Resolve index for any property with a name that matches the parent's child property name
+            customProperty->childPropertyIndex = childPropertyIndex;
+          }
+        }
+      }
+    }
+  }
+}
+
 } // namespace Internal
 
 } // namespace Dali