Make hole match with Actor size at color visual shader 55/314255/11
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 9 Jul 2024 08:58:17 +0000 (17:58 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 25 Jul 2024 05:31:28 +0000 (14:31 +0900)
There was some needs that ignore the contents area when we use Shadow.

Since visual itself doesn't know the area of view, we should use
just uSize and visual itself's corner radius.

Change-Id: I1ae6104c9d8260f43230d2949af45c8b244419f6
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
dali-toolkit/devel-api/visuals/color-visual-properties-devel.h
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/graphics/shaders/color-visual-shader.vert
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.h
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h

index e2659ff..252fbba 100644 (file)
@@ -555,6 +555,7 @@ int UtcDaliVisualGetPropertyMap1(void)
   propertyMap.Insert(DevelVisual::Property::BORDERLINE_COLOR, Color::RED);
   propertyMap.Insert(DevelVisual::Property::BORDERLINE_OFFSET, -1.0f);
   propertyMap.Insert(DevelColorVisual::Property::BLUR_RADIUS, 20.0f);
+  propertyMap.Insert(DevelColorVisual::Property::CUTOUT_POLICY, DevelColorVisual::CutoutPolicy::CUTOUT_VIEW_WITH_CORNER_RADIUS);
   Visual::Base colorVisual = factory.CreateVisual(propertyMap);
 
   Property::Map resultMap;
@@ -592,6 +593,10 @@ int UtcDaliVisualGetPropertyMap1(void)
   DALI_TEST_CHECK(blurRadiusValue);
   DALI_TEST_CHECK(blurRadiusValue->Get<float>() == 20.0f);
 
+  Property::Value* cutoutPolicyValue = resultMap.Find(DevelColorVisual::Property::CUTOUT_POLICY, Property::INTEGER);
+  DALI_TEST_CHECK(cutoutPolicyValue);
+  DALI_TEST_CHECK(cutoutPolicyValue->Get<int>() == DevelColorVisual::CutoutPolicy::CUTOUT_VIEW_WITH_CORNER_RADIUS);
+
   // change the blend color
   propertyMap[ColorVisual::Property::MIX_COLOR] = Color::CYAN;
   colorVisual                                   = factory.CreateVisual(propertyMap);
@@ -611,6 +616,35 @@ int UtcDaliVisualGetPropertyMap1(void)
   DALI_TEST_CHECK(blurRadiusValue);
   DALI_TEST_CHECK(blurRadiusValue->Get<float>() == 0.0f);
 
+  // Test wrong values 2
+  propertyMap[DevelColorVisual::Property::CUTOUT_POLICY] = Vector2(2.0f, 3.0f);
+
+  colorVisual = factory.CreateVisual(propertyMap);
+  colorVisual.CreatePropertyMap(resultMap);
+
+  cutoutPolicyValue = resultMap.Find(DevelColorVisual::Property::CUTOUT_POLICY, Property::INTEGER);
+  DALI_TEST_CHECK(cutoutPolicyValue);
+  DALI_TEST_CHECK(cutoutPolicyValue->Get<int>() == DevelColorVisual::CutoutPolicy::NONE);
+
+  // Test property set by string
+  propertyMap[DevelColorVisual::Property::CUTOUT_POLICY] = "CUTOUT_VIEW";
+
+  colorVisual = factory.CreateVisual(propertyMap);
+  colorVisual.CreatePropertyMap(resultMap);
+
+  cutoutPolicyValue = resultMap.Find(DevelColorVisual::Property::CUTOUT_POLICY, Property::INTEGER);
+  DALI_TEST_CHECK(cutoutPolicyValue);
+  DALI_TEST_CHECK(cutoutPolicyValue->Get<int>() == DevelColorVisual::CutoutPolicy::CUTOUT_VIEW);
+
+  propertyMap[DevelColorVisual::Property::CUTOUT_POLICY] = "CUTOUT_VIEW_WITH_CORNER_RADIUS";
+
+  colorVisual = factory.CreateVisual(propertyMap);
+  colorVisual.CreatePropertyMap(resultMap);
+
+  cutoutPolicyValue = resultMap.Find(DevelColorVisual::Property::CUTOUT_POLICY, Property::INTEGER);
+  DALI_TEST_CHECK(cutoutPolicyValue);
+  DALI_TEST_CHECK(cutoutPolicyValue->Get<int>() == DevelColorVisual::CutoutPolicy::CUTOUT_VIEW_WITH_CORNER_RADIUS);
+
   END_TEST;
 }
 
