Updated visual property animator to handle shader properties 88/109288/7
authorDavid Steele <david.steele@samsung.com>
Mon, 9 Jan 2017 19:17:59 +0000 (19:17 +0000)
committerDavid Steele <david.steele@samsung.com>
Thu, 12 Jan 2017 19:35:52 +0000 (19:35 +0000)
If the AnimateProperty() method cannot find the requested property
in the renderer, it now checks the shader. If it finds a registered
uniform, then it registers the same uniform on the renderer, and
sets up the appropriate transition.

Change-Id: I0f5ae27deec005f406d18ca9de28ed9cf57f96a3
Signed-off-by: David Steele <david.steele@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.h
dali-toolkit/public-api/controls/control-impl.cpp

index b6478a0..6d88a51 100644 (file)
@@ -1459,6 +1459,69 @@ int UtcDaliVisualAnimateImageVisualMixColor(void)
   END_TEST;
 }
 
+int UtcDaliVisualAnimateImageVisualPixelArea(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimateImageVisual pixel area" );
+
+  application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert("mixColor", Color::BLUE);
+  propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  actor.SetColor(Color::BLACK);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::MIX_COLOR );
+
+  tet_infoline("Test that the renderer has the mixColor property");
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+  // TransitionData only takes string keys
+  Property::Map map;
+  map["target"] = "testVisual";
+  map["property"] = "pixelArea";
+  map["initialValue"] = Vector4( 0,0,0,1 );
+  map["targetValue"] = Vector4( 0,0,1,1 ); // Animate width from zero to full
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 4.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  Animation animation = dummyImpl.CreateTransition( transition );
+  animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(2000u); // halfway point
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4(0.0f, 0.0f, 0.5f, 1.0f )), true, TEST_LOCATION );
+
+  application.Render(2000u);
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4( 0.0f, 0.0f, 1.0f, 1.0f )), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
 
 int UtcDaliVisualWireframeVisual(void)
 {
index 719a0fb..68620ea 100644 (file)
@@ -349,7 +349,77 @@ Renderer Visual::Base::GetRenderer()
   return mImpl->mRenderer;
 }
 
