2 * Copyright (c) 2015 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-renderer.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/adaptor-framework/bitmap-loader.h>
27 #include <dali/integration-api/debug.h>
30 #include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
31 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
32 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
33 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
34 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
35 #include <dali-toolkit/internal/controls/renderers/image-atlas-manager.h>
48 const char HTTP_URL[] = "http://";
49 const char HTTPS_URL[] = "https://";
52 const char * const IMAGE_FITTING_MODE( "fittingMode" );
53 const char * const IMAGE_SAMPLING_MODE( "samplingMode" );
54 const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
55 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
56 const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
59 const char * const SHRINK_TO_FIT("SHRINK_TO_FIT");
60 const char * const SCALE_TO_FILL("SCALE_TO_FILL");
61 const char * const FIT_WIDTH("FIT_WIDTH");
62 const char * const FIT_HEIGHT("FIT_HEIGHT");
63 const char * const DEFAULT("DEFAULT");
66 const char * const BOX("BOX");
67 const char * const NEAREST("NEAREST");
68 const char * const LINEAR("LINEAR");
69 const char * const BOX_THEN_NEAREST("BOX_THEN_NEAREST");
70 const char * const BOX_THEN_LINEAR("BOX_THEN_LINEAR");
71 const char * const NO_FILTER("NO_FILTER");
72 const char * const DONT_CARE("DONT_CARE");
74 const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea";
76 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
78 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
80 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
81 attribute mediump vec2 aPosition;\n
82 uniform mediump mat4 uMvpMatrix;\n
83 uniform mediump vec3 uSize;\n
84 uniform mediump vec4 uAtlasRect;\n
85 uniform mediump vec4 pixelArea;
86 varying mediump vec2 vTexCoord;\n
90 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
91 vertexPosition.xyz *= uSize;\n
92 vertexPosition = uMvpMatrix * vertexPosition;\n
94 vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n
95 gl_Position = vertexPosition;\n
99 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
100 varying mediump vec2 vTexCoord;\n
101 uniform sampler2D sTexture;\n
102 uniform lowp vec4 uColor;\n
106 gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
110 Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gridSize )
114 if( gridSize == ImageDimensions( 1, 1 ) )
116 geometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
119 geometry = Geometry::QUAD();
120 factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
125 geometry = RendererFactoryCache::CreateGridGeometry( gridSize );
131 } //unnamed namespace
133 ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
134 : ControlRenderer( factoryCache ),
135 mAtlasManager( atlasManager ),
137 mFittingMode( FittingMode::DEFAULT ),
138 mSamplingMode( SamplingMode::DEFAULT ),
139 mNativeFragmentShaderCode( ),
140 mNativeImageFlag( false )
144 ImageRenderer::~ImageRenderer()
148 void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
150 std::string oldImageUrl = mImageUrl;
152 Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
155 imageURLValue->Get( mImageUrl );
156 if( !mImageUrl.empty() )
161 Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
165 fittingValue->Get( fitting );
167 mFittingMode = FittingMode::DEFAULT;
168 if( fitting == SHRINK_TO_FIT )
170 mFittingMode = FittingMode::SHRINK_TO_FIT;
172 else if( fitting == SCALE_TO_FILL )
174 mFittingMode = FittingMode::SCALE_TO_FILL;
176 else if( fitting == FIT_WIDTH )
178 mFittingMode = FittingMode::FIT_WIDTH;
180 else if( fitting == FIT_HEIGHT )
182 mFittingMode = FittingMode::FIT_HEIGHT;
184 else if( fitting == DEFAULT )
186 mFittingMode = FittingMode::DEFAULT;
190 DALI_ASSERT_ALWAYS("Unknown fitting mode");
194 Property::Value* samplingValue = propertyMap.Find( IMAGE_SAMPLING_MODE );
197 std::string sampling;
198 samplingValue->Get( sampling );
200 mSamplingMode = SamplingMode::DEFAULT;
201 if( sampling == BOX )
203 mSamplingMode = SamplingMode::BOX;
205 else if( sampling == NEAREST )
207 mSamplingMode = SamplingMode::NEAREST;
209 else if( sampling == LINEAR )
211 mSamplingMode = SamplingMode::LINEAR;
213 else if( sampling == BOX_THEN_NEAREST )
215 mSamplingMode = SamplingMode::BOX_THEN_NEAREST;
217 else if( sampling == BOX_THEN_LINEAR )
219 mSamplingMode = SamplingMode::BOX_THEN_LINEAR;
221 else if( sampling == NO_FILTER )
223 mSamplingMode = SamplingMode::NO_FILTER;
225 else if( sampling == DONT_CARE )
227 mSamplingMode = SamplingMode::DONT_CARE;
229 else if( sampling == DEFAULT )
231 mSamplingMode = SamplingMode::DEFAULT;
235 DALI_ASSERT_ALWAYS("Unknown sampling mode");
239 int desiredWidth = 0;
240 Property::Value* desiredWidthValue = propertyMap.Find( IMAGE_DESIRED_WIDTH );
241 if( desiredWidthValue )
243 desiredWidthValue->Get( desiredWidth );
246 int desiredHeight = 0;
247 Property::Value* desiredHeightValue = propertyMap.Find( IMAGE_DESIRED_HEIGHT );
248 if( desiredHeightValue )
250 desiredHeightValue->Get( desiredHeight );
253 mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
257 Property::Value* syncLoading = propertyMap.Find( SYNCHRONOUS_LOADING );
261 syncLoading->Get( sync );
264 mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
268 mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
272 // if sync loading is required, the loading should start immediately when new image url is set or the actor is off stage
273 // ( for on-stage actor with image url unchanged, resource loading is already finished)
274 if( ( !mImpl->mRenderer || imageURLValue) && IsSynchronousResourceLoading() )
276 DoSynchronousResourceLoading();
279 // remove old renderer if exit
280 if( mImpl->mRenderer )
282 if( actor ) //remove old renderer from actor
284 actor.RemoveRenderer( mImpl->mRenderer );
286 if( !oldImageUrl.empty() ) //clean old renderer from cache
288 CleanCache( oldImageUrl );
292 NativeImage nativeImage = NativeImage::DownCast( mImage );
296 SetNativeFragmentShaderCode( nativeImage );
299 // if actor is on stage, create new renderer and apply to actor
300 if( actor && actor.OnStage() )
306 void ImageRenderer::SetSize( const Vector2& size )
308 ControlRenderer::SetSize( size );
311 void ImageRenderer::GetNaturalSize( Vector2& naturalSize ) const
315 naturalSize.x = mImage.GetWidth();
316 naturalSize.y = mImage.GetHeight();
319 else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
321 naturalSize.x = mDesiredSize.GetWidth();
322 naturalSize.y = mDesiredSize.GetHeight();
325 else if( !mImageUrl.empty() )
327 ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
328 naturalSize.x = dimentions.GetWidth();
329 naturalSize.y = dimentions.GetHeight();
333 naturalSize = Vector2::ZERO;
336 void ImageRenderer::SetClipRect( const Rect<int>& clipRect )
338 ControlRenderer::SetClipRect( clipRect );
341 void ImageRenderer::SetOffset( const Vector2& offset )
345 Renderer ImageRenderer::CreateRenderer() const
350 // If mImage is nativeImage with custom sampler or prefix, mNativeFragmentShaderCode will be applied.
351 // Renderer can't be shared between NativeImage and other image types.
352 if( !mNativeFragmentShaderCode.empty() )
354 return CreateNativeImageRenderer();
357 if( !mImpl->mCustomShader )
359 geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
361 shader = GetImageShader(mFactoryCache);
365 geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
366 if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
368 shader = GetImageShader(mFactoryCache);
372 shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
373 mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
374 mImpl->mCustomShader->mHints );
375 if( mImpl->mCustomShader->mVertexShader.empty() )
377 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
378 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
383 Renderer renderer = Renderer::New( geometry, shader );
388 Renderer ImageRenderer::CreateNativeImageRenderer() const
393 if( !mImpl->mCustomShader )
395 geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
397 shader = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
398 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
399 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
403 geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
404 shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
405 mNativeFragmentShaderCode,
406 mImpl->mCustomShader->mHints );
407 if( mImpl->mCustomShader->mVertexShader.empty() )
409 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
410 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
414 TextureSet textureSet = TextureSet::New();
415 Renderer renderer = Renderer::New( geometry, shader );
416 renderer.SetTextures( textureSet );
422 bool ImageRenderer::IsSynchronousResourceLoading() const
424 return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
427 void ImageRenderer::DoSynchronousResourceLoading()
429 if( !mImageUrl.empty() )
431 BitmapLoader loader = BitmapLoader::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
433 mPixels = loader.GetPixelData();
437 Image ImageRenderer::LoadImage( const std::string& url, bool synchronousLoading )
439 if( synchronousLoading )
444 return RendererFactory::GetBrokenRendererImage();
446 Atlas image = Atlas::New( mPixels->GetWidth(), mPixels->GetHeight(), mPixels->GetPixelFormat() );
447 image.Upload( mPixels, 0, 0 );
452 ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
453 resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
454 return resourceImage;
458 TextureSet ImageRenderer::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading )
460 TextureSet textureSet;
461 textureRect = FULL_TEXTURE_RECT;
462 if( synchronousLoading )
467 textureSet = TextureSet::New();
468 textureSet.SetImage( 0u, RendererFactory::GetBrokenRendererImage() );
472 textureSet = mAtlasManager.Add(textureRect, mPixels );
473 if( !textureSet ) // big image, no atlasing
475 Atlas image = Atlas::New( mPixels->GetWidth(), mPixels->GetHeight(), mPixels->GetPixelFormat() );
476 image.Upload( mPixels, 0, 0 );
477 textureSet = TextureSet::New();
478 textureSet.SetImage( 0u, image );
484 textureSet = mAtlasManager.Add(textureRect, url, mDesiredSize, mFittingMode, mSamplingMode );
485 if( !textureSet ) // big image, no atlasing
487 ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
488 resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
489 textureSet = TextureSet::New();
490 textureSet.SetImage( 0u, resourceImage );
497 void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
499 if( imageUrl.empty() )
504 mImageUrl = imageUrl;
505 mImpl->mRenderer.Reset();
507 if( !mImpl->mCustomShader &&
508 ( strncasecmp( imageUrl.c_str(), HTTP_URL, sizeof(HTTP_URL) -1 ) != 0 ) && // ignore remote images
509 ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) )
511 mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
512 if( !mImpl->mRenderer )
515 TextureSet textureSet = CreateTextureSet(atlasRect, imageUrl, IsSynchronousResourceLoading() );
516 Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
517 Shader shader( GetImageShader(mFactoryCache) );
518 mImpl->mRenderer = Renderer::New( geometry, shader );
519 mImpl->mRenderer.SetTextures( textureSet );
520 if( atlasRect != FULL_TEXTURE_RECT )
522 mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
524 mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
527 mImpl->mFlags |= Impl::IS_FROM_CACHE;
531 // for custom shader or remote image, renderer is not cached and atlas is not applied
533 mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
534 mImpl->mRenderer = CreateRenderer();
535 Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
536 ApplyImageToSampler( image );
540 void ImageRenderer::InitializeRenderer( const Image& image )
542 mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
544 mImpl->mRenderer = CreateRenderer();
548 ApplyImageToSampler( image );
553 void ImageRenderer::DoSetOnStage( Actor& actor )
555 if( !mImageUrl.empty() )
557 InitializeRenderer( mImageUrl );
561 InitializeRenderer( mImage );
566 void ImageRenderer::DoSetOffStage( Actor& actor )
568 //If we own the image then make sure we release it when we go off stage
569 if( !mImageUrl.empty() )
571 actor.RemoveRenderer( mImpl->mRenderer );
572 CleanCache(mImageUrl);
577 actor.RemoveRenderer( mImpl->mRenderer );
578 mImpl->mRenderer.Reset();
582 void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
585 map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
587 bool sync = IsSynchronousResourceLoading();
588 map.Insert( SYNCHRONOUS_LOADING, sync );
589 if( !mImageUrl.empty() )
591 map.Insert( IMAGE_URL_NAME, mImageUrl );
592 map.Insert( IMAGE_DESIRED_WIDTH, mDesiredSize.GetWidth() );
593 map.Insert( IMAGE_DESIRED_HEIGHT, mDesiredSize.GetHeight() );
597 map.Insert( IMAGE_DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
598 map.Insert( IMAGE_DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
600 ResourceImage resourceImage = ResourceImage::DownCast(mImage);
603 map.Insert( IMAGE_URL_NAME, resourceImage.GetUrl() );
607 switch( mFittingMode )
609 case Dali::FittingMode::FIT_HEIGHT:
611 map.Insert( IMAGE_FITTING_MODE, FIT_HEIGHT );
614 case Dali::FittingMode::FIT_WIDTH:
616 map.Insert( IMAGE_FITTING_MODE, FIT_WIDTH );
619 case Dali::FittingMode::SCALE_TO_FILL:
621 map.Insert( IMAGE_FITTING_MODE, SCALE_TO_FILL );
624 case Dali::FittingMode::SHRINK_TO_FIT:
626 map.Insert( IMAGE_FITTING_MODE, SHRINK_TO_FIT );
631 map.Insert( IMAGE_FITTING_MODE, DEFAULT );
636 switch( mSamplingMode )
638 case Dali::SamplingMode::BOX:
640 map.Insert( IMAGE_SAMPLING_MODE, BOX );
643 case Dali::SamplingMode::NEAREST:
645 map.Insert( IMAGE_SAMPLING_MODE, NEAREST );
648 case Dali::SamplingMode::LINEAR:
650 map.Insert( IMAGE_SAMPLING_MODE, LINEAR );
653 case Dali::SamplingMode::BOX_THEN_LINEAR:
655 map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_LINEAR );
658 case Dali::SamplingMode::BOX_THEN_NEAREST:
660 map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_NEAREST );
663 case Dali::SamplingMode::NO_FILTER:
665 map.Insert( IMAGE_SAMPLING_MODE, NO_FILTER );
668 case Dali::SamplingMode::DONT_CARE:
670 map.Insert( IMAGE_SAMPLING_MODE, DONT_CARE );
675 map.Insert( IMAGE_SAMPLING_MODE, DEFAULT );
681 Shader ImageRenderer::GetImageShader( RendererFactoryCache& factoryCache )
683 Shader shader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
686 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
687 factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
688 shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
689 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
694 void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
696 if( mImageUrl != imageUrl )
698 std::string oldImageUrl = mImageUrl;
699 mImageUrl = imageUrl;
701 mFittingMode = fittingMode;
702 mSamplingMode = samplingMode;
705 if( IsSynchronousResourceLoading() )
707 DoSynchronousResourceLoading();
710 if( mImpl->mRenderer )
712 if( GetIsFromCache() ) // if renderer is from cache, remove the old one
714 //remove old renderer
717 actor.RemoveRenderer( mImpl->mRenderer );
721 if( !oldImageUrl.empty() )
723 CleanCache(oldImageUrl);
726 if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
731 else // if renderer is not from cache, reuse the same renderer and only change the texture
733 Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
734 ApplyImageToSampler( image );
740 void ImageRenderer::SetImage( Actor& actor, const Image& image )
742 if( mImage != image )
744 NativeImage newNativeImage = NativeImage::DownCast( image );
745 bool newRendererFlag = true;
747 if( newNativeImage && !mNativeImageFlag )
749 SetNativeFragmentShaderCode( newNativeImage );
752 if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) )
754 newRendererFlag = false;
759 mNativeImageFlag = true;
763 mNativeFragmentShaderCode.clear();
764 mNativeImageFlag = false;
769 if( mImpl->mRenderer )
771 // if renderer is from cache, remove the old one, and create new renderer
772 if( GetIsFromCache() )
774 //remove old renderer
777 actor.RemoveRenderer( mImpl->mRenderer );
781 if( !mImageUrl.empty() )
783 CleanCache(mImageUrl);
787 if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
792 // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer
793 else if( newRendererFlag )
795 //remove old renderer
798 actor.RemoveRenderer( mImpl->mRenderer );
801 if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
806 else // if renderer is not from cache, reuse the same renderer and only change the texture
808 ApplyImageToSampler( image );
813 mDesiredSize = ImageDimensions();
814 mFittingMode = FittingMode::DEFAULT;
815 mSamplingMode = SamplingMode::DEFAULT;
819 void ImageRenderer::ApplyImageToSampler( const Image& image )
823 TextureSet textureSet = mImpl->mRenderer.GetTextures();
826 textureSet = TextureSet::New();
827 mImpl->mRenderer.SetTextures( textureSet );
829 textureSet.SetImage( 0u, image );
833 void ImageRenderer::OnImageLoaded( ResourceImage image )
835 if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
837 Image brokenImage = RendererFactory::GetBrokenRendererImage();
838 if( mImpl->mRenderer )
840 ApplyImageToSampler( brokenImage );
845 void ImageRenderer::CleanCache(const std::string& url)
847 TextureSet textureSet = mImpl->mRenderer.GetTextures();
849 Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
850 Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
851 if( index != Property::INVALID_INDEX )
853 Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
854 atlasRectValue.Get( atlasRect );
857 mImpl->mRenderer.Reset();
858 if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
860 mAtlasManager.Remove( textureSet, atlasRect );
864 void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage )
866 const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
867 const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
871 mNativeFragmentShaderCode = fragmentPreFix;
872 mNativeFragmentShaderCode += "\n";
875 if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
877 mNativeFragmentShaderCode += mImpl->mCustomShader->mFragmentShader;
881 mNativeFragmentShaderCode += FRAGMENT_SHADER;
884 if( customSamplerTypename )
886 mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
890 } // namespace Internal
892 } // namespace Toolkit