@@ -6652,4 +6686,87 @@ int UtcDaliVisualUpdatePropertyChangeShader05(void)
   application.GetGlAbstraction().mShaderLanguageVersion = originalShaderVersion;
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliVisualCutoutPolicyChangeShader01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVisualCutoutPolicyChangeShader01: ColorVisual with cutout policy");
+
+  static std::vector<UniformData> customUniforms =
+    {
+      UniformData("uCutoutWithCornerRadius", Property::Type::INTEGER),
+    };
+
+  TestGraphicsController& graphics = application.GetGraphicsController();
+  graphics.AddCustomUniforms(customUniforms);
+
+  VisualFactory factory = VisualFactory::Get();
+
+  // Test (Enable/Disable) CornerRadius, (Enable/Disable) Borderline, (Enable/Disable) Blur, and 3 kind of CutoutPolicy
+  for(int testCase = 0; testCase < 2 * 2 * 2 * 3; ++testCase)
+  {
+    const bool enableCornerRadius = (testCase & 1);
+    const bool enableBorderline   = (testCase & 2);
+    const bool enableBlur         = (testCase & 4);
+
+    // clang-format off
+    const DevelColorVisual::CutoutPolicy::Type cutoutPolicy = (testCase / 8) == 0 ? DevelColorVisual::CutoutPolicy::NONE :
+                                                              (testCase / 8) == 1 ? DevelColorVisual::CutoutPolicy::CUTOUT_VIEW :
+                                                                                    DevelColorVisual::CutoutPolicy::CUTOUT_VIEW_WITH_CORNER_RADIUS;
+    // clang-format on
+
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
+    propertyMap.Insert(Visual::Property::MIX_COLOR, Color::BLUE);
+    if(enableCornerRadius)
+    {
+      propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, 10.0f);
+      propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE);
+    }
+    if(enableBorderline)
+    {
+      propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 20.0f);
+      propertyMap.Insert(DevelVisual::Property::BORDERLINE_COLOR, Color::RED);
+      propertyMap.Insert(DevelVisual::Property::BORDERLINE_OFFSET, -1.0f);
+    }
+    if(enableBlur)
+    {
+      propertyMap.Insert(DevelColorVisual::Property::BLUR_RADIUS, 20.0f);
+    }
+    propertyMap.Insert(DevelColorVisual::Property::CUTOUT_POLICY, cutoutPolicy);
+
+    Visual::Base colorVisual = factory.CreateVisual(propertyMap);
+
+    DummyControl        dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, colorVisual);
+    dummyControl[Actor::Property::SIZE] = Vector2(200.f, 200.f);
+    application.GetScene().Add(dummyControl);
+
+    application.SendNotification();
+    application.Render();
+
+    TestShaderCodeContainSubstrings(
+      dummyControl,
+      {
+        {"#define IS_REQUIRED_BLUR", enableBlur},
+        {"#define IS_REQUIRED_BORDERLINE", !enableBlur && enableBorderline}, ///< Since borderline is ignored, due to blur enabled.
+        {"#define IS_REQUIRED_ROUNDED_CORNER", enableCornerRadius},
+        {"#define IS_REQUIRED_CUTOUT", cutoutPolicy != DevelColorVisual::CutoutPolicy::NONE},
+      },
+      TEST_LOCATION);
+
+    if(cutoutPolicy != DevelColorVisual::CutoutPolicy::NONE)
+    {
+      auto& gl = application.GetGlAbstraction();
+      DALI_TEST_EQUALS(gl.CheckUniformValue<int>("uCutoutWithCornerRadius", cutoutPolicy == DevelColorVisual::CutoutPolicy::CUTOUT_VIEW_WITH_CORNER_RADIUS ? 1 : 0), true, TEST_LOCATION);
+    }
+    dummyControl.Unparent();
+
+    application.SendNotification();
+    application.Render();
+  }
+
+  END_TEST;
+}
index bae7111..4d5ed48 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -46,12 +46,34 @@ enum
    * @note Optional.
    * @note The default is 0.
    * @note The visual size increases by the blur radius.
