Stop using ImageActor in PageTurnView
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / image / image-renderer.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "image-renderer.h"
20
21 // EXTERNAL HEADER
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/integration-api/debug.h>
26
27 // INTERNAL HEADER
28 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
29 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
30 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
31 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
32 #include <dali-toolkit/internal/controls/renderers/image-atlas-manager.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Internal
41 {
42
43 namespace
44 {
45 const char HTTP_URL[] = "http://";
46 const char HTTPS_URL[] = "https://";
47
48 const char * const RENDERER_TYPE("rendererType");
49 const char * const RENDERER_TYPE_VALUE("image");
50
51 // property names
52 const char * const IMAGE_URL_NAME( "imageUrl" );
53 const char * const IMAGE_FITTING_MODE( "imageFittingMode" );
54 const char * const IMAGE_SAMPLING_MODE( "imageSamplingMode" );
55 const char * const IMAGE_DESIRED_WIDTH( "imageDesiredWidth" );
56 const char * const IMAGE_DESIRED_HEIGHT( "imageDesiredHeight" );
57
58 // fitting modes
59 const char * const SHRINK_TO_FIT("shrinkToFit");
60 const char * const SCALE_TO_FILL("scaleToFill");
61 const char * const FIT_WIDTH("fitWidth");
62 const char * const FIT_HEIGHT("fitHeight");
63 const char * const DEFAULT("default");
64
65 // sampling modes
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("boxThenNearest");
70 const char * const BOX_THEN_LINEAR("boxThenLinear");
71 const char * const NO_FILTER("noFilter");
72 const char * const DONT_CARE("dontCare");
73
74 const std::string TEXTURE_UNIFORM_NAME = "sTexture";
75 const std::string ATLAS_RECT_UNIFORM_NAME = "uAtlasRect";
76 const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea";
77
78 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
79
80 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
81
82 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
83   attribute mediump vec2 aPosition;\n
84   uniform mediump mat4 uMvpMatrix;\n
85   uniform mediump vec3 uSize;\n
86   uniform mediump vec4 uAtlasRect;\n
87   uniform mediump vec4 pixelArea;
88   varying mediump vec2 vTexCoord;\n
89   \n
90   void main()\n
91   {\n
92     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
93     vertexPosition.xyz *= uSize;\n
94     vertexPosition = uMvpMatrix * vertexPosition;\n
95     \n
96     vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n
97     gl_Position = vertexPosition;\n
98   }\n
99 );
100
101 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
102   varying mediump vec2 vTexCoord;\n
103   uniform sampler2D sTexture;\n
104   uniform lowp vec4 uColor;\n
105   \n
106   void main()\n
107   {\n
108     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
109   }\n
110 );
111
112 Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gridSize )
113 {
114   Geometry geometry;
115
116   if( gridSize == ImageDimensions( 1, 1 ) )
117   {
118     geometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
119     if( !geometry )
120     {
121       geometry =  RendererFactoryCache::CreateQuadGeometry();
122       factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
123     }
124   }
125   else
126   {
127     geometry = RendererFactoryCache::CreateGridGeometry( gridSize );
128   }
129
130   return geometry;
131 }
132
133 } //unnamed namespace
134
135 ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
136 : ControlRenderer( factoryCache ),
137   mAtlasManager( atlasManager ),
138   mDesiredSize(),
139   mFittingMode( FittingMode::DEFAULT ),
140   mSamplingMode( SamplingMode::DEFAULT ),
141   mNativeFragmentShaderCode( ),
142   mNativeImageFlag( false )
143 {
144 }
145
146 ImageRenderer::~ImageRenderer()
147 {
148 }
149
150 void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
151 {
152   std::string oldImageUrl = mImageUrl;
153
154   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
155   if( imageURLValue )
156   {
157     imageURLValue->Get( mImageUrl );
158     if( !mImageUrl.empty() )
159     {
160       mImage.Reset();
161     }
162
163     Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
164     if( fittingValue )
165     {
166       std::string fitting;
167       fittingValue->Get( fitting );
168
169       mFittingMode = FittingMode::DEFAULT;
170       if( fitting == SHRINK_TO_FIT )
171       {
172         mFittingMode = FittingMode::SHRINK_TO_FIT;
173       }
174       else if( fitting == SCALE_TO_FILL )
175       {
176         mFittingMode = FittingMode::SCALE_TO_FILL;
177       }
178       else if( fitting == FIT_WIDTH )
179       {
180         mFittingMode = FittingMode::FIT_WIDTH;
181       }
182       else if( fitting == FIT_HEIGHT )
183       {
184         mFittingMode = FittingMode::FIT_HEIGHT;
185       }
186       else if( fitting == DEFAULT )
187       {
188         mFittingMode = FittingMode::DEFAULT;
189       }
190       else
191       {
192         DALI_ASSERT_ALWAYS("Unknown fitting mode");
193       }
194     }
195
196     Property::Value* samplingValue = propertyMap.Find( IMAGE_SAMPLING_MODE );
197     if( samplingValue )
198     {
199       std::string sampling;
200       samplingValue->Get( sampling );
201
202       mSamplingMode = SamplingMode::DEFAULT;
203       if( sampling == BOX )
204       {
205         mSamplingMode = SamplingMode::BOX;
206       }
207       else if( sampling == NEAREST )
208       {
209         mSamplingMode = SamplingMode::NEAREST;
210       }
211       else if( sampling == LINEAR )
212       {
213         mSamplingMode = SamplingMode::LINEAR;
214       }
215       else if( sampling == BOX_THEN_NEAREST )
216       {
217         mSamplingMode = SamplingMode::BOX_THEN_NEAREST;
218       }
219       else if( sampling == BOX_THEN_LINEAR )
220       {
221         mSamplingMode = SamplingMode::BOX_THEN_LINEAR;
222       }
223       else if( sampling == NO_FILTER )
224       {
225         mSamplingMode = SamplingMode::NO_FILTER;
226       }
227       else if( sampling == DONT_CARE )
228       {
229         mSamplingMode = SamplingMode::DONT_CARE;
230       }
231       else if( sampling == DEFAULT )
232       {
233         mSamplingMode = SamplingMode::DEFAULT;
234       }
235       else
236       {
237         DALI_ASSERT_ALWAYS("Unknown sampling mode");
238       }
239     }
240
241     int desiredWidth = 0;
242     Property::Value* desiredWidthValue = propertyMap.Find( IMAGE_DESIRED_WIDTH );
243     if( desiredWidthValue )
244     {
245       desiredWidthValue->Get( desiredWidth );
246     }
247
248     int desiredHeight = 0;
249     Property::Value* desiredHeightValue = propertyMap.Find( IMAGE_DESIRED_HEIGHT );
250     if( desiredHeightValue )
251     {
252       desiredHeightValue->Get( desiredHeight );
253     }
254
255     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
256   }
257
258   // remove old renderer if exit
259   if( mImpl->mRenderer )
260   {
261     if( actor ) //remove old renderer from actor
262     {
263       actor.RemoveRenderer( mImpl->mRenderer );
264     }
265     if( !oldImageUrl.empty() ) //clean old renderer from cache
266     {
267       CleanCache( oldImageUrl );
268     }
269   }
270
271   NativeImage nativeImage = NativeImage::DownCast( mImage );
272
273   if( nativeImage )
274   {
275     SetNativeFragmentShaderCode( nativeImage );
276   }
277
278   // if actor is on stage, create new renderer and apply to actor
279   if( actor && actor.OnStage() )
280   {
281     SetOnStage( actor );
282   }
283 }
284
285 void ImageRenderer::SetSize( const Vector2& size )
286 {
287   ControlRenderer::SetSize( size );
288 }
289
290 void ImageRenderer::GetNaturalSize( Vector2& naturalSize ) const
291 {
292   if(mImage)
293   {
294     naturalSize.x = mImage.GetWidth();
295     naturalSize.y = mImage.GetHeight();
296     return;
297   }
298   else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
299   {
300     naturalSize.x = mDesiredSize.GetWidth();
301     naturalSize.y = mDesiredSize.GetHeight();
302     return;
303   }
304   else if( !mImageUrl.empty() )
305   {
306     ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
307     naturalSize.x = dimentions.GetWidth();
308     naturalSize.y = dimentions.GetHeight();
309     return;
310   }
311
312   naturalSize = Vector2::ZERO;
313 }
314
315 void ImageRenderer::SetClipRect( const Rect<int>& clipRect )
316 {
317   ControlRenderer::SetClipRect( clipRect );
318 }
319
320 void ImageRenderer::SetOffset( const Vector2& offset )
321 {
322 }
323
324 Renderer ImageRenderer::CreateRenderer() const
325 {
326   Geometry geometry;
327   Shader shader;
328
329   // If mImage is nativeImage with custom sampler or prefix, mNativeFragmentShaderCode will be applied.
330   // Renderer can't be shared between NativeImage and other image types.
331   if( !mNativeFragmentShaderCode.empty() )
332   {
333     return CreateNativeImageRenderer();
334   }
335
336   if( !mImpl->mCustomShader )
337   {
338     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
339
340     shader = GetImageShader(mFactoryCache);
341   }
342   else
343   {
344     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
345     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
346     {
347       shader = GetImageShader(mFactoryCache);
348     }
349     else
350     {
351       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
352                              mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
353                              mImpl->mCustomShader->mHints );
354       if( mImpl->mCustomShader->mVertexShader.empty() )
355       {
356         shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
357         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
358       }
359     }
360   }
361
362   Material material = Material::New( shader );
363   return Renderer::New( geometry, material );
364 }
365
366 Renderer ImageRenderer::CreateNativeImageRenderer() const
367 {
368   Geometry geometry;
369   Shader shader;
370
371   if( !mImpl->mCustomShader )
372   {
373     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
374
375     shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
376     shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
377     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
378   }
379   else
380   {
381     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
382     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
383     {
384       shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
385     }
386     else
387     {
388       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
389                              mNativeFragmentShaderCode,
390                              mImpl->mCustomShader->mHints );
391       if( mImpl->mCustomShader->mVertexShader.empty() )
392       {
393         shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
394         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
395       }
396     }
397   }
398
399   Material material = Material::New( shader );
400   return Renderer::New( geometry, material );
401 }
402
403 void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
404 {
405   if( imageUrl.empty() )
406   {
407     return;
408   }
409
410   mImageUrl = imageUrl;
411   mImpl->mRenderer.Reset();
412
413   if( !mImpl->mCustomShader &&
414       ( strncasecmp( imageUrl.c_str(), HTTP_URL,  sizeof(HTTP_URL)  -1 ) != 0 ) && // ignore remote images
415       ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) )
416   {
417     mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
418     if( !mImpl->mRenderer )
419     {
420       Vector4 atlasRect;
421       Material material = mAtlasManager.Add(atlasRect, imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
422       if( material )
423       {
424         Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
425         mImpl->mRenderer = Renderer::New( geometry, material );
426         mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
427       }
428       else // big image, atlasing is not applied
429       {
430         mImpl->mRenderer = CreateRenderer();
431
432         ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
433         image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
434         Material material = mImpl->mRenderer.GetMaterial();
435         material.AddTexture( image, TEXTURE_UNIFORM_NAME );
436       }
437
438       mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
439     }
440
441     mImpl->mFlags |= Impl::IS_FROM_CACHE;
442   }
443   else
444   {
445     // for custom shader or remote image, renderer is not cached and atlas is not applied
446
447     mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
448     mImpl->mRenderer = CreateRenderer();
449     ResourceImage resourceImage = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
450     resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
451     ApplyImageToSampler( resourceImage );
452   }
453 }
454
455 void ImageRenderer::InitializeRenderer( const Image& image )
456 {
457   mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
458
459   mImpl->mRenderer = CreateRenderer();
460
461   if( image )
462   {
463     ApplyImageToSampler( image );
464   }
465 }
466
467
468 void ImageRenderer::DoSetOnStage( Actor& actor )
469 {
470   if( !mImageUrl.empty() )
471   {
472     InitializeRenderer( mImageUrl );
473   }
474   else
475   {
476     InitializeRenderer( mImage );
477   }
478
479 }
480
481 void ImageRenderer::DoSetOffStage( Actor& actor )
482 {
483   //If we own the image then make sure we release it when we go off stage
484   if( !mImageUrl.empty() )
485   {
486     actor.RemoveRenderer( mImpl->mRenderer );
487     CleanCache(mImageUrl);
488     mImage.Reset();
489   }
490   else
491   {
492     actor.RemoveRenderer( mImpl->mRenderer );
493     mImpl->mRenderer.Reset();
494   }
495 }
496
497 void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
498 {
499   map.Clear();
500   map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
501   if( !mImageUrl.empty() )
502   {
503     map.Insert( IMAGE_URL_NAME, mImageUrl );
504     map.Insert( IMAGE_DESIRED_WIDTH, mDesiredSize.GetWidth() );
505     map.Insert( IMAGE_DESIRED_HEIGHT, mDesiredSize.GetHeight() );
506   }
507   else if( mImage )
508   {
509     map.Insert( IMAGE_DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
510     map.Insert( IMAGE_DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
511
512     ResourceImage resourceImage = ResourceImage::DownCast(mImage);
513     if( resourceImage )
514     {
515       map.Insert( IMAGE_URL_NAME, resourceImage.GetUrl() );
516     }
517   }
518
519   switch( mFittingMode )
520   {
521     case Dali::FittingMode::FIT_HEIGHT:
522     {
523       map.Insert( IMAGE_FITTING_MODE, FIT_HEIGHT );
524       break;
525     }
526     case Dali::FittingMode::FIT_WIDTH:
527     {
528       map.Insert( IMAGE_FITTING_MODE, FIT_WIDTH );
529       break;
530     }
531     case Dali::FittingMode::SCALE_TO_FILL:
532     {
533       map.Insert( IMAGE_FITTING_MODE, SCALE_TO_FILL );
534       break;
535     }
536     case Dali::FittingMode::SHRINK_TO_FIT:
537     {
538       map.Insert( IMAGE_FITTING_MODE, SHRINK_TO_FIT );
539       break;
540     }
541     default:
542     {
543       map.Insert( IMAGE_FITTING_MODE, DEFAULT );
544       break;
545     }
546   }
547
548   switch( mSamplingMode )
549   {
550     case Dali::SamplingMode::BOX:
551     {
552       map.Insert( IMAGE_SAMPLING_MODE, BOX );
553       break;
554     }
555     case Dali::SamplingMode::NEAREST:
556     {
557       map.Insert( IMAGE_SAMPLING_MODE, NEAREST );
558       break;
559     }
560     case Dali::SamplingMode::LINEAR:
561     {
562       map.Insert( IMAGE_SAMPLING_MODE, LINEAR );
563       break;
564     }
565     case Dali::SamplingMode::BOX_THEN_LINEAR:
566     {
567       map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_LINEAR );
568       break;
569     }
570     case Dali::SamplingMode::BOX_THEN_NEAREST:
571     {
572       map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_NEAREST );
573       break;
574     }
575     case Dali::SamplingMode::NO_FILTER:
576     {
577       map.Insert( IMAGE_SAMPLING_MODE, NO_FILTER );
578       break;
579     }
580     case Dali::SamplingMode::DONT_CARE:
581     {
582       map.Insert( IMAGE_SAMPLING_MODE, DONT_CARE );
583       break;
584     }
585     default:
586     {
587       map.Insert( IMAGE_SAMPLING_MODE, DEFAULT );
588       break;
589     }
590   }
591 }
592
593 Shader ImageRenderer::GetImageShader( RendererFactoryCache& factoryCache )
594 {
595   Shader shader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
596   if( !shader )
597   {
598     shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
599     factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
600     shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
601     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
602   }
603   return shader;
604 }
605
606 void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
607 {
608   if( mImageUrl != imageUrl )
609   {
610     std::string oldImageUrl = mImageUrl;
611     mImageUrl = imageUrl;
612     mDesiredSize = size;
613     mFittingMode = fittingMode;
614     mSamplingMode = samplingMode;
615     mImage.Reset();
616
617     if( mImpl->mRenderer )
618     {
619       if( GetIsFromCache() ) // if renderer is from cache, remove the old one
620       {
621         //remove old renderer
622         if( actor )
623         {
624           actor.RemoveRenderer( mImpl->mRenderer );
625         }
626
627         //clean the cache
628         if( !oldImageUrl.empty() )
629         {
630           CleanCache(oldImageUrl);
631         }
632
633         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
634         {
635           SetOnStage(actor);
636         }
637       }
638       else // if renderer is not from cache, reuse the same renderer and only change the texture
639       {
640         ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
641         image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
642         ApplyImageToSampler( image );
643       }
644     }
645   }
646 }
647
648 void ImageRenderer::SetImage( Actor& actor, const Image& image )
649 {
650   if( mImage != image )
651   {
652     NativeImage newNativeImage = NativeImage::DownCast( image );
653     bool newRendererFlag = true;
654
655     if( newNativeImage && !mNativeImageFlag )
656     {
657       SetNativeFragmentShaderCode( newNativeImage );
658     }
659
660     if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) )
661     {
662       newRendererFlag = false;
663     }
664
665     if( newNativeImage )
666     {
667       mNativeImageFlag = true;
668     }
669     else
670     {
671       mNativeFragmentShaderCode.clear();
672       mNativeImageFlag = false;
673     }
674
675     mImage = image;
676
677     if( mImpl->mRenderer )
678     {
679       // if renderer is from cache, remove the old one, and create new renderer
680       if( GetIsFromCache() )
681       {
682         //remove old renderer
683         if( actor )
684         {
685           actor.RemoveRenderer( mImpl->mRenderer );
686         }
687
688         //clean the cache
689         if( !mImageUrl.empty() )
690         {
691           CleanCache(mImageUrl);
692         }
693         mImageUrl.clear();
694
695         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
696         {
697           SetOnStage(actor);
698         }
699       }
700       // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer
701       else if( newRendererFlag )
702       {
703         //remove old renderer
704         if( actor )
705         {
706           actor.RemoveRenderer( mImpl->mRenderer );
707         }
708
709         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
710         {
711           SetOnStage(actor);
712         }
713       }
714       else // if renderer is not from cache, reuse the same renderer and only change the texture
715       {
716         ApplyImageToSampler( image );
717       }
718     }
719
720     mImageUrl.clear();
721     mDesiredSize = ImageDimensions();
722     mFittingMode = FittingMode::DEFAULT;
723     mSamplingMode = SamplingMode::DEFAULT;
724   }
725 }
726
727 void ImageRenderer::ApplyImageToSampler( const Image& image )
728 {
729   if( image )
730   {
731     Material material = mImpl->mRenderer.GetMaterial();
732     if( material )
733     {
734       int index = material.GetTextureIndex( TEXTURE_UNIFORM_NAME );
735       if( index != -1 )
736       {
737         material.SetTextureImage( index, image );
738         return;
739       }
740
741       material.AddTexture( image, TEXTURE_UNIFORM_NAME );
742     }
743   }
744 }
745
746 void ImageRenderer::OnImageLoaded( ResourceImage image )
747 {
748   if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
749   {
750     Image brokenImage = RendererFactory::GetBrokenRendererImage();
751     if( mImpl->mRenderer )
752     {
753       ApplyImageToSampler( brokenImage );
754     }
755   }
756 }
757
758 void ImageRenderer::CleanCache(const std::string& url)
759 {
760   Material material = mImpl->mRenderer.GetMaterial();
761
762   Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
763   Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
764   if( index != Property::INVALID_INDEX )
765   {
766     Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
767     atlasRectValue.Get( atlasRect );
768   }
769
770   mImpl->mRenderer.Reset();
771   if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
772   {
773     mAtlasManager.Remove( material, atlasRect );
774   }
775 }
776
777 void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage )
778 {
779   const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
780   const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
781
782   if( fragmentPreFix )
783   {
784     mNativeFragmentShaderCode = fragmentPreFix;
785     mNativeFragmentShaderCode += "\n";
786   }
787
788   if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
789   {
790     mNativeFragmentShaderCode += mImpl->mCustomShader->mFragmentShader;
791   }
792   else
793   {
794     mNativeFragmentShaderCode += FRAGMENT_SHADER;
795   }
796
797   if( customSamplerTypename )
798   {
799     mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
800   }
801
802 }
803
804 } // namespace Internal
805
806 } // namespace Toolkit
807
808 } // namespace Dali