Use RegisterUniqueProperty for some more renderers
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / color / color-visual.cpp
index 9ceed38..21a1a70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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 "color-visual.h"
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/rendering/renderer-devel.h>
 #include <dali/integration-api/debug.h>
 
 //INTERNAL INCLUDES
-#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
-#include <dali-toolkit/devel-api/visual-factory/devel-visual-properties.h>
-#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
-#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
 
 namespace Dali
 {
-
 namespace Toolkit
 {
-
 namespace Internal
 {
-
 namespace
 {
-const char * const COLOR_NAME("mixColor");
-
-const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
-  attribute mediump vec2 aPosition;\n
-  uniform mediump mat4 uMvpMatrix;\n
-  uniform mediump vec3 uSize;\n
-  \n
-  void main()\n
-  {\n
-    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
-    vertexPosition.xyz *= uSize;\n
-    gl_Position = uMvpMatrix * vertexPosition;\n
-  }\n
-);
-
-const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
-  uniform lowp vec4 uColor;\n
-  uniform lowp vec4 mixColor;\n
-  \n
-  void main()\n
-  {\n
-    gl_FragColor = mixColor*uColor;\n
-  }\n
-);
-}
+const int CUSTOM_PROPERTY_COUNT(12); // 5 transform properties + Blur Radius + Mix Color + border/corner
 
-ColorVisualPtr ColorVisual::New( VisualFactoryCache& factoryCache )
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[6] =
+  {
+    VisualFactoryCache::COLOR_SHADER,
+    VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER,
+    VisualFactoryCache::COLOR_SHADER_BORDERLINE,
+    VisualFactoryCache::COLOR_SHADER_ROUNDED_BORDERLINE,
+    VisualFactoryCache::COLOR_SHADER_BLUR_EDGE,
+    VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
+};
+
+// enum of required list when we select shader
+enum ColorVisualRequireFlag
+{
+  DEFAULT        = 0,
+  ROUNDED_CORNER = 1 << 0,
+  BORDERLINE     = 1 << 1,
+  BLUR           = 1 << 2,
+};
+} // unnamed namespace
+ColorVisualPtr ColorVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
 {
-  return new ColorVisual( factoryCache );
+  ColorVisualPtr colorVisualPtr(new ColorVisual(factoryCache));
+  colorVisualPtr->SetProperties(properties);
+  colorVisualPtr->Initialize();
+  return colorVisualPtr;
 }
 
-ColorVisual::ColorVisual( VisualFactoryCache& factoryCache )
-: Visual::Base( factoryCache ),
-  mMixColorIndex( Property::INVALID_INDEX )
+ColorVisual::ColorVisual(VisualFactoryCache& factoryCache)
+: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::COLOR),
+  mBlurRadius(0.0f),
+  mBlurRadiusIndex(Property::INVALID_INDEX),
+  mAlwaysUsingBlurRadius(false)
 {
 }
 
@@ -81,94 +82,220 @@ ColorVisual::~ColorVisual()
 {
 }
 