+   * @note We cannot use blur radius and borderline properties at the same time.
    */
   BLUR_RADIUS = MIX_COLOR + 2,
+
+  /**
+   * @brief Policy of cutout the color render result.
+   * @details Name "cutoutPolicy", type Property::INTEGER.
+   * @note Optional.
+   * @note The default is CutoutPolicy::NONE.
+   */
+  CUTOUT_POLICY = MIX_COLOR + 3,
 };
 
 } // namespace Property
 
+/**
+ * @brief Enumeration for cutout policy.
+ */
+namespace CutoutPolicy
+{
+enum Type
+{
+  NONE,                           ///< Fully render the visual area (Default)
+  CUTOUT_VIEW,                    ///< Cutout the area of the view. It will use size of view.
+  CUTOUT_VIEW_WITH_CORNER_RADIUS, ///< Cutout the area of the view include visual's corner radius. It will use size of view.
+};
+} // namespace CutoutPolicy
+
 } // namespace DevelColorVisual
 
 } // namespace Toolkit
index 735f96b..e9d5c0e 100644 (file)
@@ -7,7 +7,14 @@ INPUT highp float vAliasMargin;
 INPUT highp vec4 vCornerRadius;
 #endif
 #endif
+#if defined(IS_REQUIRED_CUTOUT)
+INPUT highp vec2 vPositionFromCenter;
+#if defined(IS_REQUIRED_ROUNDED_CORNER)
+INPUT highp vec4 vCutoutCornerRadius;
+#endif
+#endif
 
+uniform highp vec3 uSize;
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
 #ifdef IS_REQUIRED_BLUR
@@ -19,6 +26,10 @@ uniform lowp vec4 borderlineColor;
 uniform lowp vec4 uActorColor;
 #endif
 
+#if defined(IS_REQUIRED_CUTOUT)
+uniform lowp int uCutoutWithCornerRadius;
+#endif
+
 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
 // Global values both rounded corner and borderline use
 
@@ -41,25 +52,25 @@ highp float gMinOutlinePotential = 0.0;
 highp float gMaxInlinePotential = 0.0;
 highp float gMinInlinePotential = 0.0;
 
-void calculateCornerRadius()
+void calculateCornerRadius(highp vec4 cornerRadius, highp vec2 position)
 {
 #ifdef IS_REQUIRED_ROUNDED_CORNER
   gRadius =
   mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
+    mix(cornerRadius.x, cornerRadius.y, sign(position.x) * 0.5 + 0.5),
+    mix(cornerRadius.w, cornerRadius.z, sign(position.x) * 0.5 + 0.5),
+    sign(position.y) * 0.5 + 0.5
   );
 #endif
 }
 
-void calculatePosition()
+void calculatePosition(highp vec2 position, highp vec2 halfSizeOfRect, highp float currentBorderlineWidth)
 {
-  gFragmentPosition = abs(vPosition) - vRectSize;
+  gFragmentPosition = abs(position) - halfSizeOfRect;
   gCenterPosition = -gRadius;
 #ifdef IS_REQUIRED_BLUR
 #elif defined(IS_REQUIRED_BORDERLINE)
-  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+  gCenterPosition += currentBorderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
 #endif
   gDiff = gFragmentPosition - gCenterPosition;
 }
