2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "image-visual.h"
22 #include <cstring> // for strncasecmp
23 #include <dali/public-api/images/resource-image.h>
24 #include <dali/public-api/images/native-image.h>
25 #include <dali/devel-api/images/atlas.h>
26 #include <dali/devel-api/images/texture-set-image.h>
27 #include <dali/devel-api/adaptor-framework/bitmap-loader.h>
28 #include <dali/integration-api/debug.h>
31 #include <dali-toolkit/internal/controls/renderers/visual-string-constants.h>
32 #include <dali-toolkit/internal/controls/renderers/visual-factory-impl.h>
33 #include <dali-toolkit/internal/controls/renderers/visual-factory-cache.h>
34 #include <dali-toolkit/internal/controls/renderers/visual-impl.h>
35 #include <dali-toolkit/internal/controls/renderers/visual-data-impl.h>
36 #include <dali-toolkit/internal/controls/renderers/image-atlas-manager.h>
49 const char HTTP_URL[] = "http://";
50 const char HTTPS_URL[] = "https://";
53 const char * const IMAGE_FITTING_MODE( "fittingMode" );
54 const char * const IMAGE_SAMPLING_MODE( "samplingMode" );
55 const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
56 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
57 const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
60 const char * const SHRINK_TO_FIT("SHRINK_TO_FIT");
61 const char * const SCALE_TO_FILL("SCALE_TO_FILL");
62 const char * const FIT_WIDTH("FIT_WIDTH");
63 const char * const FIT_HEIGHT("FIT_HEIGHT");
64 const char * const DEFAULT("DEFAULT");
67 const char * const BOX("BOX");
68 const char * const NEAREST("NEAREST");
69 const char * const LINEAR("LINEAR");
70 const char * const BOX_THEN_NEAREST("BOX_THEN_NEAREST");
71 const char * const BOX_THEN_LINEAR("BOX_THEN_LINEAR");
72 const char * const NO_FILTER("NO_FILTER");
73 const char * const DONT_CARE("DONT_CARE");
75 const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea";
77 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
79 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
81 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
82 attribute mediump vec2 aPosition;\n
83 uniform mediump mat4 uMvpMatrix;\n
84 uniform mediump vec3 uSize;\n
85 uniform mediump vec4 uAtlasRect;\n
86 uniform mediump vec4 pixelArea;
87 varying mediump vec2 vTexCoord;\n
91 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
92 vertexPosition.xyz *= uSize;\n
93 vertexPosition = uMvpMatrix * vertexPosition;\n
95 vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n
96 gl_Position = vertexPosition;\n
100 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
101 varying mediump vec2 vTexCoord;\n
102 uniform sampler2D sTexture;\n
103 uniform lowp vec4 uColor;\n
107 gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
111 Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridSize )
115 if( gridSize == ImageDimensions( 1, 1 ) )
117 geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
120 geometry = VisualFactoryCache::CreateQuadGeometry();
121 factoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
126 geometry = VisualFactoryCache::CreateGridGeometry( gridSize );
132 } //unnamed namespace
134 ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
135 : Visual( factoryCache ),
136 mAtlasManager( atlasManager ),
138 mFittingMode( FittingMode::DEFAULT ),
139 mSamplingMode( SamplingMode::DEFAULT ),
140 mNativeFragmentShaderCode( ),
141 mNativeImageFlag( false )
145 ImageVisual::~ImageVisual()
149 void ImageVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
151 std::string oldImageUrl = mImageUrl;
153 Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
156 imageURLValue->Get( mImageUrl );
157 if( !mImageUrl.empty() )
162 Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
166 fittingValue->Get( fitting );
168 mFittingMode = FittingMode::DEFAULT;
169 if( fitting == SHRINK_TO_FIT )
171 mFittingMode = FittingMode::SHRINK_TO_FIT;
173 else if( fitting == SCALE_TO_FILL )
175 mFittingMode = FittingMode::SCALE_TO_FILL;
177 else if( fitting == FIT_WIDTH )
179 mFittingMode = FittingMode::FIT_WIDTH;
181 else if( fitting == FIT_HEIGHT )
183 mFittingMode = FittingMode::FIT_HEIGHT;
185 else if( fitting == DEFAULT )
187 mFittingMode = FittingMode::DEFAULT;
191 DALI_ASSERT_ALWAYS("Unknown fitting mode");
195 Property::Value* samplingValue = propertyMap.Find( IMAGE_SAMPLING_MODE );
198 std::string sampling;
199 samplingValue->Get( sampling );
201 mSamplingMode = SamplingMode::DEFAULT;
202 if( sampling == BOX )
204 mSamplingMode = SamplingMode::BOX;
206 else if( sampling == NEAREST )
208 mSamplingMode = SamplingMode::NEAREST;
210 else if( sampling == LINEAR )
212 mSamplingMode = SamplingMode::LINEAR;
214 else if( sampling == BOX_THEN_NEAREST )
216 mSamplingMode = SamplingMode::BOX_THEN_NEAREST;
218 else if( sampling == BOX_THEN_LINEAR )
220 mSamplingMode = SamplingMode::BOX_THEN_LINEAR;
222 else if( sampling == NO_FILTER )
224 mSamplingMode = SamplingMode::NO_FILTER;
226 else if( sampling == DONT_CARE )
228 mSamplingMode = SamplingMode::DONT_CARE;
230 else if( sampling == DEFAULT )
232 mSamplingMode = SamplingMode::DEFAULT;
236 DALI_ASSERT_ALWAYS("Unknown sampling mode");
240 int desiredWidth = 0;
241 Property::Value* desiredWidthValue = propertyMap.Find( IMAGE_DESIRED_WIDTH );
242 if( desiredWidthValue )
244 desiredWidthValue->Get( desiredWidth );
247 int desiredHeight = 0;
248 Property::Value* desiredHeightValue = propertyMap.Find( IMAGE_DESIRED_HEIGHT );
249 if( desiredHeightValue )
251 desiredHeightValue->Get( desiredHeight );
254 mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
258 Property::Value* syncLoading = propertyMap.Find( SYNCHRONOUS_LOADING );
262 syncLoading->Get( sync );
265 mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
269 mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
273 // if sync loading is required, the loading should start immediately when new image url is set or the actor is off stage
274 // ( for on-stage actor with image url unchanged, resource loading is already finished)
275 if( ( !mImpl->mRenderer || imageURLValue) && IsSynchronousResourceLoading() )
277 DoSynchronousResourceLoading();
280 // remove old renderer if exit
281 if( mImpl->mRenderer )
283 if( actor ) //remove old renderer from actor
285 actor.RemoveRenderer( mImpl->mRenderer );
287 if( !oldImageUrl.empty() ) //clean old renderer from cache
289 CleanCache( oldImageUrl );
293 NativeImage nativeImage = NativeImage::DownCast( mImage );
297 SetNativeFragmentShaderCode( nativeImage );
300 // if actor is on stage, create new renderer and apply to actor
301 if( actor && actor.OnStage() )
307 void ImageVisual::SetSize( const Vector2& size )
309 Visual::SetSize( size );
312 void ImageVisual::GetNaturalSize( Vector2& naturalSize ) const
316 naturalSize.x = mImage.GetWidth();
317 naturalSize.y = mImage.GetHeight();
320 else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
322 naturalSize.x = mDesiredSize.GetWidth();
323 naturalSize.y = mDesiredSize.GetHeight();
326 else if( !mImageUrl.empty() )
328 ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
329 naturalSize.x = dimentions.GetWidth();
330 naturalSize.y = dimentions.GetHeight();
334 naturalSize = Vector2::ZERO;
337 void ImageVisual::SetClipRect( const Rect<int>& clipRect )
339 Visual::SetClipRect( clipRect );
342 void ImageVisual::SetOffset( const Vector2& offset )
346 Renderer ImageVisual::CreateRenderer() const
351 // If mImage is nativeImage with custom sampler or prefix, mNativeFragmentShaderCode will be applied.
352 // Renderer can't be shared between NativeImage and other image types.
353 if( !mNativeFragmentShaderCode.empty() )
355 return CreateNativeImageVisual();
358 if( !mImpl->mCustomShader )
360 geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
362 shader = GetImageShader(mFactoryCache);
366 geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
367 if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
369 shader = GetImageShader(mFactoryCache);
373 shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
374 mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
375 mImpl->mCustomShader->mHints );
376 if( mImpl->mCustomShader->mVertexShader.empty() )
378 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
379 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
384 Renderer renderer = Renderer::New( geometry, shader );
389 Renderer ImageVisual::CreateNativeImageVisual() const
394 if( !mImpl->mCustomShader )
396 geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
398 shader = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
399 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
400 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
404 geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
405 shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
406 mNativeFragmentShaderCode,
407 mImpl->mCustomShader->mHints );
408 if( mImpl->mCustomShader->mVertexShader.empty() )
410 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
411 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
415 TextureSet textureSet = TextureSet::New();
416 Renderer renderer = Renderer::New( geometry, shader );
417 renderer.SetTextures( textureSet );
423 bool ImageVisual::IsSynchronousResourceLoading() const
425 return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
428 void ImageVisual::DoSynchronousResourceLoading()
430 if( !mImageUrl.empty() )
432 BitmapLoader loader = BitmapLoader::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
434 mPixels = loader.GetPixelData();
438 Image ImageVisual::LoadImage( const std::string& url, bool synchronousLoading )
440 if( synchronousLoading )
445 return VisualFactory::GetBrokenRendererImage();
447 Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() );
448 image.Upload( mPixels, 0, 0 );
453 ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
454 resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
455 return resourceImage;
459 TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading )
461 TextureSet textureSet;
462 textureRect = FULL_TEXTURE_RECT;
463 if( synchronousLoading )
468 textureSet = TextureSet::New();
469 TextureSetImage( textureSet, 0u, VisualFactory::GetBrokenRendererImage() );
473 textureSet = mAtlasManager.Add(textureRect, mPixels );
474 if( !textureSet ) // big image, no atlasing
476 Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() );
477 image.Upload( mPixels, 0, 0 );
478 textureSet = TextureSet::New();
479 TextureSetImage( textureSet, 0u, image );
485 textureSet = mAtlasManager.Add(textureRect, url, mDesiredSize, mFittingMode, mSamplingMode );
486 if( !textureSet ) // big image, no atlasing
488 ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
489 resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
490 textureSet = TextureSet::New();
491 TextureSetImage( textureSet, 0u, resourceImage );
498 void ImageVisual::InitializeRenderer( const std::string& imageUrl )
500 if( imageUrl.empty() )
505 mImageUrl = imageUrl;
506 mImpl->mRenderer.Reset();
508 if( !mImpl->mCustomShader &&
509 ( strncasecmp( imageUrl.c_str(), HTTP_URL, sizeof(HTTP_URL) -1 ) != 0 ) && // ignore remote images
510 ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) )
512 mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
513 if( !mImpl->mRenderer )
516 TextureSet textureSet = CreateTextureSet(atlasRect, imageUrl, IsSynchronousResourceLoading() );
517 Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
518 Shader shader( GetImageShader(mFactoryCache) );
519 mImpl->mRenderer = Renderer::New( geometry, shader );
520 mImpl->mRenderer.SetTextures( textureSet );
521 if( atlasRect != FULL_TEXTURE_RECT )
523 mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
525 mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
528 mImpl->mFlags |= Impl::IS_FROM_CACHE;
532 // for custom shader or remote image, renderer is not cached and atlas is not applied
534 mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
535 mImpl->mRenderer = CreateRenderer();
536 Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
537 ApplyImageToSampler( image );
541 void ImageVisual::InitializeRenderer( const Image& image )
543 mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
545 mImpl->mRenderer = CreateRenderer();
549 ApplyImageToSampler( image );
554 void ImageVisual::DoSetOnStage( Actor& actor )
556 if( !mImageUrl.empty() )
558 InitializeRenderer( mImageUrl );
562 InitializeRenderer( mImage );
567 void ImageVisual::DoSetOffStage( Actor& actor )
569 //If we own the image then make sure we release it when we go off stage
570 if( !mImageUrl.empty() )
572 actor.RemoveRenderer( mImpl->mRenderer );
573 CleanCache(mImageUrl);
578 actor.RemoveRenderer( mImpl->mRenderer );
579 mImpl->mRenderer.Reset();
583 void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
586 map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
588 bool sync = IsSynchronousResourceLoading();
589 map.Insert( SYNCHRONOUS_LOADING, sync );
590 if( !mImageUrl.empty() )
592 map.Insert( IMAGE_URL_NAME, mImageUrl );
593 map.Insert( IMAGE_DESIRED_WIDTH, mDesiredSize.GetWidth() );
594 map.Insert( IMAGE_DESIRED_HEIGHT, mDesiredSize.GetHeight() );
598 map.Insert( IMAGE_DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
599 map.Insert( IMAGE_DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
601 ResourceImage resourceImage = ResourceImage::DownCast(mImage);
604 map.Insert( IMAGE_URL_NAME, resourceImage.GetUrl() );
608 switch( mFittingMode )
610 case Dali::FittingMode::FIT_HEIGHT:
612 map.Insert( IMAGE_FITTING_MODE, FIT_HEIGHT );
615 case Dali::FittingMode::FIT_WIDTH:
617 map.Insert( IMAGE_FITTING_MODE, FIT_WIDTH );
620 case Dali::FittingMode::SCALE_TO_FILL:
622 map.Insert( IMAGE_FITTING_MODE, SCALE_TO_FILL );
625 case Dali::FittingMode::SHRINK_TO_FIT:
627 map.Insert( IMAGE_FITTING_MODE, SHRINK_TO_FIT );
632 map.Insert( IMAGE_FITTING_MODE, DEFAULT );
637 switch( mSamplingMode )
639 case Dali::SamplingMode::BOX:
641 map.Insert( IMAGE_SAMPLING_MODE, BOX );
644 case Dali::SamplingMode::NEAREST:
646 map.Insert( IMAGE_SAMPLING_MODE, NEAREST );
649 case Dali::SamplingMode::LINEAR:
651 map.Insert( IMAGE_SAMPLING_MODE, LINEAR );
654 case Dali::SamplingMode::BOX_THEN_LINEAR:
656 map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_LINEAR );
659 case Dali::SamplingMode::BOX_THEN_NEAREST:
661 map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_NEAREST );
664 case Dali::SamplingMode::NO_FILTER:
666 map.Insert( IMAGE_SAMPLING_MODE, NO_FILTER );
669 case Dali::SamplingMode::DONT_CARE:
671 map.Insert( IMAGE_SAMPLING_MODE, DONT_CARE );
676 map.Insert( IMAGE_SAMPLING_MODE, DEFAULT );
682 Shader ImageVisual::GetImageShader( VisualFactoryCache& factoryCache )
684 Shader shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
687 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
688 factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
689 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
690 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
695 void ImageVisual::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
697 if( mImageUrl != imageUrl )
699 std::string oldImageUrl = mImageUrl;
700 mImageUrl = imageUrl;
702 mFittingMode = fittingMode;
703 mSamplingMode = samplingMode;
706 if( IsSynchronousResourceLoading() )
708 DoSynchronousResourceLoading();
711 if( mImpl->mRenderer )
713 if( GetIsFromCache() ) // if renderer is from cache, remove the old one
715 //remove old renderer
718 actor.RemoveRenderer( mImpl->mRenderer );
722 if( !oldImageUrl.empty() )
724 CleanCache(oldImageUrl);
727 if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
732 else // if renderer is not from cache, reuse the same renderer and only change the texture
734 Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
735 ApplyImageToSampler( image );
741 void ImageVisual::SetImage( Actor& actor, const Image& image )
743 if( mImage != image )
745 NativeImage newNativeImage = NativeImage::DownCast( image );
746 bool newRendererFlag = true;
748 if( newNativeImage && !mNativeImageFlag )
750 SetNativeFragmentShaderCode( newNativeImage );
753 if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) )
755 newRendererFlag = false;
760 mNativeImageFlag = true;
764 mNativeFragmentShaderCode.clear();
765 mNativeImageFlag = false;
770 if( mImpl->mRenderer )
772 // if renderer is from cache, remove the old one, and create new renderer
773 if( GetIsFromCache() )
775 //remove old renderer
778 actor.RemoveRenderer( mImpl->mRenderer );
782 if( !mImageUrl.empty() )
784 CleanCache(mImageUrl);
788 if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
793 // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer
794 else if( newRendererFlag )
796 //remove old renderer
799 actor.RemoveRenderer( mImpl->mRenderer );
802 if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
807 else // if renderer is not from cache, reuse the same renderer and only change the texture
809 ApplyImageToSampler( image );
814 mDesiredSize = ImageDimensions();
815 mFittingMode = FittingMode::DEFAULT;
816 mSamplingMode = SamplingMode::DEFAULT;
820 void ImageVisual::ApplyImageToSampler( const Image& image )
824 TextureSet textureSet = mImpl->mRenderer.GetTextures();
827 textureSet = TextureSet::New();
828 mImpl->mRenderer.SetTextures( textureSet );
830 TextureSetImage( textureSet, 0u, image );
834 void ImageVisual::OnImageLoaded( ResourceImage image )
836 if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
838 Image brokenImage = VisualFactory::GetBrokenRendererImage();
839 if( mImpl->mRenderer )
841 ApplyImageToSampler( brokenImage );
846 void ImageVisual::CleanCache(const std::string& url)
848 TextureSet textureSet = mImpl->mRenderer.GetTextures();
850 Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
851 Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
852 if( index != Property::INVALID_INDEX )
854 Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
855 atlasRectValue.Get( atlasRect );
858 mImpl->mRenderer.Reset();
859 if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
861 mAtlasManager.Remove( textureSet, atlasRect );
865 void ImageVisual::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage )
867 const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
868 const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
872 mNativeFragmentShaderCode = fragmentPreFix;
873 mNativeFragmentShaderCode += "\n";
876 if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
878 mNativeFragmentShaderCode += mImpl->mCustomShader->mFragmentShader;
882 mNativeFragmentShaderCode += FRAGMENT_SHADER;
885 if( customSamplerTypename )
887 mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
891 } // namespace Internal
893 } // namespace Toolkit