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