@@ -69,7 +80,7 @@ void calculatePotential()
   gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
 }
 
-void setupMinMaxPotential()
+void setupMinMaxPotential(highp float currentBorderlineWidth)
 {
   gPotentialRange = vAliasMargin;
 
@@ -80,8 +91,8 @@ void setupMinMaxPotential()
   gMaxInlinePotential = gMaxOutlinePotential;
   gMinInlinePotential = gMinOutlinePotential;
 #elif defined(IS_REQUIRED_BORDERLINE)
-  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
-  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+  gMaxInlinePotential = gMaxOutlinePotential - currentBorderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - currentBorderlineWidth;
 #else
   gMaxInlinePotential = gMaxOutlinePotential;
   gMinInlinePotential = gMinOutlinePotential;
@@ -92,13 +103,13 @@ void setupMinMaxPotential()
   gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y) / max(1.0, gRadius), 0.0, 1.0);
 }
 
-void PreprocessPotential()
+void PreprocessPotential(highp vec4 cornerRadius, highp vec2 position, highp vec2 halfSizeOfRect, highp float currentBorderlineWidth)
 {
-  calculateCornerRadius();
-  calculatePosition();
+  calculateCornerRadius(cornerRadius, position);
+  calculatePosition(position, halfSizeOfRect, currentBorderlineWidth);
   calculatePotential();
 
-  setupMinMaxPotential();
+  setupMinMaxPotential(currentBorderlineWidth);
 }
 #endif
 
@@ -277,6 +288,38 @@ void main()
 {
   lowp vec4 targetColor = vec4(mixColor, 1.0) * uColor;
 
+#ifdef IS_REQUIRED_CUTOUT
+  mediump float discardOpacity = 1.0;
+
+  if(abs(vPositionFromCenter.x) <= uSize.x * 0.5 && abs(vPositionFromCenter.y) <= uSize.y * 0.5)
+  {
+#if defined(IS_REQUIRED_ROUNDED_CORNER)
+    if(uCutoutWithCornerRadius > 0)
+    {
+      // Ignore borderline width
+      PreprocessPotential(vCutoutCornerRadius, vPositionFromCenter, uSize.xy * 0.5, 0.0);
+
+      // Decrease potential range, to avoid alias make some hole.
+      gMinOutlinePotential -= gPotentialRange * 0.5;
+      gMaxOutlinePotential -= gPotentialRange * 0.5;
+
+      discardOpacity = smoothstep(gMinOutlinePotential, gMaxOutlinePotential, gPotential);
+    }
+    else
+    {
+      discardOpacity = 0.0;
+    }
+
+    if(discardOpacity < 0.001)
+    {
+      discard;
+    }
+#else
+    discard;
+#endif
+  }
+#endif
+
 #if defined(IS_REQUIRED_BLUR) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
   // skip most potential calculate for performance
   if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
@@ -285,7 +328,16 @@ void main()
   }
   else
   {
-    PreprocessPotential();
+    highp vec4 tempCornerRadius = vec4(0.0);
+    highp float tempBorderlineWidth = 0.0;
+#ifdef IS_REQUIRED_ROUNDED_CORNER
+    tempCornerRadius = vCornerRadius;
+#endif
+#ifdef IS_REQUIRED_BLUR
+#elif defined(IS_REQUIRED_BORDERLINE)
+    tempBorderlineWidth = borderlineWidth;
+#endif
+    PreprocessPotential(tempCornerRadius, vPosition, vRectSize, tempBorderlineWidth);
 #endif
 
 #ifdef IS_REQUIRED_BLUR
@@ -305,4 +357,8 @@ void main()
 #if defined(IS_REQUIRED_BLUR) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
   }
 #endif
