Merge "(AutomatedTests) Ensure warnings are shown as errors" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / image-actor-impl.cpp
1 /*
2  * Copyright (c) 2014 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 <dali/internal/event/actors/image-actor-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/animation/constraints.h> // for EqualToConstraint
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/internal/event/animation/constraint-impl.h>
29 #include <dali/internal/event/common/property-helper.h>
30 #include <dali/internal/event/effects/shader-effect-impl.h>
31 #include <dali/internal/event/images/image-connector.h>
32 #include <dali/internal/event/images/nine-patch-image-impl.h>
33
34 namespace Dali
35 {
36
37 namespace Internal
38 {
39
40 namespace
41 {
42
43 // Properties
44
45 //              Name           Type   writable animatable constraint-input  enum for index-checking
46 DALI_PROPERTY_TABLE_BEGIN
47 DALI_PROPERTY( "pixelArea",    RECTANGLE, true,    false,   true,    Dali::ImageActor::Property::PIXEL_AREA )
48 DALI_PROPERTY( "style",        STRING,    true,    false,   true,    Dali::ImageActor::Property::STYLE      )
49 DALI_PROPERTY( "border",       VECTOR4,   true,    false,   true,    Dali::ImageActor::Property::BORDER     )
50 DALI_PROPERTY( "image",        MAP,       true,    false,   false,   Dali::ImageActor::Property::IMAGE      )
51 DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX )
52
53 BaseHandle Create()
54 {
55   return Dali::ImageActor::New();
56 }
57
58 TypeRegistration mType( typeid( Dali::ImageActor ), typeid( Dali::Actor ), Create );
59
60 struct GridVertex
61 {
62   Vector3 mPosition;
63   Vector2 mTextureCoord;
64 };
65
66 GeometryPtr CreateQuadGeometry( const Vector2& size, unsigned int imageWidth, unsigned int imageHeight, const Dali::ImageActor::PixelArea& pixelArea )
67 {
68   const float halfWidth = size.width * 0.5f;
69   const float halfHeight = size.height * 0.5f;
70   GridVertex quadVertexData[4] =
71   {
72       { Vector3( -halfWidth, -halfHeight, 0.f ), Vector2( ( pixelArea.x                   ) / (float)imageWidth, ( pixelArea.y                    ) / (float)imageHeight ) },
73       { Vector3( -halfWidth,  halfHeight, 0.f ), Vector2( ( pixelArea.x                   ) / (float)imageWidth, ( pixelArea.y + pixelArea.height ) / (float)imageHeight ) },
74       { Vector3(  halfWidth, -halfHeight, 0.f ), Vector2( ( pixelArea.x + pixelArea.width ) / (float)imageWidth, ( pixelArea.y                    ) / (float)imageHeight ) },
75       { Vector3(  halfWidth,  halfHeight, 0.f ), Vector2( ( pixelArea.x + pixelArea.width ) / (float)imageWidth, ( pixelArea.y + pixelArea.height ) / (float)imageHeight ) }
76   };
77
78   Property::Map quadVertexFormat;
79   quadVertexFormat["aPosition"] = Property::VECTOR3;
80   quadVertexFormat["aTexCoord"] = Property::VECTOR2;
81   PropertyBufferPtr quadVertices = PropertyBuffer::New();
82   quadVertices->SetFormat( quadVertexFormat );
83   quadVertices->SetSize( 4 );
84   quadVertices->SetData(quadVertexData);
85
86   // Create the geometry object
87   GeometryPtr geometry = Geometry::New();
88   geometry->AddVertexBuffer( *quadVertices );
89   geometry->SetGeometryType( Dali::Geometry::TRIANGLE_STRIP );
90
91   return geometry;
92 }
93
94 GeometryPtr CreateGridGeometry( const Vector2& size, unsigned int gridWidth, unsigned int gridHeight, unsigned int imageWidth, unsigned int imageHeight, const Dali::ImageActor::PixelArea& pixelArea )
95 {
96   // Create vertices
97   std::vector< GridVertex > vertices;
98   vertices.reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
99
100   for( unsigned int y = 0u; y < gridHeight + 1; ++y )
101   {
102     float yPos = (float)y / gridHeight;
103     for( unsigned int x = 0u; x < gridWidth + 1; ++x )
104     {
105       float xPos = (float)x / gridWidth;
106       GridVertex vertex = {
107                             Vector3( size.width * ( xPos - 0.5f ), size.height * ( yPos - 0.5f ), 0.0f ),
108                             Vector2( ( pixelArea.x + pixelArea.width  * xPos ) / (float)imageWidth,
109                                      ( pixelArea.y + pixelArea.height * yPos ) / (float)imageHeight )
110                           };
111       vertices.push_back( vertex );
112     }
113   }
114
115   // Create indices
116   Vector< unsigned int > indices;
117   indices.Reserve( ( gridWidth + 2 ) * gridHeight * 2 - 2);
118
119   for( unsigned int row = 0u; row < gridHeight; ++row )
120   {
121     unsigned int rowStartIndex = row*(gridWidth+1u);
122     unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
123
124     if( row != 0u ) // degenerate index on non-first row
125     {
126       indices.PushBack( rowStartIndex );
127     }
128
129     for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
130     {
131       indices.PushBack( rowStartIndex + column);
132       indices.PushBack( nextRowStartIndex + column);
133     }
134
135     if( row != gridHeight-1u ) // degenerate index on non-last row
136     {
137       indices.PushBack( nextRowStartIndex + gridWidth );
138     }
139   }
140
141
142   Property::Map vertexFormat;
143   vertexFormat[ "aPosition" ] = Property::VECTOR3;
144   vertexFormat[ "aTexCoord" ] = Property::VECTOR2;
145   PropertyBufferPtr vertexPropertyBuffer = PropertyBuffer::New();
146   vertexPropertyBuffer->SetFormat( vertexFormat );
147   vertexPropertyBuffer->SetSize( vertices.size() );
148   if( vertices.size() > 0 )
149   {
150     vertexPropertyBuffer->SetData( &vertices[ 0 ] );
151   }
152
153   Property::Map indexFormat;
154   indexFormat[ "indices" ] = Property::INTEGER;
155   PropertyBufferPtr indexPropertyBuffer = PropertyBuffer::New();
156   indexPropertyBuffer->SetFormat( indexFormat );
157   indexPropertyBuffer->SetSize( indices.Size() );
158   if( indices.Size() > 0 )
159   {
160     indexPropertyBuffer->SetData( &indices[ 0 ] );
161   }
162
163   // Create the geometry object
164   GeometryPtr geometry = Geometry::New();
165   geometry->AddVertexBuffer( *vertexPropertyBuffer );
166   geometry->SetIndexBuffer( *indexPropertyBuffer );
167   geometry->SetGeometryType( Dali::Geometry::TRIANGLE_STRIP );
168
169   return geometry;
170
171 }
172
173 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
174   attribute mediump vec3 aPosition;\n
175   attribute mediump vec2 aTexCoord;\n
176   varying mediump vec2 vTexCoord;\n
177   uniform mediump mat4 uMvpMatrix;\n
178   uniform mediump vec3 uSize;\n
179   uniform mediump vec4 uTextureRect;\n
180   \n
181   void main()\n
182   {\n
183     mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n
184     vertexPosition = uMvpMatrix * vertexPosition;\n
185     \n
186     vTexCoord = aTexCoord;\n
187     gl_Position = vertexPosition;\n
188   }\n
189 );
190
191 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
192   varying mediump vec2 vTexCoord;\n
193   uniform sampler2D sTexture;\n
194   uniform lowp vec4 uColor;\n
195   \n
196   void main()\n
197   {\n
198     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
199   }\n
200 );
201
202 const size_t INVALID_TEXTURE_ID = (size_t)-1;
203 const int INVALID_RENDERER_ID = -1;
204 const unsigned int MAXIMUM_GRID_SIZE = 2048;
205 }
206
207 ImageActorPtr ImageActor::New()
208 {
209   ImageActorPtr actor( new ImageActor );
210
211   // Second-phase construction of base class
212   actor->Initialize();
213
214   //Create the renderer
215   actor->mRenderer = Renderer::New();
216
217   GeometryPtr quad = CreateQuadGeometry( Vector2::ONE, 1, 1, PixelArea() );
218   actor->mRenderer->SetGeometry( *quad );
219
220   ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
221   MaterialPtr material = Material::New();
222   material->SetShader( *shader );
223   actor->mRenderer->SetMaterial( *material );
224
225   return actor;
226 }
227
228 void ImageActor::OnInitialize()
229 {
230   // TODO: Remove this, at the moment its needed for size negotiation to work
231   SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
232 }
233
234 void ImageActor::SetImage( ImagePtr& image )
235 {
236   if( !image )
237   {
238     if( mRendererIndex != INVALID_RENDERER_ID )
239     {
240       RemoveRenderer( mRendererIndex );
241       mRendererIndex = INVALID_RENDERER_ID;
242     }
243   }
244   else
245   {
246     SamplerPtr sampler = Sampler::New();
247     sampler->SetFilterMode( mMinFilter, mMagFilter );
248
249     mTextureIndex = mRenderer->GetMaterial()->AddTexture( image, "sTexture", sampler );
250
251     if( mRendererIndex == INVALID_RENDERER_ID )
252     {
253       mRendererIndex = AddRenderer( *mRenderer );
254     }
255
256     if( !mIsPixelAreaSet )
257     {
258       mPixelArea = PixelArea( 0, 0, image->GetWidth(), image->GetHeight() );
259     }
260
261     RelayoutRequest();
262   }
263 }
264
265 ImagePtr ImageActor::GetImage() const
266 {
267   return mRenderer->GetMaterial()->GetTexture( mTextureIndex );
268 }
269
270 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
271 {
272   mPixelArea = pixelArea;
273   mIsPixelAreaSet = true;
274
275   RelayoutRequest();
276 }
277
278 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
279 {
280   return mPixelArea;
281 }
282
283 bool ImageActor::IsPixelAreaSet() const
284 {
285   return mIsPixelAreaSet;
286 }
287
288 void ImageActor::ClearPixelArea()
289 {
290   mIsPixelAreaSet = false;
291
292   int imageWidth = 0;
293   int imageHeight = 0;
294   ImagePtr image = GetImage();
295   if( image )
296   {
297     imageWidth = image->GetWidth();
298     imageHeight = image->GetHeight();
299   }
300
301   mPixelArea = PixelArea( 0, 0, imageWidth, imageHeight );
302
303   RelayoutRequest();
304 }
305
306 ImageActor::ImageActor()
307 : Actor( Actor::BASIC ),
308   mRendererIndex( INVALID_RENDERER_ID ),
309   mTextureIndex( INVALID_TEXTURE_ID ),
310   mEffectTextureIndex( INVALID_TEXTURE_ID ),
311   mMinFilter( FilterMode::DEFAULT ),
312   mMagFilter( FilterMode::DEFAULT ),
313   mIsPixelAreaSet( false )
314 {
315 }
316
317 ImageActor::~ImageActor()
318 {
319 }
320
321 Vector3 ImageActor::GetNaturalSize() const
322 {
323   Vector2 naturalSize( CalculateNaturalSize() );
324   return Vector3( naturalSize.width, naturalSize.height, 0.f );
325 }
326
327 Vector2 ImageActor::CalculateNaturalSize() const
328 {
329   // if no image then natural size is 0
330   Vector2 size( 0.0f, 0.0f );
331
332   ImagePtr image = GetImage();
333   if( image )
334   {
335     if( IsPixelAreaSet() )
336     {
337       PixelArea area(GetPixelArea());
338       size.width = area.width;
339       size.height = area.height;
340     }
341     else
342     {
343       size = image->GetNaturalSize();
344     }
345   }
346
347   return size;
348 }
349
350 void ImageActor::OnRelayout( const Vector2& size, RelayoutContainer& container )
351 {
352   unsigned int gridWidth = 1;
353   unsigned int gridHeight = 1;
354   if( mShaderEffect )
355   {
356     Vector2 gridSize = mShaderEffect->GetGridSize( size );
357
358     //limit the grid size
359     gridWidth = std::min( MAXIMUM_GRID_SIZE, static_cast<unsigned int>(gridSize.width) );
360     gridHeight = std::min( MAXIMUM_GRID_SIZE, static_cast<unsigned int>(gridSize.height) );
361   }
362
363   unsigned int imageWidth = 1u;
364   unsigned int imageHeight = 1u;
365   ImagePtr image = GetImage();
366   if( image )
367   {
368     imageWidth = image->GetWidth();
369     imageHeight = image->GetHeight();
370   }
371
372   GeometryPtr geometry = gridWidth <= 1 && gridHeight <= 1 ?
373                          CreateQuadGeometry( size, imageWidth, imageHeight, mPixelArea ) :
374                          CreateGridGeometry( size, gridWidth, gridHeight, imageWidth, imageHeight, mPixelArea );
375
376   mRenderer->SetGeometry( *geometry );
377
378   Vector4 textureRect( 0.f, 0.f, 1.f, 1.f );
379   if( mIsPixelAreaSet && image )
380   {
381     const float uScale = 1.0f / float(imageWidth);
382     const float vScale = 1.0f / float(imageHeight);
383     const float x = uScale * float(mPixelArea.x);
384     const float y = vScale * float(mPixelArea.y);
385     const float width  = uScale * float(mPixelArea.width);
386     const float height = vScale * float(mPixelArea.height);
387
388     // bottom left
389     textureRect.x = x;
390     textureRect.y = y;
391
392     // top right
393     textureRect.z = x + width;
394     textureRect.w = y + height;
395   }
396
397   Material* material = mRenderer->GetMaterial();
398   material->RegisterProperty( "sTextureRect", textureRect );
399 }
400
401 unsigned int ImageActor::GetDefaultPropertyCount() const
402 {
403   return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
404 }
405
406 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
407 {
408   Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
409
410   indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
411
412   int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
413   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
414   {
415     indices.PushBack( index );
416   }
417 }
418
419 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
420 {
421   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
422   {
423     return Actor::IsDefaultPropertyWritable(index);
424   }
425
426   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
427   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
428   {
429     return DEFAULT_PROPERTY_DETAILS[ index ].writable;
430   }
431
432   return false;
433 }
434
435 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
436 {
437   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
438   {
439     return Actor::IsDefaultPropertyAnimatable( index );
440   }
441
442   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
443   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
444   {
445     return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
446   }
447
448   return false;
449 }
450
451 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
452 {
453   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
454   {
455     return Actor::IsDefaultPropertyAConstraintInput( index );
456   }
457
458   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
459   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
460   {
461     return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
462   }
463
464   return false;
465 }
466
467 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
468 {
469   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
470   {
471     return Actor::GetDefaultPropertyType( index );
472   }
473
474   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
475   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
476   {
477     return DEFAULT_PROPERTY_DETAILS[index].type;
478   }
479
480   // index out-of-bounds
481   return Property::NONE;
482 }
483
484 const char* ImageActor::GetDefaultPropertyName( Property::Index index ) const
485 {
486   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
487   {
488     return Actor::GetDefaultPropertyName(index);
489   }
490
491   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
492   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
493   {
494     return DEFAULT_PROPERTY_DETAILS[index].name;
495   }
496
497   // index out-of-bounds
498   return NULL;
499 }
500
501 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
502 {
503   Property::Index index = Property::INVALID_INDEX;
504
505   // Look for name in default properties
506   for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
507   {
508     const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
509     if( 0 == strcmp( name.c_str(), property->name ) ) // Don't want to convert rhs to string
510     {
511       index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
512       break;
513     }
514   }
515
516   // If not found, check in base class
517   if( Property::INVALID_INDEX == index )
518   {
519     index = Actor::GetDefaultPropertyIndex( name );
520   }
521   return index;
522 }
523
524 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
525 {
526   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
527   {
528     Actor::SetDefaultProperty( index, propertyValue );
529   }
530   else
531   {
532     switch(index)
533     {
534       case Dali::ImageActor::Property::PIXEL_AREA:
535       {
536         SetPixelArea(propertyValue.Get<Rect<int> >());
537         break;
538       }
539       case Dali::ImageActor::Property::STYLE:
540       {
541         //not supported
542         break;
543       }
544       case Dali::ImageActor::Property::BORDER:
545       {
546         //not supported
547         break;
548       }
549       case Dali::ImageActor::Property::IMAGE:
550       {
551         Dali::Image img = Scripting::NewImage( propertyValue );
552         if(img)
553         {
554           ImagePtr image( &GetImplementation(img) );
555           SetImage( image );
556         }
557         else
558         {
559           DALI_LOG_WARNING("Cannot create image from property value\n");
560         }
561         break;
562       }
563       default:
564       {
565         DALI_LOG_WARNING("Unknown property (%d)\n", index);
566         break;
567       }
568     } // switch(index)
569
570   } // else
571 }
572
573 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
574 {
575   Property::Value ret;
576   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
577   {
578     ret = Actor::GetDefaultProperty( index );
579   }
580   else
581   {
582     switch( index )
583     {
584       case Dali::ImageActor::Property::PIXEL_AREA:
585       {
586         Rect<int> r = GetPixelArea();
587         ret = r;
588         break;
589       }
590       case Dali::ImageActor::Property::STYLE:
591       {
592         //not supported
593         break;
594       }
595       case Dali::ImageActor::Property::BORDER:
596       {
597         //not supported
598         break;
599       }
600       case Dali::ImageActor::Property::IMAGE:
601       {
602         Property::Map map;
603         Scripting::CreatePropertyMap( Dali::Image( GetImage().Get() ), map );
604         ret = Property::Value( map );
605         break;
606       }
607       default:
608       {
609         DALI_LOG_WARNING( "Unknown property (%d)\n", index );
610         break;
611       }
612     } // switch(index)
613   }
614
615   return ret;
616 }
617
618 void ImageActor::SetSortModifier(float modifier)
619 {
620   mRenderer->SetDepthIndex( modifier );
621 }
622
623 float ImageActor::GetSortModifier() const
624 {
625   return mRenderer->GetDepthIndex();
626 }
627
628 void ImageActor::SetCullFace(CullFaceMode mode)
629 {
630   mRenderer->GetMaterial()->SetFaceCullingMode( static_cast< Dali::Material::FaceCullingMode >( mode ) );
631 }
632
633 CullFaceMode ImageActor::GetCullFace() const
634 {
635   return static_cast< CullFaceMode >( mRenderer->GetMaterial()->GetFaceCullingMode() );
636 }
637
638 void ImageActor::SetBlendMode( BlendingMode::Type mode )
639 {
640   mRenderer->GetMaterial()->SetBlendMode( mode );
641 }
642
643 BlendingMode::Type ImageActor::GetBlendMode() const
644 {
645   return mRenderer->GetMaterial()->GetBlendMode();
646 }
647
648 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgba,   BlendingFactor::Type destFactorRgba )
649 {
650   mRenderer->GetMaterial()->SetBlendFunc( srcFactorRgba, destFactorRgba, srcFactorRgba, destFactorRgba );
651 }
652
653 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgb,   BlendingFactor::Type destFactorRgb,
654                                BlendingFactor::Type srcFactorAlpha, BlendingFactor::Type destFactorAlpha )
655 {
656   mRenderer->GetMaterial()->SetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
657 }
658
659 void ImageActor::GetBlendFunc( BlendingFactor::Type& srcFactorRgb,   BlendingFactor::Type& destFactorRgb,
660                                BlendingFactor::Type& srcFactorAlpha, BlendingFactor::Type& destFactorAlpha ) const
661 {
662   mRenderer->GetMaterial()->GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
663 }
664
665 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgba )
666 {
667   mRenderer->GetMaterial()->SetBlendEquation( equationRgba, equationRgba );
668 }
669
670 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgb, BlendingEquation::Type equationAlpha )
671 {
672   mRenderer->GetMaterial()->SetBlendEquation( equationRgb, equationAlpha );
673 }
674
675 void ImageActor::GetBlendEquation( BlendingEquation::Type& equationRgb, BlendingEquation::Type& equationAlpha ) const
676 {
677   mRenderer->GetMaterial()->GetBlendEquation( equationRgb, equationAlpha );
678 }
679
680 void ImageActor::SetBlendColor( const Vector4& color )
681 {
682   mBlendColor = color;
683   mRenderer->GetMaterial()->SetBlendColor( mBlendColor );
684 }
685
686 const Vector4& ImageActor::GetBlendColor() const
687 {
688   return mBlendColor;
689 }
690
691 void ImageActor::SetFilterMode( FilterMode::Type minFilter, FilterMode::Type magFilter )
692 {
693   mMinFilter = minFilter;
694   mMagFilter = magFilter;
695
696   if( mTextureIndex != INVALID_TEXTURE_ID )
697   {
698     SamplerPtr sampler = Sampler::New();
699     sampler->SetFilterMode( minFilter, magFilter );
700
701     mRenderer->GetMaterial()->SetTextureSampler( mTextureIndex, sampler.Get() );
702   }
703 }
704
705 void ImageActor::GetFilterMode( FilterMode::Type& minFilter, FilterMode::Type& magFilter ) const
706 {
707   minFilter = mMinFilter;
708   magFilter = mMagFilter;
709 }
710
711 void ImageActor::SetShaderEffect( ShaderEffect& effect )
712 {
713   if( mShaderEffect )
714   {
715     mShaderEffect->Disconnect( this );
716   }
717
718   mShaderEffect = ShaderEffectPtr( &effect );
719   effect.Connect( this );
720
721   ShaderPtr shader = mShaderEffect->GetShader();
722   mRenderer->GetMaterial()->SetShader( *shader );
723
724   EffectImageUpdated();
725 }
726
727 ShaderEffectPtr ImageActor::GetShaderEffect() const
728 {
729   return mShaderEffect;
730 }
731
732 void ImageActor::RemoveShaderEffect()
733 {
734   //if we previously had a subdivided grid then we need to reset the geometry as well
735   if( mShaderEffect )
736   {
737     mShaderEffect->Disconnect( this );
738
739     if( mShaderEffect->GetGridSize( Vector2(INFINITY, INFINITY) ) != Vector2::ONE )
740     {
741       RelayoutRequest();
742     }
743   }
744
745   ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
746   mRenderer->GetMaterial()->SetShader( *shader );
747   mShaderEffect.Reset();
748 }
749
750 void ImageActor::EffectImageUpdated()
751 {
752   if( mShaderEffect )
753   {
754     Dali::Image effectImage = mShaderEffect->GetEffectImage();
755     if( effectImage )
756     {
757       Image& effectImageImpl = GetImplementation( effectImage );
758
759       if( mEffectTextureIndex == INVALID_TEXTURE_ID )
760       {
761         mEffectTextureIndex = mRenderer->GetMaterial()->AddTexture( &effectImageImpl, "sEffect", NULL );
762       }
763       else
764       {
765         mRenderer->GetMaterial()->SetTextureImage( mEffectTextureIndex, &effectImageImpl );
766       }
767     }
768     else
769     {
770       if( mEffectTextureIndex != INVALID_TEXTURE_ID )
771       {
772         mRenderer->GetMaterial()->RemoveTexture( mEffectTextureIndex );
773       }
774       mEffectTextureIndex = INVALID_TEXTURE_ID;
775     }
776
777     //ensure that the sEffectRect uniform is set
778     Shader* shader = mRenderer->GetMaterial()->GetShader();
779     Property::Index index = shader->GetPropertyIndex( "sEffectRect" );
780     if( index == Property::INVALID_INDEX )
781     {
782       shader->RegisterProperty( "sEffectRect", Vector4( 0.f, 0.f, 1.f, 1.f) );
783     }
784   }
785 }
786
787 } // namespace Internal
788
789 } // namespace Dali