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