X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Frenderers%2Fimage%2Fimage-renderer.cpp;h=7862d5326809420c683e4ddb66c12dff2ce1b684;hb=d43575da616e1370372b1331f47dce36dc4ac145;hp=b78cdab9f6ad70a31a1b27c08d958363113a8482;hpb=a073ebfd862b49692c8e6d7dff2b128e62a4f6df;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp index b78cdab..7862d53 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp @@ -19,6 +19,7 @@ #include "image-renderer.h" // EXTERNAL HEADER +#include // for strncasecmp #include #include @@ -27,6 +28,7 @@ #include #include #include +#include namespace Dali { @@ -39,6 +41,9 @@ namespace Internal namespace { +const char HTTP_URL[] = "http://"; +const char HTTPS_URL[] = "https://"; + const char * const RENDERER_TYPE("rendererType"); const char * const RENDERER_TYPE_VALUE("imageRenderer"); @@ -65,13 +70,22 @@ const char * const BOX_THEN_LINEAR("boxThenLinear"); const char * const NO_FILTER("noFilter"); const char * const DONT_CARE("dontCare"); -std::string TEXTURE_UNIFORM_NAME = "sTexture"; +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( attribute mediump vec2 aPosition;\n - varying mediump vec2 vTexCoord;\n uniform mediump mat4 uMvpMatrix;\n uniform mediump vec3 uSize;\n + uniform mediump vec4 uAtlasRect;\n + uniform mediump vec4 pixelArea; + varying mediump vec2 vTexCoord;\n \n void main()\n {\n @@ -79,7 +93,7 @@ const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( vertexPosition.xyz *= uSize;\n vertexPosition = uMvpMatrix * vertexPosition;\n \n - vTexCoord = aPosition + vec2(0.5);\n + vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n gl_Position = vertexPosition;\n }\n ); @@ -88,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 ); @@ -186,11 +201,13 @@ Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gri } //unnamed namespace -ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache ) +ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasManager& atlasManager ) : ControlRenderer( factoryCache ), + mAtlasManager( atlasManager ), mDesiredSize(), mFittingMode( FittingMode::DEFAULT ), - mSamplingMode( SamplingMode::DEFAULT ) + mSamplingMode( SamplingMode::DEFAULT ), + mIsAlphaPreMultiplied( false ) { } @@ -306,35 +323,23 @@ void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap mDesiredSize = ImageDimensions( desiredWidth, desiredHeight ); } + // remove old renderer if exit if( mImpl->mRenderer ) { - //remove old renderer - if( actor ) + if( actor ) //remove old renderer from actor { actor.RemoveRenderer( mImpl->mRenderer ); } - - //clean the cache - if( !oldImageUrl.empty() ) + if( !oldImageUrl.empty() ) //clean old renderer from cache { - mFactoryCache.CleanRendererCache( oldImageUrl ); - } - - //Initialize the renderer - if( !mImageUrl.empty() ) - { - InitializeRenderer( mImageUrl ); - } - else if( mImage ) - { - InitializeRenderer( mImage ); + CleanCache( oldImageUrl ); } + } - //add the new renderer to the actor - if( actor && mImpl->mRenderer ) - { - actor.AddRenderer( mImpl->mRenderer ); - } + // if actor is on stage, create new renderer and apply to actor + if( actor && actor.OnStage() ) + { + SetOnStage( actor ); } } @@ -385,30 +390,26 @@ Renderer ImageRenderer::CreateRenderer() const if( !mImpl->mCustomShader ) { geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); - shader = mFactoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER ); - if( !shader ) - { - shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ); - mFactoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader ); - } + shader = GetImageShader(mFactoryCache); } else { geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize ); if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() ) { - shader = mFactoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER ); - if( !shader ) - { - shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ); - mFactoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader ); - } + shader = GetImageShader(mFactoryCache); } else { shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader, mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader, mImpl->mCustomShader->mHints ); + if( mImpl->mCustomShader->mVertexShader.empty() ) + { + 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 ); + } } } @@ -418,36 +419,53 @@ Renderer ImageRenderer::CreateRenderer() const void ImageRenderer::InitializeRenderer( const std::string& imageUrl ) { - if( mImageUrl.empty() ) + if( imageUrl.empty() ) { - mImpl->mFlags &= ~Impl::IS_FROM_CACHE; return; } + mImageUrl = imageUrl; mImpl->mRenderer.Reset(); - if( !mImpl->mCustomShader ) + + if( !mImpl->mCustomShader && + ( strncasecmp( imageUrl.c_str(), HTTP_URL, sizeof(HTTP_URL) -1 ) != 0 ) && // ignore remote images + ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) ) { mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl ); if( !mImpl->mRenderer ) { - mImpl->mRenderer = CreateRenderer(); + Vector4 atlasRect; + Material material = mAtlasManager.Add(atlasRect, imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); + if( material ) + { + Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); + mImpl->mRenderer = Renderer::New( geometry, material ); + mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect ); + } + else // big image, atlasing is not applied + { + mImpl->mRenderer = CreateRenderer(); - ResourceImage image = Dali::ResourceImage::New( imageUrl ); - image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); - Material material = mImpl->mRenderer.GetMaterial(); - material.AddTexture( image, TEXTURE_UNIFORM_NAME ); + ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); + image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); + Material material = mImpl->mRenderer.GetMaterial(); + material.AddTexture( image, TEXTURE_UNIFORM_NAME ); + } mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer ); } + mImpl->mFlags |= Impl::IS_FROM_CACHE; } else { + // for custom shader or remote image, renderer is not cached and atlas is not applied + mImpl->mFlags &= ~Impl::IS_FROM_CACHE; mImpl->mRenderer = CreateRenderer(); - ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); - image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); - ApplyImageToSampler( image ); + ResourceImage resourceImage = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); + resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); + ApplyImageToSampler( resourceImage ); } } @@ -455,13 +473,12 @@ void ImageRenderer::InitializeRenderer( const Image& image ) { mImpl->mFlags &= ~Impl::IS_FROM_CACHE; - if( !image ) + mImpl->mRenderer = CreateRenderer(); + + if( image ) { - return; + ApplyImageToSampler( image ); } - - mImpl->mRenderer = CreateRenderer(); - ApplyImageToSampler( image ); } @@ -471,23 +488,12 @@ void ImageRenderer::DoSetOnStage( Actor& actor ) { InitializeRenderer( mImageUrl ); } - else if( mImage ) + else { InitializeRenderer( mImage ); } - if( !GetIsFromCache() ) - { - Image image = mImage; - if( !mImageUrl.empty() ) - { - ResourceImage resourceImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode ); - resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); - image = resourceImage; - } - - ApplyImageToSampler( image ); - } + EnablePreMultipliedAlpha( mIsAlphaPreMultiplied ); } void ImageRenderer::DoSetOffStage( Actor& actor ) @@ -495,11 +501,16 @@ void ImageRenderer::DoSetOffStage( Actor& actor ) //If we own the image then make sure we release it when we go off stage if( !mImageUrl.empty() ) { - //clean the renderer from the cache since it may no longer be in use - mFactoryCache.CleanRendererCache( mImageUrl ); + actor.RemoveRenderer( mImpl->mRenderer ); + CleanCache(mImageUrl); mImage.Reset(); } + else + { + actor.RemoveRenderer( mImpl->mRenderer ); + mImpl->mRenderer.Reset(); + } } void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const @@ -598,18 +609,34 @@ void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const } } -void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl ) +Shader ImageRenderer::GetImageShader( RendererFactoryCache& factoryCache ) { - SetImage( actor, imageUrl, 0, 0, Dali::FittingMode::DEFAULT, Dali::SamplingMode::DEFAULT ); + Shader shader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER ); + if( !shader ) + { + shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ); + 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; } -void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, int desiredWidth, int desiredHeight, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode ) +void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode ) { if( mImageUrl != imageUrl ) { + std::string oldImageUrl = mImageUrl; + mImageUrl = imageUrl; + mDesiredSize = size; + mFittingMode = fittingMode; + mSamplingMode = samplingMode; + mImage.Reset(); + if( mImpl->mRenderer ) { - if( GetIsFromCache() ) + if( GetIsFromCache() ) // if renderer is from cache, remove the old one { //remove old renderer if( actor ) @@ -618,33 +645,23 @@ void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, int des } //clean the cache - if( !mImageUrl.empty() ) + if( !oldImageUrl.empty() ) { - mFactoryCache.CleanRendererCache( mImageUrl ); + CleanCache(oldImageUrl); } - //Initialize the renderer - InitializeRenderer( imageUrl ); - - //add the new renderer to the actor - if( actor && mImpl->mRenderer ) + if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor { - actor.AddRenderer( mImpl->mRenderer ); + SetOnStage(actor); } } - else + else // if renderer is not from cache, reuse the same renderer and only change the texture { ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); ApplyImageToSampler( image ); } } - - mImageUrl = imageUrl; - mDesiredSize = ImageDimensions( desiredWidth, desiredHeight ); - mFittingMode = fittingMode; - mSamplingMode = samplingMode; - mImage.Reset(); } } @@ -652,9 +669,11 @@ void ImageRenderer::SetImage( Actor& actor, const Image& image ) { if( mImage != image ) { + mImage = image; + if( mImpl->mRenderer ) { - if( GetIsFromCache() ) + if( GetIsFromCache() ) // if renderer is from cache, remove the old one { //remove old renderer if( actor ) @@ -665,25 +684,21 @@ void ImageRenderer::SetImage( Actor& actor, const Image& image ) //clean the cache if( !mImageUrl.empty() ) { - mFactoryCache.CleanRendererCache( mImageUrl ); + CleanCache(mImageUrl); } + mImageUrl.clear(); - //Initialize the renderer - InitializeRenderer( image ); - - //add the new renderer to the actor - if( actor && mImpl->mRenderer ) + if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor { - actor.AddRenderer( mImpl->mRenderer ); + SetOnStage(actor); } } - else + else // if renderer is not from cache, reuse the same renderer and only change the texture { ApplyImageToSampler( image ); } } - mImage = image; mImageUrl.clear(); mDesiredSize = ImageDimensions(); mFittingMode = FittingMode::DEFAULT; @@ -691,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 ) @@ -714,14 +760,33 @@ void ImageRenderer::OnImageLoaded( ResourceImage image ) { if( image.GetLoadingState() == Dali::ResourceLoadingFailed ) { - Image image = RendererFactory::GetBrokenRendererImage(); + Image brokenImage = RendererFactory::GetBrokenRendererImage(); if( mImpl->mRenderer ) { - ApplyImageToSampler( image ); + ApplyImageToSampler( brokenImage ); } } } +void ImageRenderer::CleanCache(const std::string& url) +{ + Material material = mImpl->mRenderer.GetMaterial(); + + Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f ); + Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME ); + if( index != Property::INVALID_INDEX ) + { + Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index ); + atlasRectValue.Get( atlasRect ); + } + + mImpl->mRenderer.Reset(); + if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX ) + { + mAtlasManager.Remove( material, atlasRect ); + } +} + } // namespace Internal } // namespace Toolkit