-void ColorVisual::DoSetProperties( const Property::Map& propertyMap )
+void ColorVisual::DoSetProperties(const Property::Map& propertyMap)
 {
-  Property::Value* color = propertyMap.Find( Toolkit::ColorVisual::Property::MIX_COLOR, COLOR_NAME );
-  if( !( color && color->Get(mMixColor) ) )
+  // By virtue of DoSetProperties being called last, this will override
+  // anything set by Toolkit::Visual::Property::MIX_COLOR
+  Property::Value* colorValue = propertyMap.Find(Toolkit::ColorVisual::Property::MIX_COLOR, MIX_COLOR);
+  if(colorValue)
   {
-    DALI_LOG_ERROR( "Fail to provide a color to the ColorVisual object\n" );
+    Vector4 color;
+    if(colorValue->Get(color))
+    {
+      Property::Type type = colorValue->GetType();
+      if(type == Property::VECTOR4)
+      {
+        SetMixColor(color);
+      }
+      else if(type == Property::VECTOR3)
+      {
+        Vector3 color3(color);
+        SetMixColor(color3);
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR("ColorVisual: mixColor property has incorrect type\n");
+    }
   }
-}
 
-void ColorVisual::SetSize( const Vector2& size )
-{
-  Visual::Base::SetSize( size );
+  Property::Value* blurRadiusValue = propertyMap.Find(Toolkit::DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME);
+  if(blurRadiusValue)
+  {
+    if(!blurRadiusValue->Get(mBlurRadius))
+    {
+      DALI_LOG_ERROR("ColorVisual:DoSetProperties:: BLUR_RADIUS property has incorrect type: %d\n", blurRadiusValue->GetType());
+    }
+
+    if(mBlurRadiusIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mRenderer.SetProperty(mBlurRadiusIndex, mBlurRadius);
+    }
+    else if(DALI_UNLIKELY(mImpl->mRenderer && (!EqualsZero(mBlurRadius) || mAlwaysUsingBlurRadius)))
+    {
+      // Unusual case. SetProperty called after OnInitialize().
+      // Assume that DoAction call UPDATE_PROPERTY.
+      // We must regist properies into renderer, and update shader.
+
+      // BlurRadius added by this action. Regist property to renderer.
+      mBlurRadiusIndex = mImpl->mRenderer.RegisterUniqueProperty(DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME, mBlurRadius);
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+      // Change the shader must not be occured many times. we always have to use blur feature.
+      mAlwaysUsingBlurRadius = true;
 
-  // ToDo: renderer responds to the size change
+      // Change shader
+      UpdateShader();
+    }
+  }
 }
 
-void ColorVisual::DoSetOnStage( Actor& actor )
+void ColorVisual::DoSetOnScene(Actor& actor)
 {
-  InitializeRenderer();
+  actor.AddRenderer(mImpl->mRenderer);
 
-  actor.AddRenderer( mImpl->mRenderer );
+  // Color Visual generated and ready to display
+  ResourceReady(Toolkit::Visual::ResourceStatus::READY);
 }
 
-void ColorVisual::DoCreatePropertyMap( Property::Map& map ) const
+void ColorVisual::DoSetOffScene(Actor& actor)
 {
-  map.Clear();
-  map.Insert( Toolkit::VisualProperty::TYPE, Toolkit::Visual::COLOR );
-  map.Insert( Toolkit::ColorVisual::Property::MIX_COLOR, mMixColor );
+  actor.RemoveRenderer(mImpl->mRenderer);
 }
 
-void ColorVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
+void ColorVisual::DoCreatePropertyMap(Property::Map& map) const
 {
-  // TODO
-  /* David Steele comented :
-
-     Some things to bear in mind:
-
-     We currently keep a copy of the mix color in the ColorVisual object, which is then used to instantiate the registered property on the renderer.
-
-     The user can get the renderer and animate the mixColor property (it's registered, so is automatically a scene-graph property).
+  map.Clear();
+  map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  map.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor);
 
-     The GetProperty method will have to read from the renderer, or from the cached value in the Visual, and the SetProperty will have to write to cache and to the renderer if present.
-  */
+  if(mImpl->mRenderer && mBlurRadiusIndex != Property::INVALID_INDEX)
+  {
+    // Update values from Renderer
+    float blurRadius = mImpl->mRenderer.GetProperty<float>(mBlurRadiusIndex);
+    map.Insert(Toolkit::DevelColorVisual::Property::BLUR_RADIUS, blurRadius);
+  }
+  else
+  {
+    map.Insert(Toolkit::DevelColorVisual::Property::BLUR_RADIUS, mBlurRadius);
+  }
 }
 
-Dali::Property::Value ColorVisual::DoGetProperty( Dali::Property::Index index )
+void ColorVisual::DoCreateInstancePropertyMap(Property::Map& map) const
 {
-  // TODO
-  return Dali::Property::Value();
+  // Do nothing
 }
 
-void ColorVisual::InitializeRenderer()
+void ColorVisual::OnSetTransform()
 {
-  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-  if( !geometry )
+  if(mImpl->mRenderer)
   {
-    geometry =  VisualFactoryCache::CreateQuadGeometry();
-    mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
+    mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
   }
+}
 
-  Shader shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
-  if( !shader )
+void ColorVisual::UpdateShader()
+{
+  if(mImpl->mRenderer)
   {
-    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-    mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER, shader );
+    Shader shader = GenerateShader();
+    mImpl->mRenderer.SetShader(shader);
   }
+}
+
+void ColorVisual::OnInitialize()
+{
+  Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
+
+  Shader shader = GenerateShader();
+
+  mImpl->mRenderer = Renderer::New(geometry, shader);
+  mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
 
-  mImpl->mRenderer = Renderer::New( geometry, shader );
+  // ColorVisual has it's own index key for mix color - use this instead
+  // of using the new base index to avoid changing existing applications
+  // String keys will get to this property.
+  mImpl->mMixColorIndex = mImpl->mRenderer.RegisterProperty(Toolkit::ColorVisual::Property::MIX_COLOR, MIX_COLOR, Vector3(mImpl->mMixColor));
 
-  mMixColorIndex = mImpl->mRenderer.RegisterProperty( Toolkit::ColorVisual::Property::MIX_COLOR, COLOR_NAME, mMixColor );
-  if( mMixColor.a < 1.f )
+  if(!EqualsZero(mBlurRadius))
   {
-    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+    mBlurRadiusIndex = mImpl->mRenderer.RegisterUniqueProperty(DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME, mBlurRadius);
+    mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
   }
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
 }
 