+
+#ifdef IS_REQUIRED_CUTOUT
+  OUT_COLOR.a *= discardOpacity;
+#endif
 }
index 29b7442..223de22 100644 (file)
@@ -8,6 +8,12 @@ OUTPUT highp float vAliasMargin;
 OUTPUT highp vec4 vCornerRadius;
 #endif
 #endif
+#if defined(IS_REQUIRED_CUTOUT)
+OUTPUT highp vec2 vPositionFromCenter;
+#if defined(IS_REQUIRED_ROUNDED_CORNER)
+OUTPUT highp vec4 vCutoutCornerRadius;
+#endif
+#endif
 
 uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
@@ -92,7 +98,17 @@ vec4 ComputeVertexPosition()
 #else
   highp vec2 vPosition = aPosition * visualSize;
 #endif
+
+#if defined(IS_REQUIRED_CUTOUT)
+  vPositionFromCenter = vPosition + anchorPoint * visualSize + visualOffset + origin * uSize.xy;
+#if defined(IS_REQUIRED_ROUNDED_CORNER)
+  vCutoutCornerRadius = mix(cornerRadius * min(uSize.x, uSize.y), cornerRadius, cornerRadiusPolicy);
+  vCutoutCornerRadius = min(vCutoutCornerRadius, min(uSize.x, uSize.y) * 0.5);
+#endif
+  return vec4(vPositionFromCenter, 0.0, 1.0);
+#else
   return vec4(vPosition + anchorPoint * visualSize + visualOffset + origin * uSize.xy, 0.0, 1.0);
+#endif
 }
 
 void main()
index 10856d3..435eac0 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 // CLASS HEADER
-#include "color-visual.h"
+#include <dali-toolkit/internal/visuals/color/color-visual.h>
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/rendering/renderer-devel.h>
@@ -24,7 +24,6 @@
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
 
 //INTERNAL INCLUDES
-#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>
@@ -42,16 +41,32 @@ namespace Internal
 {
 namespace
 {
-const int CUSTOM_PROPERTY_COUNT(0);
+const int CUSTOM_PROPERTY_COUNT(0); ///< Note : cutout policy property will be registered only of the cutout view is used.
+                                    ///<        We don't need to reserve that property memory always.
+
+// cutout policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN(CUTOUT_POLICY)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelColorVisual::CutoutPolicy, NONE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelColorVisual::CutoutPolicy, CUTOUT_VIEW)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelColorVisual::CutoutPolicy, CUTOUT_VIEW_WITH_CORNER_RADIUS)
+DALI_ENUM_TO_STRING_TABLE_END(CUTOUT_POLICY)
+
+constexpr VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[] = {
+  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,
+};
 
-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,
+constexpr VisualFactoryCache::ShaderType SHADER_TYPE_WITH_CUTOUT_TABLE[] = {
+  VisualFactoryCache::COLOR_SHADER_CUTOUT,
+  VisualFactoryCache::COLOR_SHADER_CUTOUT_ROUNDED_CORNER,
+  VisualFactoryCache::COLOR_SHADER_CUTOUT_BORDERLINE,
+  VisualFactoryCache::COLOR_SHADER_CUTOUT_ROUNDED_BORDERLINE,
+  VisualFactoryCache::COLOR_SHADER_CUTOUT_BLUR_EDGE,
+  VisualFactoryCache::COLOR_SHADER_CUTOUT_ROUNDED_CORNER_BLUR_EDGE,
 };
 
 // enum of required list when we select shader
@@ -65,6 +80,7 @@ enum ColorVisualRequireFlag
 
 constexpr uint32_t MINIMUM_SHADER_VERSION_SUPPORT_ROUNDED_BLUR = 300;
 } // unnamed namespace
+
 ColorVisualPtr ColorVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
 {
   ColorVisualPtr colorVisualPtr(new ColorVisual(factoryCache));
@@ -76,6 +92,7 @@ ColorVisualPtr ColorVisual::New(VisualFactoryCache& factoryCache, const Property
 ColorVisual::ColorVisual(VisualFactoryCache& factoryCache)
 : Visual::Base(factoryCache, Visual::FittingMode::DONT_CARE, Toolkit::Visual::COLOR),
   mBlurRadius(0.0f),
+  mCutoutPolicy(DevelColorVisual::CutoutPolicy::NONE),
   mAlwaysUsingBlurRadius(false)
 {
 }
@@ -141,6 +158,22 @@ void ColorVisual::DoSetProperties(const Property::Map& propertyMap)
       }
     }
   }
