Property::Map propertyMap;
propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
propertyMap.Insert(Visual::Property::MIX_COLOR, Color::BLUE);
+ propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS, 10.0f );
Visual::Base colorVisual = factory.CreateVisual( propertyMap );
Property::Map resultMap;
DALI_TEST_CHECK( colorValue );
DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::BLUE );
+ Property::Value* radiusValue = resultMap.Find( DevelVisual::Property::CORNER_RADIUS, Property::FLOAT );
+ DALI_TEST_CHECK( radiusValue );
+ DALI_TEST_CHECK( radiusValue->Get< float >() == 10.0f );
+
// change the blend color
propertyMap[ColorVisual::Property::MIX_COLOR] = Color::CYAN;
colorVisual = factory.CreateVisual( propertyMap );
END_TEST;
}
+
+int UtcDaliVisualRoundedCorner(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliVisualRoundedCorner" );
+
+ // image visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float cornerRadius = 30.0f;
+
+ properties[Visual::Property::TYPE] = Visual::IMAGE;
+ properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+ properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetSize( 200.f, 200.f );
+ dummy.SetParentOrigin( ParentOrigin::CENTER );
+ Stage::GetCurrent().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+ }
+
+ // color visual
+ {
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map properties;
+ float cornerRadius = 30.0f;
+
+ properties[Visual::Property::TYPE] = Visual::COLOR;
+ properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+ properties["cornerRadius"] = cornerRadius;
+
+ Visual::Base visual = factory.CreateVisual( properties );
+
+ // trigger creation through setting on stage
+ DummyControl dummy = DummyControl::New( true );
+ Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ dummy.SetSize( 200.f, 200.f );
+ dummy.SetParentOrigin( ParentOrigin::CENTER );
+ Stage::GetCurrent().Add( dummy );
+
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+ }
+
+ END_TEST;
+}
* @note The default is defined by the type of visual (if it's suitable to be stretched or not).
*/
VISUAL_FITTING_MODE = OPACITY + 1,
+
+ /**
+ * @brief The radius for the rounded corners of the visual
+ * @details Name "cornerRadius", type Property::FLOAT or Property::VECTOR4.
+ * @note Optional.
+ */
+ CORNER_RADIUS = OPACITY + 2,
};
} // namespace Property
{
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
bool atlasing = false;
- Shader shader = mImageVisualShaderFactory.GetShader( mFactoryCache, atlasing, defaultWrapMode );
+ Shader shader = mImageVisualShaderFactory.GetShader( mFactoryCache, atlasing, defaultWrapMode, IsRoundedCornerRequired() );
Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
}
else
{
- shader = mImageVisualShaderFactory.GetShader( mFactoryCache, false, true );
+ shader = mImageVisualShaderFactory.GetShader( mFactoryCache, false, true, false );
}
Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
gl_FragColor = vec4(mixColor, 1.0)*uColor;\n
}\n
);
+
+const char* VERTEX_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+ attribute mediump vec2 aPosition;\n
+ uniform highp mat4 uMvpMatrix;\n
+ uniform mediump vec3 uSize;\n
+ varying mediump vec2 vPosition;\n
+ varying mediump vec2 vRectSize;\n
+ \n
+ //Visual size and offset
+ uniform mediump vec2 offset;\n
+ uniform mediump vec2 size;\n
+ uniform mediump vec4 offsetSizeMode;\n
+ uniform mediump vec2 origin;\n
+ uniform mediump vec2 anchorPoint;\n
+ uniform mediump float cornerRadius;\n
+ \n
+ vec4 ComputeVertexPosition()\n
+ {\n
+ vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+ vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+ vRectSize = visualSize / 2.0 - cornerRadius;\n
+ vPosition = aPosition* visualSize;\n
+ return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+ }\n
+ \n
+ void main()\n
+ {\n
+ gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+ }\n
+);
+
+//float distance = length( max( abs( position - center ), size ) - size ) - radius;
+const char* FRAGMENT_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+ varying mediump vec2 vPosition;\n
+ varying mediump vec2 vRectSize;\n
+ uniform lowp vec4 uColor;\n
+ uniform lowp vec3 mixColor;\n
+ uniform mediump float cornerRadius;\n
+ \n
+ void main()\n
+ {\n
+ mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - cornerRadius;\n
+ gl_FragColor = uColor * vec4( mixColor, 1.0 );\n
+ gl_FragColor.a *= smoothstep( 1.0, -1.0, dist );\n
+ }\n
+);
+
}
ColorVisualPtr ColorVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
{
Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
- Shader shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
- if( !shader )
+ Shader shader;
+ if( !IsRoundedCornerRequired() )
{
- shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER, shader );
+ shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER, shader );
+ }
+ }
+ else
+ {
+ shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER_ROUNDED_CORNER, FRAGMENT_SHADER_ROUNDED_CORNER );
+ mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER, shader );
+ }
}
mImpl->mRenderer = Renderer::New( geometry, shader );
for( int j = segmentStart; j<segmentEnd; j++ )
{
- float ratio = static_cast<float>(j-segmentStart)/segmentWidth;
+ float ratio = static_cast<float>(j-segmentStart)/(segmentWidth - 1);
Vector4 currentColor = mGradientStops[i].mStopColor * (1.f-ratio) + mGradientStops[i+1].mStopColor * ratio;
pixels[k*4] = static_cast<unsigned char>( 255.f * Clamp( currentColor.r, 0.f, 1.f ) );
pixels[k*4+1] = static_cast<unsigned char>( 255.f * Clamp( currentColor.g, 0.f, 1.f ) );
}\n
);
+const char* VERTEX_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+ attribute mediump vec2 aPosition;\n
+ uniform highp mat4 uMvpMatrix;\n
+ uniform mediump vec3 uSize;\n
+ uniform mediump vec4 pixelArea;
+ varying mediump vec2 vTexCoord;\n
+ varying mediump vec2 vPosition;\n
+ varying mediump vec2 vRectSize;\n
+ \n
+ //Visual size and offset
+ uniform mediump vec2 offset;\n
+ uniform mediump vec2 size;\n
+ uniform mediump vec4 offsetSizeMode;\n
+ uniform mediump vec2 origin;\n
+ uniform mediump vec2 anchorPoint;\n
+ uniform mediump float cornerRadius;\n
+ \n
+ vec4 ComputeVertexPosition()\n
+ {\n
+ vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+ vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+ vRectSize = visualSize / 2.0 - cornerRadius;\n
+ vPosition = aPosition* visualSize;\n
+ return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+ }\n
+\n
+ void main()\n
+ {\n
+ gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+ vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
+ }\n
+);
+
+//float distance = length( max( abs( position - center ), size ) - size ) - radius;
+const char* FRAGMENT_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+ varying mediump vec2 vTexCoord;\n
+ varying mediump vec2 vPosition;\n
+ varying mediump vec2 vRectSize;\n
+ uniform sampler2D sTexture;\n
+ uniform lowp vec4 uColor;\n
+ uniform lowp vec3 mixColor;\n
+ uniform mediump float cornerRadius;\n
+ \n
+ void main()\n
+ {\n
+ mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - cornerRadius;\n
+ gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );\n
+ gl_FragColor.a *= smoothstep( 1.0, -1.0, dist );\n
+ }\n
+);
+
} // unnamed namespace
ImageVisualShaderFactory::ImageVisualShaderFactory()
{
}
-Shader ImageVisualShaderFactory::GetShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping )
+Shader ImageVisualShaderFactory::GetShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner )
{
Shader shader;
if( atlasing )
}
else
{
- shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
- if( !shader )
+ if( roundedCorner )
+ {
+ shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER_ROUNDED_CORNER, FRAGMENT_SHADER_ROUNDED_CORNER );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, shader );
+ }
+ }
+ else
{
- shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_NO_ATLAS );
- shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
- factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
+ shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_NO_ATLAS );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
+ }
}
}
* @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
* @param[in] atlasing Whether texture atlasing is applied.
* @param[in] defaultTextureWrapping Whether the default texture wrap mode is applied.
+ * @param[in] roundedCorner Whether the rounded corder is applied.
*/
- Shader GetShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping );
+ Shader GetShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner );
/**
* Request the default vertex shader source.
shader = mImageVisualShaderFactory.GetShader( mFactoryCache,
mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
- mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE );
+ mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
+ IsRoundedCornerRequired() );
}
else
{
Shader shader;
if( !mImpl->mCustomShader )
{
- shader = mImageVisualShaderFactory.GetShader( mFactoryCache, mAttemptAtlasing, true );
+ shader = mImageVisualShaderFactory.GetShader( mFactoryCache, mAttemptAtlasing, true, false );
}
else
{
mTransform(),
mMixColor( Color::WHITE ),
mControlSize( Vector2::ZERO ),
+ mCornerRadius( 0.0f ),
mDepthIndex( 0.0f ),
mMixColorIndex( Property::INVALID_INDEX ),
+ mCornerRadiusIndex( Property::INVALID_INDEX ),
mFittingMode( fittingMode ),
mFlags( 0 ),
mResourceStatus( Toolkit::Visual::ResourceStatus::PREPARING )
Transform mTransform;
Vector4 mMixColor;
Size mControlSize;
+ float mCornerRadius;
int mDepthIndex;
Property::Index mMixColorIndex;
+ Property::Index mCornerRadiusIndex;
FittingMode mFittingMode; //< How the contents should fit the view
int mFlags;
Toolkit::Visual::ResourceStatus mResourceStatus;
{
matchKey = Property::Key( Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE );
}
+ else if( matchKey == CORNER_RADIUS )
+ {
+ matchKey = Property::Key( Toolkit::DevelVisual::Property::CORNER_RADIUS );
+ }
}
switch( matchKey.indexKey )
value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode );
break;
}
+ case Toolkit::DevelVisual::Property::CORNER_RADIUS:
+ {
+ float radius;
+ if( value.Get( radius ) )
+ {
+ mImpl->mCornerRadius = radius;
+ }
+ break;
+ }
}
}
{
RegisterMixColor();
+ if( IsRoundedCornerRequired() )
+ {
+ mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty( CORNER_RADIUS, mImpl->mCornerRadius );
+
+ mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+ }
+
mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
mImpl->mFlags |= Impl::IS_ON_STAGE; // Only sets the flag if renderer exists
{
DoSetOffStage( actor );
mImpl->mMixColorIndex = Property::INVALID_INDEX;
+ mImpl->mCornerRadiusIndex = Property::INVALID_INDEX;
mImpl->mFlags &= ~Impl::IS_ON_STAGE;
}
}
auto fittingModeString = Scripting::GetLinearEnumerationName< FittingMode >(
mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT );
map.Insert( Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString );
+
+ map.Insert( Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius );
}
void Visual::Base::CreateInstancePropertyMap( Property::Map& map ) const
return mImpl->mFlags & Impl::IS_ON_STAGE;
}
+bool Visual::Base::IsRoundedCornerRequired() const
+{
+ return !EqualsZero( mImpl->mCornerRadius );
+}
+
void Visual::Base::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
{
// May be overriden by derived class
*/
bool IsOnStage() const;
+ /**
+ * @brief Query whether the corners of the visual requires to be rounded.
+ *
+ * @return Returns true if the rounded corner is required, false otherwise.
+ */
+ bool IsRoundedCornerRequired() const;
+
private:
/**
enum ShaderType
{
COLOR_SHADER,
+ COLOR_SHADER_ROUNDED_CORNER,
BORDER_SHADER,
BORDER_SHADER_ANTI_ALIASING,
GRADIENT_SHADER_LINEAR_USER_SPACE,
IMAGE_SHADER,
IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
+ IMAGE_SHADER_ROUNDED_CORNER,
NINE_PATCH_SHADER,
NINE_PATCH_MASK_SHADER,
TEXT_SHADER_MULTI_COLOR_TEXT,
// Fitting mode
const char * const VISUAL_FITTING_MODE( "visualFittingMode" );
+// Corner radius
+const char * const CORNER_RADIUS( "cornerRadius" );
+
// Color visual
const char * const RENDER_IF_TRANSPARENT_NAME( "renderIfTransparent" );
// Fitting mode
extern const char * const VISUAL_FITTING_MODE;
+// Corner radius
+extern const char * const CORNER_RADIUS;
+
// Color visual
extern const char * const RENDER_IF_TRANSPARENT_NAME;