-void ColorVisual::SetColor(const Vector4& color)
+Shader ColorVisual::GenerateShader() const
 {
-  mMixColor = color;
+  Shader                         shader;
+  VisualFactoryCache::ShaderType shaderType;
+
+  bool roundedCorner  = IsRoundedCornerRequired();
+  bool borderline     = IsBorderlineRequired();
+  bool blur           = !EqualsZero(mBlurRadius) || mAlwaysUsingBlurRadius;
+  int  shaderTypeFlag = ColorVisualRequireFlag::DEFAULT;
+
+  if(roundedCorner)
+  {
+    shaderTypeFlag |= ColorVisualRequireFlag::ROUNDED_CORNER;
+  }
+  if(blur)
+  {
+    // If we use blur, just ignore borderline
+    borderline = false;
+    shaderTypeFlag |= ColorVisualRequireFlag::BLUR;
+  }
+  if(borderline)
+  {
+    shaderTypeFlag |= ColorVisualRequireFlag::BORDERLINE;
+  }
 
-  if( mImpl->mRenderer )
+  shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+  shader     = mFactoryCache.GetShader(shaderType);
+  if(!shader)
   {
-    (mImpl->mRenderer).SetProperty( mMixColorIndex, color );
-    if( color.a < 1.f )
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+    if(roundedCorner)
     {
-      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+      vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
     }
+    if(blur)
+    {
+      vertexShaderPrefixList += "#define IS_REQUIRED_BLUR 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BLUR 1\n";
+    }
+    if(borderline)
+    {
+      vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+    }
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
+    mFactoryCache.SaveShader(shaderType, shader);
+  }
+
+  return shader;
+}
+
+Dali::Property ColorVisual::OnGetPropertyObject(Dali::Property::Key key)
+{
+  if(!mImpl->mRenderer)
+  {
+    Handle handle;
+    return Dali::Property(handle, Property::INVALID_INDEX);
   }
+
+  if((key.type == Property::Key::INDEX && key.indexKey == DevelColorVisual::Property::BLUR_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == BLUR_RADIUS_NAME))
+  {
+    mBlurRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME, mBlurRadius);
+
+    // Blur is animated now. we always have to use blur feature.
+    mAlwaysUsingBlurRadius = true;
+
+    mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+    // Change shader
+    UpdateShader();
+
+    return Dali::Property(mImpl->mRenderer, mBlurRadiusIndex);
+  }
+
+  Handle handle;
+  return Dali::Property(handle, Property::INVALID_INDEX);
 }
 
 } // namespace Internal