NativeImageSource with tbm_surface for tizen 3.0 wayland
[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("imageRenderer");
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 // Set this uniform to 1.0 for conventional alpha blending; if pre-multiplied alpha blending, set this uniform to 0.0
79 const std::string ALPHA_BLENDING_UNIFORM_NAME = "uAlphaBlending";
80
81 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
82
83 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
84
85 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
86   attribute mediump vec2 aPosition;\n
87   uniform mediump mat4 uMvpMatrix;\n
88   uniform mediump vec3 uSize;\n
89   uniform mediump vec4 uAtlasRect;\n
90   uniform mediump vec4 pixelArea;
91   varying mediump vec2 vTexCoord;\n
92   \n
93   void main()\n
94   {\n
95     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
96     vertexPosition.xyz *= uSize;\n
97     vertexPosition = uMvpMatrix * vertexPosition;\n
98     \n
99     vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n
100     gl_Position = vertexPosition;\n
101   }\n
102 );
103
104 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
105   varying mediump vec2 vTexCoord;\n
106   uniform sampler2D sTexture;\n
107   uniform lowp vec4 uColor;\n
108   uniform lowp float uAlphaBlending; // Set to 1.0 for conventional alpha blending; if pre-multiplied alpha blending, set to 0.0
109   \n
110   void main()\n
111   {\n
112     gl_FragColor = texture2D( sTexture, vTexCoord ) * vec4( uColor.rgb*max( uAlphaBlending, uColor.a ), uColor.a );\n
113   }\n
114 );
115
116
117 Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices )
118 {
119   Property::Map vertexFormat;
120   vertexFormat[ "aPosition" ] = Property::VECTOR2;
121   PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat, vertices.Size() );
122   if( vertices.Size() > 0 )
123   {
124     vertexPropertyBuffer.SetData( &vertices[ 0 ] );
125   }
126
127   Property::Map indexFormat;
128   indexFormat[ "indices" ] = Property::INTEGER;
129   PropertyBuffer indexPropertyBuffer = PropertyBuffer::New( indexFormat, indices.Size() );
130   if( indices.Size() > 0 )
131   {
132     indexPropertyBuffer.SetData( &indices[ 0 ] );
133   }
134
135   // Create the geometry object
136   Geometry geometry = Geometry::New();
137   geometry.AddVertexBuffer( vertexPropertyBuffer );
138   geometry.SetIndexBuffer( indexPropertyBuffer );
139   geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
140
141   return geometry;
142 }
143
144 Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gridSize )
145 {
146   Geometry geometry;
147
148   if( gridSize == ImageDimensions( 1, 1 ) )
149   {
150     geometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
151     if( !geometry )
152     {
153       geometry =  factoryCache.CreateQuadGeometry();
154       factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
155     }
156   }
157   else
158   {
159     uint16_t gridWidth = gridSize.GetWidth();
160     uint16_t gridHeight = gridSize.GetHeight();
161
162     // Create vertices
163     Vector< Vector2 > vertices;
164     vertices.Reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
165
166     for( int y = 0; y < gridHeight + 1; ++y )
167     {
168       for( int x = 0; x < gridWidth + 1; ++x )
169       {
170         vertices.PushBack( Vector2( (float)x/gridWidth - 0.5f, (float)y/gridHeight  - 0.5f) );
171       }
172     }
173
174     // Create indices
175     Vector< unsigned int > indices;
176     indices.Reserve( (gridWidth+2)*gridHeight*2 - 2);
177
178     for( unsigned int row = 0u; row < gridHeight; ++row )
179     {
180       unsigned int rowStartIndex = row*(gridWidth+1u);
181       unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
182
183       if( row != 0u ) // degenerate index on non-first row
184       {
185         indices.PushBack( rowStartIndex );
186       }
187
188       for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
189       {
190         indices.PushBack( rowStartIndex + column);
191         indices.PushBack( nextRowStartIndex + column);
192       }
193
194       if( row != gridHeight-1u ) // degenerate index on non-last row
195       {
196         indices.PushBack( nextRowStartIndex + gridWidth );
197       }
198     }
199
200     return GenerateGeometry( vertices, indices );
201   }
202
203   return geometry;
204 }
205
206 } //unnamed namespace
207
208 ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
209 : ControlRenderer( factoryCache ),
210   mAtlasManager( atlasManager ),
211   mDesiredSize(),
212   mFittingMode( FittingMode::DEFAULT ),
213   mSamplingMode( SamplingMode::DEFAULT ),
214   mIsAlphaPreMultiplied( false ),
215   mNativeFragmentShaderCode( ),
216   mNativeImageFlag( false )
217 {
218 }
219
220 ImageRenderer::~ImageRenderer()
221 {
222 }
223
224 void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
225 {
226   std::string oldImageUrl = mImageUrl;
227
228   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
229   if( imageURLValue )
230   {
231     imageURLValue->Get( mImageUrl );
232     if( !mImageUrl.empty() )
233     {
234       mImage.Reset();
235     }
236
237     Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
238     if( fittingValue )
239     {
240       std::string fitting;
241       fittingValue->Get( fitting );
242
243       mFittingMode = FittingMode::DEFAULT;
244       if( fitting == SHRINK_TO_FIT )
245       {
246         mFittingMode = FittingMode::SHRINK_TO_FIT;
247       }
248       else if( fitting == SCALE_TO_FILL )
249       {
250         mFittingMode = FittingMode::SCALE_TO_FILL;
251       }
252       else if( fitting == FIT_WIDTH )
253       {
254         mFittingMode = FittingMode::FIT_WIDTH;
255       }
256       else if( fitting == FIT_HEIGHT )
257       {
258         mFittingMode = FittingMode::FIT_HEIGHT;
259       }
260       else if( fitting == DEFAULT )
261       {
262         mFittingMode = FittingMode::DEFAULT;
263       }
264       else
265       {
266         DALI_ASSERT_ALWAYS("Unknown fitting mode");
267       }
268     }
269
270     Property::Value* samplingValue = propertyMap.Find( IMAGE_SAMPLING_MODE );
271     if( samplingValue )
272     {
273       std::string sampling;
274       samplingValue->Get( sampling );
275
276       mSamplingMode = SamplingMode::DEFAULT;
277       if( sampling == BOX )
278       {
279         mSamplingMode = SamplingMode::BOX;
280       }
281       else if( sampling == NEAREST )
282       {
283         mSamplingMode = SamplingMode::NEAREST;
284       }
285       else if( sampling == LINEAR )
286       {
287         mSamplingMode = SamplingMode::LINEAR;
288       }
289       else if( sampling == BOX_THEN_NEAREST )
290       {
291         mSamplingMode = SamplingMode::BOX_THEN_NEAREST;
292       }
293       else if( sampling == BOX_THEN_LINEAR )
294       {
295         mSamplingMode = SamplingMode::BOX_THEN_LINEAR;
296       }
297       else if( sampling == NO_FILTER )
298       {
299         mSamplingMode = SamplingMode::NO_FILTER;
300       }
301       else if( sampling == DONT_CARE )
302       {
303         mSamplingMode = SamplingMode::DONT_CARE;
304       }
305       else if( sampling == DEFAULT )
306       {
307         mSamplingMode = SamplingMode::DEFAULT;
308       }
309       else
310       {
311         DALI_ASSERT_ALWAYS("Unknown sampling mode");
312       }
313     }
314
315     int desiredWidth = 0;
316     Property::Value* desiredWidthValue = propertyMap.Find( IMAGE_DESIRED_WIDTH );
317     if( desiredWidthValue )
318     {
319       desiredWidthValue->Get( desiredWidth );
320     }
321
322     int desiredHeight = 0;
323     Property::Value* desiredHeightValue = propertyMap.Find( IMAGE_DESIRED_HEIGHT );
324     if( desiredHeightValue )
325     {
326       desiredHeightValue->Get( desiredHeight );
327     }
328
329     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
330   }
331
332   // remove old renderer if exit
333   if( mImpl->mRenderer )
334   {
335     if( actor ) //remove old renderer from actor
336     {
337       actor.RemoveRenderer( mImpl->mRenderer );
338     }
339     if( !oldImageUrl.empty() ) //clean old renderer from cache
340     {
341       CleanCache( oldImageUrl );
342     }
343   }
344
345   NativeImage nativeImage = NativeImage::DownCast( mImage );
346
347   if( nativeImage )
348   {
349     SetNativeFragmentShaderCode( nativeImage );
350   }
351
352   // if actor is on stage, create new renderer and apply to actor
353   if( actor && actor.OnStage() )
354   {
355     SetOnStage( actor );
356   }
357 }
358
359 void ImageRenderer::SetSize( const Vector2& size )
360 {
361   ControlRenderer::SetSize( size );
362 }
363
364 void ImageRenderer::GetNaturalSize( Vector2& naturalSize ) const
365 {
366   if(mImage)
367   {
368     naturalSize.x = mImage.GetWidth();
369     naturalSize.y = mImage.GetHeight();
370     return;
371   }
372   else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
373   {
374     naturalSize.x = mDesiredSize.GetWidth();
375     naturalSize.y = mDesiredSize.GetHeight();
376     return;
377   }
378   else if( !mImageUrl.empty() )
379   {
380     ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
381     naturalSize.x = dimentions.GetWidth();
382     naturalSize.y = dimentions.GetHeight();
383     return;
384   }
385
386   naturalSize = Vector2::ZERO;
387 }
388
389 void ImageRenderer::SetClipRect( const Rect<int>& clipRect )
390 {
391   ControlRenderer::SetClipRect( clipRect );
392 }
393
394 void ImageRenderer::SetOffset( const Vector2& offset )
395 {
396 }
397
398 Renderer ImageRenderer::CreateRenderer() const
399 {
400   Geometry geometry;
401   Shader shader;
402
403   // If mImage is nativeImage with custom sampler or prefix, mNativeFragmentShaderCode will be applied.
404   // Renderer can't be shared between NativeImage and other image types.
405   if( !mNativeFragmentShaderCode.empty() )
406   {
407     return CreateNativeImageRenderer();
408   }
409
410   if( !mImpl->mCustomShader )
411   {
412     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
413
414     shader = GetImageShader(mFactoryCache);
415   }
416   else
417   {
418     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
419     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
420     {
421       shader = GetImageShader(mFactoryCache);
422     }
423     else
424     {
425       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
426                              mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
427                              mImpl->mCustomShader->mHints );
428       if( mImpl->mCustomShader->mVertexShader.empty() )
429       {
430         shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
431         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
432         shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f );
433       }
434     }
435   }
436
437   Material material = Material::New( shader );
438   return Renderer::New( geometry, material );
439 }
440
441 Renderer ImageRenderer::CreateNativeImageRenderer() const
442 {
443   Geometry geometry;
444   Shader shader;
445
446   if( !mImpl->mCustomShader )
447   {
448     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
449
450     shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
451     shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
452     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
453     shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f );
454   }
455   else
456   {
457     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
458     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
459     {
460       shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
461     }
462     else
463     {
464       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
465                              mNativeFragmentShaderCode,
466                              mImpl->mCustomShader->mHints );
467       if( mImpl->mCustomShader->mVertexShader.empty() )
468       {
469         shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
470         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
471         shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f );
472       }
473     }
474   }
475
476   Material material = Material::New( shader );
477   return Renderer::New( geometry, material );
478 }
479
480 void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
481 {
482   if( imageUrl.empty() )
483   {
484     return;
485   }
486
487   mImageUrl = imageUrl;
488   mImpl->mRenderer.Reset();
489
490   if( !mImpl->mCustomShader &&
491       ( strncasecmp( imageUrl.c_str(), HTTP_URL,  sizeof(HTTP_URL)  -1 ) != 0 ) && // ignore remote images
492       ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) )
493   {
494     mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
495     if( !mImpl->mRenderer )
496     {
497       Vector4 atlasRect;
498       Material material = mAtlasManager.Add(atlasRect, imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
499       if( material )
500       {
501         Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
502         mImpl->mRenderer = Renderer::New( geometry, material );
503         mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
504       }
505       else // big image, atlasing is not applied
506       {
507         mImpl->mRenderer = CreateRenderer();
508
509         ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
510         image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
511         Material material = mImpl->mRenderer.GetMaterial();
512         material.AddTexture( image, TEXTURE_UNIFORM_NAME );
513       }
514
515       mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
516     }
517
518     mImpl->mFlags |= Impl::IS_FROM_CACHE;
519   }
520   else
521   {
522     // for custom shader or remote image, renderer is not cached and atlas is not applied
523
524     mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
525     mImpl->mRenderer = CreateRenderer();
526     ResourceImage resourceImage = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
527     resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
528     ApplyImageToSampler( resourceImage );
529   }
530 }
531
532 void ImageRenderer::InitializeRenderer( const Image& image )
533 {
534   mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
535
536   mImpl->mRenderer = CreateRenderer();
537
538   if( image )
539   {
540     ApplyImageToSampler( image );
541   }
542 }
543
544
545 void ImageRenderer::DoSetOnStage( Actor& actor )
546 {
547   if( !mImageUrl.empty() )
548   {
549     InitializeRenderer( mImageUrl );
550   }
551   else
552   {
553     InitializeRenderer( mImage );
554   }
555
556   EnablePreMultipliedAlpha( mIsAlphaPreMultiplied );
557 }
558
559 void ImageRenderer::DoSetOffStage( Actor& actor )
560 {
561   //If we own the image then make sure we release it when we go off stage
562   if( !mImageUrl.empty() )
563   {
564     actor.RemoveRenderer( mImpl->mRenderer );
565     CleanCache(mImageUrl);
566
567     mImage.Reset();
568   }
569   else
570   {
571     actor.RemoveRenderer( mImpl->mRenderer );
572     mImpl->mRenderer.Reset();
573   }
574 }
575
576 void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
577 {
578   map.Clear();
579   map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
580   if( !mImageUrl.empty() )
581   {
582     map.Insert( IMAGE_URL_NAME, mImageUrl );
583     map.Insert( IMAGE_DESIRED_WIDTH, mDesiredSize.GetWidth() );
584     map.Insert( IMAGE_DESIRED_HEIGHT, mDesiredSize.GetHeight() );
585   }
586   else if( mImage )
587   {
588     map.Insert( IMAGE_DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
589     map.Insert( IMAGE_DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
590
591     ResourceImage resourceImage = ResourceImage::DownCast(mImage);
592     if( resourceImage )
593     {
594       map.Insert( IMAGE_URL_NAME, resourceImage.GetUrl() );
595     }
596   }
597
598   switch( mFittingMode )
599   {
600     case Dali::FittingMode::FIT_HEIGHT:
601     {
602       map.Insert( IMAGE_FITTING_MODE, FIT_HEIGHT );
603       break;
604     }
605     case Dali::FittingMode::FIT_WIDTH:
606     {
607       map.Insert( IMAGE_FITTING_MODE, FIT_WIDTH );
608       break;
609     }
610     case Dali::FittingMode::SCALE_TO_FILL:
611     {
612       map.Insert( IMAGE_FITTING_MODE, SCALE_TO_FILL );
613       break;
614     }
615     case Dali::FittingMode::SHRINK_TO_FIT:
616     {
617       map.Insert( IMAGE_FITTING_MODE, SHRINK_TO_FIT );
618       break;
619     }
620     default:
621     {
622       map.Insert( IMAGE_FITTING_MODE, DEFAULT );
623       break;
624     }
625   }
626
627   switch( mSamplingMode )
628   {
629     case Dali::SamplingMode::BOX:
630     {
631       map.Insert( IMAGE_SAMPLING_MODE, BOX );
632       break;
633     }
634     case Dali::SamplingMode::NEAREST:
635     {
636       map.Insert( IMAGE_SAMPLING_MODE, NEAREST );
637       break;
638     }
639     case Dali::SamplingMode::LINEAR:
640     {
641       map.Insert( IMAGE_SAMPLING_MODE, LINEAR );
642       break;
643     }
644     case Dali::SamplingMode::BOX_THEN_LINEAR:
645     {
646       map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_LINEAR );
647       break;
648     }
649     case Dali::SamplingMode::BOX_THEN_NEAREST:
650     {
651       map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_NEAREST );
652       break;
653     }
654     case Dali::SamplingMode::NO_FILTER:
655     {
656       map.Insert( IMAGE_SAMPLING_MODE, NO_FILTER );
657       break;
658     }
659     case Dali::SamplingMode::DONT_CARE:
660     {
661       map.Insert( IMAGE_SAMPLING_MODE, DONT_CARE );
662       break;
663     }
664     default:
665     {
666       map.Insert( IMAGE_SAMPLING_MODE, DEFAULT );
667       break;
668     }
669   }
670 }
671
672 Shader ImageRenderer::GetImageShader( RendererFactoryCache& factoryCache )
673 {
674   Shader shader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
675   if( !shader )
676   {
677     shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
678     factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
679     shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
680     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
681     shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f );
682   }
683   return shader;
684 }
685
686 void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
687 {
688   if( mImageUrl != imageUrl )
689   {
690     std::string oldImageUrl = mImageUrl;
691     mImageUrl = imageUrl;
692     mDesiredSize = size;
693     mFittingMode = fittingMode;
694     mSamplingMode = samplingMode;
695     mImage.Reset();
696
697     if( mImpl->mRenderer )
698     {
699       if( GetIsFromCache() ) // if renderer is from cache, remove the old one
700       {
701         //remove old renderer
702         if( actor )
703         {
704           actor.RemoveRenderer( mImpl->mRenderer );
705         }
706
707         //clean the cache
708         if( !oldImageUrl.empty() )
709         {
710           CleanCache(oldImageUrl);
711         }
712
713         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
714         {
715           SetOnStage(actor);
716         }
717       }
718       else // if renderer is not from cache, reuse the same renderer and only change the texture
719       {
720         ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
721         image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
722         ApplyImageToSampler( image );
723       }
724     }
725   }
726 }
727
728 void ImageRenderer::SetImage( Actor& actor, const Image& image )
729 {
730   if( mImage != image )
731   {
732     NativeImage newNativeImage = NativeImage::DownCast( image );
733     bool newRendererFlag = true;
734
735     if( newNativeImage && !mNativeImageFlag )
736     {
737       SetNativeFragmentShaderCode( newNativeImage );
738     }
739
740     if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) )
741     {
742       newRendererFlag = false;
743     }
744
745     if( newNativeImage )
746     {
747       mNativeImageFlag = true;
748     }
749     else
750     {
751       mNativeFragmentShaderCode.clear();
752       mNativeImageFlag = false;
753     }
754
755     mImage = image;
756
757     if( mImpl->mRenderer )
758     {
759       // if renderer is from cache, remove the old one, and create new renderer
760       if( GetIsFromCache() )
761       {
762         //remove old renderer
763         if( actor )
764         {
765           actor.RemoveRenderer( mImpl->mRenderer );
766         }
767
768         //clean the cache
769         if( !mImageUrl.empty() )
770         {
771           CleanCache(mImageUrl);
772         }
773         mImageUrl.clear();
774
775         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
776         {
777           SetOnStage(actor);
778         }
779       }
780       // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer
781       else if( newRendererFlag )
782       {
783         //remove old renderer
784         if( actor )
785         {
786           actor.RemoveRenderer( mImpl->mRenderer );
787         }
788
789         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
790         {
791           SetOnStage(actor);
792         }
793       }
794       else // if renderer is not from cache, reuse the same renderer and only change the texture
795       {
796         ApplyImageToSampler( image );
797       }
798     }
799
800     mImageUrl.clear();
801     mDesiredSize = ImageDimensions();
802     mFittingMode = FittingMode::DEFAULT;
803     mSamplingMode = SamplingMode::DEFAULT;
804   }
805 }
806
807 void ImageRenderer::EnablePreMultipliedAlpha( bool preMultipled )
808 {
809   mIsAlphaPreMultiplied = preMultipled;
810   if( mImpl->mRenderer )
811   {
812     Material material = mImpl->mRenderer.GetMaterial();
813
814     if( preMultipled )
815     {
816       material.SetBlendFunc( BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA,
817                              BlendingFactor::ONE, BlendingFactor::ONE );
818       if( !mImpl->mCustomShader || mImpl->mCustomShader->mVertexShader.empty())
819       {
820         material.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 0.f );
821       }
822     }
823     else
824     {
825       // using default blend func
826       material.SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
827                               BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
828
829       Property::Index index = material.GetPropertyIndex( ALPHA_BLENDING_UNIFORM_NAME );
830       if( index != Property::INVALID_INDEX ) // only set value when the property already exist on the Material
831       {
832         material.SetProperty( index, 1.f );
833       }
834     }
835   }
836 }
837
838 void ImageRenderer::ApplyImageToSampler( const Image& image )
839 {
840   if( image )
841   {
842     Material material = mImpl->mRenderer.GetMaterial();
843     if( material )
844     {
845       int index = material.GetTextureIndex( TEXTURE_UNIFORM_NAME );
846       if( index != -1 )
847       {
848         material.SetTextureImage( index, image );
849         return;
850       }
851
852       material.AddTexture( image, TEXTURE_UNIFORM_NAME );
853     }
854   }
855 }
856
857 void ImageRenderer::OnImageLoaded( ResourceImage image )
858 {
859   if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
860   {
861     Image brokenImage = RendererFactory::GetBrokenRendererImage();
862     if( mImpl->mRenderer )
863     {
864       ApplyImageToSampler( brokenImage );
865     }
866   }
867 }
868
869 void ImageRenderer::CleanCache(const std::string& url)
870 {
871   Material material = mImpl->mRenderer.GetMaterial();
872
873   Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
874   Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
875   if( index != Property::INVALID_INDEX )
876   {
877     Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
878     atlasRectValue.Get( atlasRect );
879   }
880
881   mImpl->mRenderer.Reset();
882   if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
883   {
884     mAtlasManager.Remove( material, atlasRect );
885   }
886 }
887
888 void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage )
889 {
890   const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
891   const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
892
893   if( fragmentPreFix )
894   {
895     mNativeFragmentShaderCode = fragmentPreFix;
896     mNativeFragmentShaderCode += "\n";
897   }
898
899   if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
900   {
901     mNativeFragmentShaderCode += mImpl->mCustomShader->mFragmentShader;
902   }
903   else
904   {
905     mNativeFragmentShaderCode += FRAGMENT_SHADER;
906   }
907
908   if( customSamplerTypename )
909   {
910     mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
911   }
912
913 }
914
915 } // namespace Internal
916
917 } // namespace Toolkit
918
919 } // namespace Dali