+
+  Property::Value* cutoutPolicyValue = propertyMap.Find(Toolkit::DevelColorVisual::Property::CUTOUT_POLICY, CUTOUT_POLICY_NAME);
+  if(cutoutPolicyValue)
+  {
+    int cutoutPolicy = static_cast<int>(DevelColorVisual::CutoutPolicy::NONE) - 1; ///< Make always invalid
+    if(DALI_UNLIKELY(!Scripting::GetEnumerationProperty(*cutoutPolicyValue, CUTOUT_POLICY_TABLE, CUTOUT_POLICY_TABLE_COUNT, cutoutPolicy)))
+    {
+      std::ostringstream oss;
+      oss << *cutoutPolicyValue;
+      DALI_LOG_ERROR("ColorVisual:DoSetProperties:: CUTOUT_POLICY property has incorrect type : %d, value : %s\n", cutoutPolicyValue->GetType(), oss.str().c_str());
+    }
+    else
+    {
+      mCutoutPolicy = static_cast<DevelColorVisual::CutoutPolicy::Type>(cutoutPolicy);
+    }
+  }
 }
 
 void ColorVisual::DoSetOnScene(Actor& actor)
@@ -161,6 +194,7 @@ void ColorVisual::DoCreatePropertyMap(Property::Map& map) const
   map.Clear();
   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
   map.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor);
+  map.Insert(Toolkit::DevelColorVisual::Property::CUTOUT_POLICY, mCutoutPolicy);
 
   if(mImpl->mRenderer)
   {
@@ -223,6 +257,12 @@ void ColorVisual::OnInitialize()
     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
   }
 
+  if(IsCutoutRequired())
+  {
+    int cutoutWithCornerRadius = (mCutoutPolicy == DevelColorVisual::CutoutPolicy::CUTOUT_VIEW_WITH_CORNER_RADIUS) ? 1 : 0;
+    mImpl->mRenderer.RegisterUniqueProperty("uCutoutWithCornerRadius", cutoutWithCornerRadius);
+  }
+
   // Register transform properties
   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
 }
@@ -235,6 +275,7 @@ Shader ColorVisual::GenerateShader() const
   bool roundedCorner  = IsRoundedCornerRequired();
   bool borderline     = IsBorderlineRequired();
   bool blur           = IsBlurRequired();
+  bool cutout         = IsCutoutRequired();
   int  shaderTypeFlag = ColorVisualRequireFlag::DEFAULT;
 
   if(blur)
@@ -252,7 +293,7 @@ Shader ColorVisual::GenerateShader() const
     shaderTypeFlag |= ColorVisualRequireFlag::BORDERLINE;
   }
 
-  shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+  shaderType = cutout ? SHADER_TYPE_WITH_CUTOUT_TABLE[shaderTypeFlag] : SHADER_TYPE_TABLE[shaderTypeFlag];
   shader     = mFactoryCache.GetShader(shaderType);
   if(!shader)
   {
@@ -279,6 +320,11 @@ Shader ColorVisual::GenerateShader() const
       vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
       fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
     }
+    if(cutout)
+    {
+      vertexShaderPrefixList += "#define IS_REQUIRED_CUTOUT\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_CUTOUT\n";
+    }
 
     shader = mFactoryCache.GenerateAndSaveShader(shaderType,
                                                  Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_VERT.data(),
@@ -331,6 +377,11 @@ bool ColorVisual::IsBlurRequired() const
   return mAlwaysUsingBlurRadius || !EqualsZero(blurRadius);
 }
 
