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