From 543e89293214ebed96d22ac8aa5522e217ec18f9 Mon Sep 17 00:00:00 2001 From: Xiangyin Ma Date: Fri, 15 Jan 2016 15:26:25 +0000 Subject: [PATCH] Pre-multiplied Alpha support for ImageView Change-Id: Ia2a4c293e96e239a84f5e039304e25a4ba6b4492 --- .../src/dali-toolkit/utc-Dali-ImageView.cpp | 48 ++++++++++++++++++++++ .../controls/image-view/image-view-impl.cpp | 40 +++++++++++++++++- .../internal/controls/image-view/image-view-impl.h | 16 ++++++++ .../controls/renderers/image/image-renderer.cpp | 45 +++++++++++++++++++- .../controls/renderers/image/image-renderer.h | 9 ++++ .../public-api/controls/image-view/image-view.h | 1 + 6 files changed, 156 insertions(+), 3 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index b00e79f..cc62d54 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -21,6 +21,8 @@ #include #include +#include +#include using namespace Dali; using namespace Toolkit; @@ -284,6 +286,52 @@ int UtcDaliImageViewSetGetProperty02(void) END_TEST; } + +int UtcDaliImageViewSetGetProperty03(void) +{ + ToolkitTestApplication application; + + Image image = CreateBufferImage( 10, 10, Color::WHITE ); + ImageView imageView = ImageView::New(image); + Stage::GetCurrent().Add( imageView ); + application.SendNotification(); + application.Render(); + + // conventional alpha blending + Material material = imageView.GetRendererAt( 0 ).GetMaterial(); + BlendingFactor::Type srcFactorRgb; + BlendingFactor::Type destFactorRgb; + BlendingFactor::Type srcFactorAlpha; + BlendingFactor::Type destFactorAlpha; + material.GetBlendFunc(srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha); + DALI_TEST_CHECK( srcFactorRgb == BlendingFactor::SRC_ALPHA ); + DALI_TEST_CHECK( destFactorRgb == BlendingFactor::ONE_MINUS_SRC_ALPHA ); + DALI_TEST_CHECK( srcFactorAlpha == BlendingFactor::ONE ); + DALI_TEST_CHECK( destFactorAlpha == BlendingFactor::ONE_MINUS_SRC_ALPHA ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + + float alphaBlendingUniform; + DALI_TEST_CHECK( gl.GetUniformValue( "uAlphaBlending", alphaBlendingUniform ) ); + DALI_TEST_EQUALS( alphaBlendingUniform, 1.f, TEST_LOCATION ); + + // pre-multiplied alpha blending + imageView.SetProperty( Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA, true ); + application.SendNotification(); + application.Render(); + + material.GetBlendFunc(srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha); + DALI_TEST_CHECK( srcFactorRgb == BlendingFactor::ONE ); + DALI_TEST_CHECK( destFactorRgb == BlendingFactor::ONE_MINUS_SRC_ALPHA ); + DALI_TEST_CHECK( srcFactorAlpha == BlendingFactor::ONE ); + DALI_TEST_CHECK( destFactorAlpha == BlendingFactor::ONE ); + + DALI_TEST_CHECK( gl.GetUniformValue( "uAlphaBlending", alphaBlendingUniform ) ); + DALI_TEST_EQUALS( alphaBlendingUniform, 0.f, TEST_LOCATION ); + + END_TEST; +} + int UtcDaliImageViewSizeWithBackground(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp index aaab3b6..aecb859 100644 --- a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp +++ b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp @@ -35,6 +35,7 @@ BaseHandle Create() DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ImageView, Toolkit::Control, Create ); DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "resourceUrl", STRING, RESOURCE_URL ) DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "image", MAP, IMAGE ) +DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA ) DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA ) DALI_TYPE_REGISTRATION_END() @@ -44,7 +45,8 @@ DALI_TYPE_REGISTRATION_END() using namespace Dali; ImageView::ImageView() -: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ) +: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ), + mPremultipledAlphaEnabled( false ) { } @@ -145,6 +147,26 @@ void ImageView::SetImage( const std::string& url, ImageDimensions size ) } } +void ImageView::EnablePreMultipliedAlpha( bool preMultipled ) +{ + mPremultipledAlphaEnabled = preMultipled; + + if( mRenderer ) + { + ControlRenderer& rendererImpl = GetImplementation( mRenderer ); + if (&typeid( rendererImpl ) == &typeid(ImageRenderer) ) + { + ImageRenderer* imageRenderer = static_cast( &rendererImpl ); + imageRenderer->EnablePreMultipliedAlpha( preMultipled ); + } + } +} + +bool ImageView::IsPreMultipliedAlphaEnabled() const +{ + return mPremultipledAlphaEnabled; +} + void ImageView::SetDepthIndex( int depthIndex ) { if( mRenderer ) @@ -266,6 +288,16 @@ void ImageView::SetProperty( BaseObject* object, Property::Index index, const Pr break; } + + case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA: + { + bool IsPre; + if( value.Get( IsPre ) ) + { + GetImpl(imageView).EnablePreMultipliedAlpha( IsPre ); + } + break; + } } } } @@ -308,6 +340,12 @@ Property::Value ImageView::GetProperty( BaseObject* object, Property::Index prop } break; } + + case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA: + { + value = impl.IsPreMultipliedAlphaEnabled(); + break; + } } } diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.h b/dali-toolkit/internal/controls/image-view/image-view-impl.h index 19d75ac..2b31bf9 100644 --- a/dali-toolkit/internal/controls/image-view/image-view-impl.h +++ b/dali-toolkit/internal/controls/image-view/image-view-impl.h @@ -75,6 +75,20 @@ public: */ void SetImage( const std::string& imageUrl, ImageDimensions size ); + /** + * @brief Set whether the Pre-multiplied Alpha Blending is required + * + * @param[in] preMultipled whether alpha is pre-multiplied. + */ + void EnablePreMultipliedAlpha( bool preMultipled ); + + /** + * @brief Query whether alpha is pre-multiplied. + * + * @return True is alpha is pre-multiplied, false otherwise. + */ + bool IsPreMultipliedAlphaEnabled() const; + // Properties /** * Called when a property of an object of this type is set. @@ -140,6 +154,8 @@ private: std::string mUrl; ///< the url for the image if the image came from a URL, empty otherwise Image mImage; ///< the Image if the image came from a Image, null otherwise Property::Map mPropertyMap; ///< the Property::Map if the image came from a Property::Map, empty otherwise + + bool mPremultipledAlphaEnabled; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp index 8b13a4e..7862d53 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp @@ -73,6 +73,10 @@ const char * const DONT_CARE("dontCare"); const std::string TEXTURE_UNIFORM_NAME = "sTexture"; const std::string ATLAS_RECT_UNIFORM_NAME = "uAtlasRect"; const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea"; + +// Set this uniform to 1.0 for conventional alpha blending; if pre-multiplied alpha blending, set this uniform to 0.0 +const std::string ALPHA_BLENDING_UNIFORM_NAME = "uAlphaBlending"; + const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( @@ -98,10 +102,11 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER( varying mediump vec2 vTexCoord;\n uniform sampler2D sTexture;\n uniform lowp vec4 uColor;\n + uniform lowp float uAlphaBlending; // Set to 1.0 for conventional alpha blending; if pre-multiplied alpha blending, set to 0.0 \n void main()\n {\n - gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n + gl_FragColor = texture2D( sTexture, vTexCoord ) * vec4( uColor.rgb*max( uAlphaBlending, uColor.a ), uColor.a );\n }\n ); @@ -201,7 +206,8 @@ ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasMana mAtlasManager( atlasManager ), mDesiredSize(), mFittingMode( FittingMode::DEFAULT ), - mSamplingMode( SamplingMode::DEFAULT ) + mSamplingMode( SamplingMode::DEFAULT ), + mIsAlphaPreMultiplied( false ) { } @@ -402,6 +408,7 @@ Renderer ImageRenderer::CreateRenderer() const { shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT ); shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f ); } } } @@ -485,6 +492,8 @@ void ImageRenderer::DoSetOnStage( Actor& actor ) { InitializeRenderer( mImage ); } + + EnablePreMultipliedAlpha( mIsAlphaPreMultiplied ); } void ImageRenderer::DoSetOffStage( Actor& actor ) @@ -609,6 +618,7 @@ Shader ImageRenderer::GetImageShader( RendererFactoryCache& factoryCache ) factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader ); shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT ); shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f ); } return shader; } @@ -696,6 +706,37 @@ void ImageRenderer::SetImage( Actor& actor, const Image& image ) } } +void ImageRenderer::EnablePreMultipliedAlpha( bool preMultipled ) +{ + mIsAlphaPreMultiplied = preMultipled; + if( mImpl->mRenderer ) + { + Material material = mImpl->mRenderer.GetMaterial(); + + if( preMultipled ) + { + material.SetBlendFunc( BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA, + BlendingFactor::ONE, BlendingFactor::ONE ); + if( !mImpl->mCustomShader || mImpl->mCustomShader->mVertexShader.empty()) + { + material.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 0.f ); + } + } + else + { + // using default blend func + material.SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA, + BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA ); + + Property::Index index = material.GetPropertyIndex( ALPHA_BLENDING_UNIFORM_NAME ); + if( index != Property::INVALID_INDEX ) // only set value when the property already exist on the Material + { + material.SetProperty( index, 1.f ); + } + } + } +} + void ImageRenderer::ApplyImageToSampler( const Image& image ) { if( image ) diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.h b/dali-toolkit/internal/controls/renderers/image/image-renderer.h index 2a8af0f..4b73fc6 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.h +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.h @@ -162,6 +162,13 @@ public: */ void SetImage( Actor& actor, const Image& image ); + /** + * @brief Set whether the Pre-multiplied Alpha Blending is required + * + * @param[in] preMultipled whether alpha is pre-multiplied. + */ + void EnablePreMultipliedAlpha( bool preMultipled ); + private: /** @@ -217,6 +224,8 @@ private: Dali::ImageDimensions mDesiredSize; Dali::FittingMode::Type mFittingMode; Dali::SamplingMode::Type mSamplingMode; + bool mIsAlphaPreMultiplied; + }; } // namespace Internal diff --git a/dali-toolkit/public-api/controls/image-view/image-view.h b/dali-toolkit/public-api/controls/image-view/image-view.h index b5f7db7..898fd3f 100644 --- a/dali-toolkit/public-api/controls/image-view/image-view.h +++ b/dali-toolkit/public-api/controls/image-view/image-view.h @@ -68,6 +68,7 @@ public: // Event side properties RESOURCE_URL = PROPERTY_START_INDEX, ///< name "resourceUrl", @deprecated DALi 1.1.16 Use IMAGE instead. type string IMAGE, ///< name "image", @see SetImage(), type string if it is a url, map otherwise + PRE_MULTIPLIED_ALPHA, ///< name "preMultipliedAlpha", @since DALi 1.1.18 type Boolean @pre image must be initialized. // Animatable properties PIXEL_AREA = ANIMATABLE_PROPERTY_START_INDEX, ///< name "pixelArea", @since DALi 1.1.18 type Vector4, Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0]. -- 2.7.4