+bool ColorVisual::IsCutoutRequired() const
+{
+  return (mCutoutPolicy != DevelColorVisual::CutoutPolicy::NONE);
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 0a8a8b2..ae93885 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_COLOR_VISUAL_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -22,6 +22,7 @@
 #include <dali/public-api/common/intrusive-ptr.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 
 namespace Dali
@@ -131,6 +132,13 @@ protected:
    */
   bool IsBlurRequired() const;
 
+  /**
+   * @brief Query whether the visual requires to cutout feature.
+   *
+   * @return Returns true if the cutout is required, false otherwise.
+   */
+  bool IsCutoutRequired() const;
+
 private:
   // Undefined
   ColorVisual(const ColorVisual& colorRenderer);
@@ -139,8 +147,10 @@ private:
   ColorVisual& operator=(const ColorVisual& colorRenderer);
 
 private:
-  float mBlurRadius;                ///< The blur radius
-  bool  mAlwaysUsingBlurRadius : 1; ///< Whether we need the blur radius in shader always.
+  float mBlurRadius; ///< The blur radius
+
+  DevelColorVisual::CutoutPolicy::Type mCutoutPolicy : 3;          ///< The policy of cutout
+  bool                                 mAlwaysUsingBlurRadius : 1; ///< Whether we need the blur radius in shader always.
 };
 
 } // namespace Internal
index 3a61d4d..2e6f88c 100644 (file)
@@ -62,6 +62,12 @@ public:
     COLOR_SHADER_ROUNDED_BORDERLINE,
     COLOR_SHADER_BLUR_EDGE,
     COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
+    COLOR_SHADER_CUTOUT,
+    COLOR_SHADER_CUTOUT_ROUNDED_CORNER,
+    COLOR_SHADER_CUTOUT_BORDERLINE,
+    COLOR_SHADER_CUTOUT_ROUNDED_BORDERLINE,
+    COLOR_SHADER_CUTOUT_BLUR_EDGE,
+    COLOR_SHADER_CUTOUT_ROUNDED_CORNER_BLUR_EDGE,
     BORDER_SHADER,
     BORDER_SHADER_ANTI_ALIASING,
     GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
index d4df78c..53a271b 100644 (file)
@@ -53,6 +53,12 @@ DALI_ENUM_TO_STRING_TABLE_BEGIN(VISUAL_SHADER_TYPE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_ROUNDED_BORDERLINE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_BLUR_EDGE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_CUTOUT)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_CUTOUT_ROUNDED_CORNER)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_CUTOUT_BORDERLINE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_CUTOUT_ROUNDED_BORDERLINE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_CUTOUT_BLUR_EDGE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, COLOR_SHADER_CUTOUT_ROUNDED_CORNER_BLUR_EDGE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, BORDER_SHADER)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, BORDER_SHADER_ANTI_ALIASING)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Internal::VisualFactoryCache::ShaderType, GRADIENT_SHADER_LINEAR_BOUNDING_BOX)
@@ -172,6 +178,7 @@ const char* const CORNER_RADIUS_POLICY("cornerRadiusPolicy");
 
 // Color visual
 const char* const BLUR_RADIUS_NAME("blurRadius");
+const char* const CUTOUT_POLICY_NAME("cutoutPolicy");
 
 // Image visual
 const char* const IMAGE_URL_NAME("url");
index 1e7eea9..2a5a68d 100644 (file)
@@ -74,6 +74,7 @@ extern const char* const CORNER_RADIUS_POLICY;
 
 // Color visual
 extern const char* const BLUR_RADIUS_NAME;
+extern const char* const CUTOUT_POLICY_NAME;
 
 // Image visual
 extern const char* const IMAGE_URL_NAME;