-void Visual::Base::AnimateProperty( Dali::Animation& transition, Internal::TransitionData::Animator& animator )
+
+Property::Index Visual::Base::GetPropertyIndex( Property::Key key )
+{
+  Property::Index index = DevelHandle::GetPropertyIndex( mImpl->mRenderer, key );
+
+  if( index == Property::INVALID_INDEX )
+  {
+    // Is it a shader property?
+    Shader shader = mImpl->mRenderer.GetShader();
+    index = DevelHandle::GetPropertyIndex( shader, key );
+    if( index != Property::INVALID_INDEX )
+    {
+      // Yes - we should register it in the Renderer so it can be set / animated
+      // independently, as shaders are shared across multiple renderers.
+      std::string keyName;
+      Property::Index keyIndex( Property::INVALID_KEY );
+      if( key.type == Property::Key::INDEX )
+      {
+        keyName = shader.GetPropertyName( index );
+        keyIndex = key.indexKey;
+      }
+      else
+      {
+        keyName = key.stringKey;
+        // Leave keyIndex as INVALID_KEY - it can still be registered against the string key.
+      }
+      Property::Value value = shader.GetProperty( index );
+      index = DevelHandle::RegisterProperty( mImpl->mRenderer, keyIndex, keyName, value );
+    }
+  }
+  return index;
+}
+
+void Visual::Base::SetupTransition(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator,
+  Property::Index index )
+{
+  if( index != Property::INVALID_INDEX )
+  {
+    if( mImpl->mRenderer )
+    {
+      if( animator.animate == false )
+      {
+        mImpl->mRenderer.SetProperty( index, animator.targetValue );
+      }
+      else
+      {
+        if( animator.initialValue.GetType() != Property::NONE )
+        {
+          mImpl->mRenderer.SetProperty( index, animator.initialValue );
+        }
+
+        if( ! transition )
+        {
+          transition = Dali::Animation::New( 0.1f );
+        }
+
+        transition.AnimateTo( Property( mImpl->mRenderer, index ),
+                              animator.targetValue,
+                              animator.alphaFunction,
+                              TimePeriod( animator.timePeriodDelay,
+                                          animator.timePeriodDuration ) );
+      }
+    }
+  }
+}
+
+void Visual::Base::AnimateProperty(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator )
 {
 #if defined(DEBUG_ENABLED)
   {
@@ -361,21 +431,31 @@ void Visual::Base::AnimateProperty( Dali::Animation& transition, Internal::Trans
 
   Property::Index index = Property::INVALID_INDEX;
 
-  // Get the property index
   bool isMixColor = false;
+  bool isMixColorOpaque = true;
+
+  // Get the property index
   if( animator.propertyKey == Toolkit::DevelVisual::Property::MIX_COLOR ||
       animator.propertyKey == MIX_COLOR )
   {
     isMixColor = true;
     index = mImpl->mMixColorIndex;
+
+    Vector4 initialColor;
+    if( animator.initialValue.Get(initialColor) ) // if there is an initial color, test it
+    {
+      isMixColorOpaque = initialColor.a >= 1.0f;
+    }
+    else
+    {
+      isMixColorOpaque = mImpl->mMixColor.a >= 1.0f; // otherwise, test the current color
+    }
   }
   else if( mImpl->mRenderer )
   {
-    index = DevelHandle::GetPropertyIndex( mImpl->mRenderer, animator.propertyKey );
+    index = GetPropertyIndex( animator.propertyKey );
   }
 
-  Vector4 currentMixColor( mImpl->mMixColor );
-
   // Set target value into data store
   if( animator.targetValue.GetType() != Property::NONE )
   {
@@ -385,7 +465,8 @@ void Visual::Base::AnimateProperty( Dali::Animation& transition, Internal::Trans
     }
     else
     {
-      // Note: there may be several of these calls if more than one transform property is animated.
+      // Note: there may be several of these calls if more than one
+      // transform property is animated.
       Property::Map map;
       if( animator.propertyKey.type == Property::Key::INDEX )
       {
@@ -402,69 +483,23 @@ void Visual::Base::AnimateProperty( Dali::Animation& transition, Internal::Trans
 
   if( index != Property::INVALID_INDEX )
   {
-    if( mImpl->mRenderer )
-    {
-      if( animator.animate == false )
-      {
-        mImpl->mRenderer.SetProperty( index, animator.targetValue );
-        if( isMixColor )
-        {
-          mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, mImpl->mMixColor.a < 1.0 ? BlendMode::ON : BlendMode::AUTO );
-        }
-      }
-      else
-      {
-        if( animator.initialValue.GetType() != Property::NONE )
-        {
-          if( isMixColor )
-          {
-            animator.initialValue.Get( currentMixColor );
-          }
-
-#if defined(DEBUG_ENABLED)
-          {
-            std::ostringstream oss;
-            oss << animator.initialValue;
-            DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "  Setting Initial Value - %s\n", oss.str().c_str() );
-          }
-#endif
-          mImpl->mRenderer.SetProperty( index, animator.initialValue );
-        }
-
-        if( isMixColor )
-        {
-          mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE,
-                                        ( currentMixColor.a < 1.0 || mImpl->mMixColor.a < 1.0 ) ? BlendMode::ON : BlendMode::AUTO );
-        }
-
-        if( ! transition )
-        {
-          transition = Dali::Animation::New( 0.1f );
-        }
+    SetupTransition( transition, animator, index );
 
-#if defined(DEBUG_ENABLED)
-        {
-          std::ostringstream oss;
-          oss << animator.targetValue;
-          DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "  Animating to Value - %s\n", oss.str().c_str() );
-        }
-#endif
-
-        transition.AnimateTo( Property( mImpl->mRenderer, index ),
-                              animator.targetValue,
-                              animator.alphaFunction,
-                              TimePeriod( animator.timePeriodDelay,
-                                          animator.timePeriodDuration ) );
+    // For mix color, ensure the blend mode is on if the initial or final values are not opaque,
+    // and that it is turned off after the animation ends if the final value is opaque
+    if( isMixColor && (!isMixColorOpaque || mImpl->mMixColor.a < 1.0f) )
+    {
+      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
 
-        if( isMixColor && currentMixColor.a < 1.0f && mImpl->mMixColor.a >= 1.0f )
+      if( animator.animate == true && mImpl->mMixColor.a >= 1.0f )
+      {
+        // When it becomes opaque, set the blend mode back to automatically
+        if( ! mImpl->mBlendSlotDelegate )
         {
-          // When it becomes opaque, set the blend mode back to automatically
-          if( ! mImpl->mBlendSlotDelegate )
-          {
-            mImpl->mBlendSlotDelegate = new SlotDelegate<Visual::Base>(this);
-          }
-          transition.FinishedSignal().Connect( *(mImpl->mBlendSlotDelegate), &Visual::Base::OnMixColorFinished );
+          mImpl->mBlendSlotDelegate = new SlotDelegate<Visual::Base>(this);
         }
+        transition.FinishedSignal().Connect( *(mImpl->mBlendSlotDelegate),
+                                             &Visual::Base::OnMixColorFinished );
       }
     }
   }
index 054708f..1722964 100644 (file)
@@ -270,6 +270,27 @@ private:
   void RegisterMixColor();
 
   /**
+   * Find the matching property on the renderer or shader. If it's a shader
+   * property, register it on the renderer in order to animate it for this
+   * visual independently.
+   * @param[in] key The key to match.
+   * @return the matching index, or INVALID_INDEX if it's not found
+   */
+  Property::Index GetPropertyIndex( Property::Key key );
+
+  /**
+   * Set up the transition. If no animation is required, then
+   * transition will be untouched.
+   *
+   * @param[in] transition The transition to use or set up.
+   * @param[in] animator The animation data to use
+   * @param[in] index The property index on the renderer to animate
+   */
+  void SetupTransition( Dali::Animation& transition,
+                        Internal::TransitionData::Animator& animator,
+                        Property::Index index );
+
+  /**
    * When a mix color animation has finished, ensure the blend mode is set back
    * to the right value for the target opacity.
    */
index a0796ec..18dd3fd 100644 (file)
@@ -79,8 +79,10 @@ struct RegisteredVisual
   Toolkit::Visual::Base visual;
   bool enabled;
 
-  RegisteredVisual( Property::Index aIndex, Toolkit::Visual::Base &aVisual, bool aEnabled) :
-                   index(aIndex), visual(aVisual), enabled(aEnabled) {}
+  RegisteredVisual( Property::Index aIndex, Toolkit::Visual::Base &aVisual, bool aEnabled)
+  : index(aIndex), visual(aVisual), enabled(aEnabled)
+  {
+  }
 };
 
 typedef Dali::OwnerContainer< RegisteredVisual* > RegisteredVisualContainer;
@@ -793,8 +795,8 @@ void Control::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visu
   {
     Toolkit::GetImplementation(visual).SetOnStage( self );
   }
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual number of registered visuals(%d)\n",  mImpl->mVisuals.Size() );
 
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n",  visual.GetName().c_str(), index, enabled?"T":"F" );
 }
 
 void Control::UnregisterVisual( Property::Index index )
@@ -827,7 +829,7 @@ void Control::EnableVisual( Property::Index index, bool enable )
   {
     if (  (*iter)->enabled == enable )
     {
-      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual Already enabled set (%s) \n", enable?"enabled":"disabled");
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
       return;
     }
 
@@ -837,12 +839,12 @@ void Control::EnableVisual( Property::Index index, bool enable )
     {
       if ( enable )
       {
-        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting Visual(%d) on stage \n", index );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
         Toolkit::GetImplementation((*iter)->visual).SetOnStage( parentActor );
       }
       else
       {
-        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting Visual(%d) off stage \n", index );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
         Toolkit::GetImplementation((*iter)->visual).SetOffStage( parentActor );  // No need to call if control not staged.
       }
     }