Merge changes I0cbfe8d4,I63b556cb 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, int imageWidth, 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, int imageWidth, 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
174 template< typename T>
175 ConstraintBase* CreateEqualConstraint(Object& target, Property::Index index, Internal::SourceContainer& sources )
176 {
177   typedef typename Dali::Internal::PropertyConstraintPtr< T >::Type PropertyConstraintPtrType;
178
179   CallbackBase* callback = new Dali::Constraint::Function< T >( EqualToConstraint() );
180   PropertyConstraintPtrType funcPtr( new Internal::PropertyConstraint< T >( reinterpret_cast< Dali::Constraint::Function< T >* >( callback ) ) );
181
182   return Internal::Constraint< T >::New( target, index, sources, funcPtr );
183 }
184
185 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
186   attribute mediump vec3 aPosition;\n
187   attribute mediump vec2 aTexCoord;\n
188   varying mediump vec2 vTexCoord;\n
189   uniform mediump mat4 uMvpMatrix;\n
190   uniform mediump vec3 uSize;\n
191   uniform mediump vec4 uTextureRect;\n
192   \n
193   void main()\n
194   {\n
195     mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n
196     vertexPosition = uMvpMatrix * vertexPosition;\n
197     \n
198     vTexCoord = aTexCoord;\n
199     gl_Position = vertexPosition;\n
200   }\n
201 );
202
203 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
204   varying mediump vec2 vTexCoord;\n
205   uniform sampler2D sTexture;\n
206   uniform lowp vec4 uColor;\n
207   \n
208   void main()\n
209   {\n
210     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
211   }\n
212 );
213
214 const size_t INVALID_TEXTURE_ID = (size_t)-1;
215 const int INVALID_RENDERER_ID = -1;
216 const unsigned int MAXIMUM_GRID_SIZE = 2048;
217 }
218
219 ImageActorPtr ImageActor::New()
220 {
221   ImageActorPtr actor( new ImageActor );
222
223   // Second-phase construction of base class
224   actor->Initialize();
225
226   //Create the renderer
227   actor->mRenderer = Renderer::New();
228
229   GeometryPtr quad = CreateQuadGeometry( Vector2::ONE, 1, 1, PixelArea() );
230   actor->mRenderer->SetGeometry( *quad );
231
232   ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
233   MaterialPtr material = Material::New();
234   material->SetShader( *shader );
235   actor->mRenderer->SetMaterial( *material );
236
237   return actor;
238 }
239
240 void ImageActor::OnInitialize()
241 {
242   // TODO: Remove this, at the moment its needed for size negotiation to work
243   SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
244 }
245
246 void ImageActor::SetImage( ImagePtr& image )
247 {
248   if( !image )
249   {
250     if( mRendererIndex != INVALID_RENDERER_ID )
251     {
252       RemoveRenderer( mRendererIndex );
253       mRendererIndex = INVALID_RENDERER_ID;
254     }
255   }
256   else
257   {
258     SamplerPtr sampler = Sampler::New();
259     sampler->SetFilterMode( mMinFilter, mMagFilter );
260
261     mTextureIndex = mRenderer->GetMaterial()->AddTexture( image, "sTexture", sampler );
262
263     if( mRendererIndex == INVALID_RENDERER_ID )
264     {
265       mRendererIndex = AddRenderer( *mRenderer );
266     }
267
268     if( !mIsPixelAreaSet )
269     {
270       mPixelArea = PixelArea( 0, 0, image->GetWidth(), image->GetHeight() );
271     }
272
273     RelayoutRequest();
274   }
275 }
276
277 ImagePtr ImageActor::GetImage() const
278 {
279   return mRenderer->GetMaterial()->GetTexture( mTextureIndex );
280 }
281
282 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
283 {
284   mPixelArea = pixelArea;
285   mIsPixelAreaSet = true;
286
287   RelayoutRequest();
288 }
289
290 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
291 {
292   return mPixelArea;
293 }
294
295 bool ImageActor::IsPixelAreaSet() const
296 {
297   return mIsPixelAreaSet;
298 }
299
300 void ImageActor::ClearPixelArea()
301 {
302   mIsPixelAreaSet = false;
303
304   int imageWidth = 0;
305   int imageHeight = 0;
306   ImagePtr image = GetImage();
307   if( image )
308   {
309     imageWidth = image->GetWidth();
310     imageHeight = image->GetHeight();
311   }
312
313   mPixelArea = PixelArea( 0, 0, imageWidth, imageHeight );
314
315   RelayoutRequest();
316 }
317
318 ImageActor::ImageActor()
319 : Actor( Actor::BASIC ),
320   mRendererIndex( INVALID_RENDERER_ID ),
321   mTextureIndex( INVALID_TEXTURE_ID ),
322   mEffectTextureIndex( INVALID_TEXTURE_ID ),
323   mMinFilter( FilterMode::DEFAULT ),
324   mMagFilter( FilterMode::DEFAULT ),
325   mIsPixelAreaSet( false )
326 {
327 }
328
329 ImageActor::~ImageActor()
330 {
331 }
332
333 Vector3 ImageActor::GetNaturalSize() const
334 {
335   Vector2 naturalSize( CalculateNaturalSize() );
336   return Vector3( naturalSize.width, naturalSize.height, 0.f );
337 }
338
339 Vector2 ImageActor::CalculateNaturalSize() const
340 {
341   // if no image then natural size is 0
342   Vector2 size( 0.0f, 0.0f );
343
344   ImagePtr image = GetImage();
345   if( image )
346   {
347     if( IsPixelAreaSet() )
348     {
349       PixelArea area(GetPixelArea());
350       size.width = area.width;
351       size.height = area.height;
352     }
353     else
354     {
355       size = image->GetNaturalSize();
356     }
357   }
358
359   return size;
360 }
361
362 void ImageActor::OnRelayout( const Vector2& size, RelayoutContainer& container )
363 {
364   int imageWidth = 1;
365   int imageHeight = 1;
366
367   ImagePtr image = GetImage();
368
369   if( image )
370   {
371     imageWidth = image->GetWidth();
372     imageHeight = image->GetHeight();
373   }
374
375   unsigned int gridWidth = 1;
376   unsigned int gridHeight = 1;
377   if( mShaderEffect )
378   {
379     Dali::ShaderEffect::GeometryHints hints = mShaderEffect->GetGeometryHints();
380     Property::Value gridDensityValue = mShaderEffect->GetDefaultProperty( Dali::ShaderEffect::Property::GRID_DENSITY );
381     int gridDensity = Dali::ShaderEffect::DEFAULT_GRID_DENSITY;
382     gridDensityValue.Get( gridDensity );
383
384     if( ( hints & Dali::ShaderEffect::HINT_GRID_X ) )
385     {
386       gridWidth = size.width / gridDensity;
387     }
388     if( ( hints & Dali::ShaderEffect::HINT_GRID_Y ) )
389     {
390       gridHeight = size.height / gridDensity;
391     }
392
393     //limit the grid size
394     gridWidth = std::min( MAXIMUM_GRID_SIZE, gridWidth );
395     gridHeight = std::min( MAXIMUM_GRID_SIZE, gridHeight );
396   }
397
398   GeometryPtr quad = gridWidth <= 1 && gridHeight <= 1 ?
399                        CreateQuadGeometry( size, imageWidth, imageHeight, mPixelArea ) :
400                        CreateGridGeometry( size, gridWidth, gridHeight, imageWidth, imageHeight, mPixelArea );
401
402   mRenderer->SetGeometry( *quad );
403
404   Vector4 textureRect( 0.f, 0.f, 1.f, 1.f );
405   if( mIsPixelAreaSet )
406   {
407     ImagePtr image = GetImage();
408     if( image )
409     {
410       int imageWidth = image->GetWidth();
411       int imageHeight = image->GetHeight();;
412
413       const float uScale = 1.0f / float(imageWidth);
414       const float vScale = 1.0f / float(imageHeight);
415       const float x = uScale * float(mPixelArea.x);
416       const float y = vScale * float(mPixelArea.y);
417       const float width  = uScale * float(mPixelArea.width);
418       const float height = vScale * float(mPixelArea.height);
419
420       // bottom left
421       textureRect.x = x;
422       textureRect.y = y;
423
424       // top right
425       textureRect.z = x + width;
426       textureRect.w = y + height;
427     }
428   }
429
430   Material* material = mRenderer->GetMaterial();
431   Property::Index index = material->GetPropertyIndex( "sTextureRect" );
432   if( index != Property::INVALID_INDEX )
433   {
434     material->SetProperty( index, textureRect );
435   }
436   else
437   {
438     material->RegisterProperty( "sTextureRect", textureRect );
439   }
440 }
441
442 unsigned int ImageActor::GetDefaultPropertyCount() const
443 {
444   return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
445 }
446
447 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
448 {
449   Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
450
451   indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
452
453   int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
454   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
455   {
456     indices.PushBack( index );
457   }
458 }
459
460 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
461 {
462   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
463   {
464     return Actor::IsDefaultPropertyWritable(index);
465   }
466
467   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
468   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
469   {
470     return DEFAULT_PROPERTY_DETAILS[ index ].writable;
471   }
472
473   return false;
474 }
475
476 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
477 {
478   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
479   {
480     return Actor::IsDefaultPropertyAnimatable( 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 ].animatable;
487   }
488
489   return false;
490 }
491
492 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
493 {
494   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
495   {
496     return Actor::IsDefaultPropertyAConstraintInput( index );
497   }
498
499   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
500   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
501   {
502     return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
503   }
504
505   return false;
506 }
507
508 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
509 {
510   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
511   {
512     return Actor::GetDefaultPropertyType( index );
513   }
514
515   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
516   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
517   {
518     return DEFAULT_PROPERTY_DETAILS[index].type;
519   }
520
521   // index out-of-bounds
522   return Property::NONE;
523 }
524
525 const char* ImageActor::GetDefaultPropertyName( Property::Index index ) const
526 {
527   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
528   {
529     return Actor::GetDefaultPropertyName(index);
530   }
531
532   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
533   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
534   {
535     return DEFAULT_PROPERTY_DETAILS[index].name;
536   }
537
538   // index out-of-bounds
539   return NULL;
540 }
541
542 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
543 {
544   Property::Index index = Property::INVALID_INDEX;
545
546   // Look for name in default properties
547   for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
548   {
549     const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
550     if( 0 == strcmp( name.c_str(), property->name ) ) // Don't want to convert rhs to string
551     {
552       index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
553       break;
554     }
555   }
556
557   // If not found, check in base class
558   if( Property::INVALID_INDEX == index )
559   {
560     index = Actor::GetDefaultPropertyIndex( name );
561   }
562   return index;
563 }
564
565 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
566 {
567   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
568   {
569     Actor::SetDefaultProperty( index, propertyValue );
570   }
571   else
572   {
573     switch(index)
574     {
575       case Dali::ImageActor::Property::PIXEL_AREA:
576       {
577         SetPixelArea(propertyValue.Get<Rect<int> >());
578         break;
579       }
580       case Dali::ImageActor::Property::STYLE:
581       {
582         //not supported
583         break;
584       }
585       case Dali::ImageActor::Property::BORDER:
586       {
587         //not supported
588         break;
589       }
590       case Dali::ImageActor::Property::IMAGE:
591       {
592         Dali::Image img = Scripting::NewImage( propertyValue );
593         if(img)
594         {
595           ImagePtr image( &GetImplementation(img) );
596           SetImage( image );
597         }
598         else
599         {
600           DALI_LOG_WARNING("Cannot create image from property value\n");
601         }
602         break;
603       }
604       default:
605       {
606         DALI_LOG_WARNING("Unknown property (%d)\n", index);
607         break;
608       }
609     } // switch(index)
610
611   } // else
612 }
613
614 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
615 {
616   Property::Value ret;
617   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
618   {
619     ret = Actor::GetDefaultProperty( index );
620   }
621   else
622   {
623     switch( index )
624     {
625       case Dali::ImageActor::Property::PIXEL_AREA:
626       {
627         Rect<int> r = GetPixelArea();
628         ret = r;
629         break;
630       }
631       case Dali::ImageActor::Property::STYLE:
632       {
633         //not supported
634         break;
635       }
636       case Dali::ImageActor::Property::BORDER:
637       {
638         //not supported
639         break;
640       }
641       case Dali::ImageActor::Property::IMAGE:
642       {
643         Property::Map map;
644         Scripting::CreatePropertyMap( Dali::Image( GetImage().Get() ), map );
645         ret = Property::Value( map );
646         break;
647       }
648       default:
649       {
650         DALI_LOG_WARNING( "Unknown property (%d)\n", index );
651         break;
652       }
653     } // switch(index)
654   }
655
656   return ret;
657 }
658
659 void ImageActor::SetSortModifier(float modifier)
660 {
661   mRenderer->SetDepthIndex( modifier );
662 }
663
664 float ImageActor::GetSortModifier() const
665 {
666   return mRenderer->GetDepthIndex();
667 }
668
669 void ImageActor::SetCullFace(CullFaceMode mode)
670 {
671   mRenderer->GetMaterial()->SetFaceCullingMode( static_cast< Dali::Material::FaceCullingMode >( mode ) );
672 }
673
674 CullFaceMode ImageActor::GetCullFace() const
675 {
676   return static_cast< CullFaceMode >( mRenderer->GetMaterial()->GetFaceCullingMode() );
677 }
678
679 void ImageActor::SetBlendMode( BlendingMode::Type mode )
680 {
681   mRenderer->GetMaterial()->SetBlendMode( mode );
682 }
683
684 BlendingMode::Type ImageActor::GetBlendMode() const
685 {
686   return mRenderer->GetMaterial()->GetBlendMode();
687 }
688
689 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgba,   BlendingFactor::Type destFactorRgba )
690 {
691   mRenderer->GetMaterial()->SetBlendFunc( srcFactorRgba, destFactorRgba, srcFactorRgba, destFactorRgba );
692 }
693
694 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgb,   BlendingFactor::Type destFactorRgb,
695                                BlendingFactor::Type srcFactorAlpha, BlendingFactor::Type destFactorAlpha )
696 {
697   mRenderer->GetMaterial()->SetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
698 }
699
700 void ImageActor::GetBlendFunc( BlendingFactor::Type& srcFactorRgb,   BlendingFactor::Type& destFactorRgb,
701                                BlendingFactor::Type& srcFactorAlpha, BlendingFactor::Type& destFactorAlpha ) const
702 {
703   mRenderer->GetMaterial()->GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
704 }
705
706 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgba )
707 {
708   mRenderer->GetMaterial()->SetBlendEquation( equationRgba, equationRgba );
709 }
710
711 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgb, BlendingEquation::Type equationAlpha )
712 {
713   mRenderer->GetMaterial()->SetBlendEquation( equationRgb, equationAlpha );
714 }
715
716 void ImageActor::GetBlendEquation( BlendingEquation::Type& equationRgb, BlendingEquation::Type& equationAlpha ) const
717 {
718   mRenderer->GetMaterial()->GetBlendEquation( equationRgb, equationAlpha );
719 }
720
721 void ImageActor::SetBlendColor( const Vector4& color )
722 {
723   mBlendColor = color;
724   mRenderer->GetMaterial()->SetBlendColor( mBlendColor );
725 }
726
727 const Vector4& ImageActor::GetBlendColor() const
728 {
729   return mBlendColor;
730 }
731
732 void ImageActor::SetFilterMode( FilterMode::Type minFilter, FilterMode::Type magFilter )
733 {
734   mMinFilter = minFilter;
735   mMagFilter = magFilter;
736
737   if( mTextureIndex != INVALID_TEXTURE_ID )
738   {
739     SamplerPtr sampler = Sampler::New();
740     sampler->SetFilterMode( minFilter, magFilter );
741
742     mRenderer->GetMaterial()->SetTextureSampler( mTextureIndex, sampler.Get() );
743   }
744 }
745
746 void ImageActor::GetFilterMode( FilterMode::Type& minFilter, FilterMode::Type& magFilter ) const
747 {
748   minFilter = mMinFilter;
749   magFilter = mMagFilter;
750 }
751
752 void ImageActor::SetShaderEffect( ShaderEffect& effect )
753 {
754   if( mShaderEffect )
755   {
756     mShaderEffect->Disconnect( this );
757   }
758
759   mShaderEffect = ShaderEffectPtr( &effect );
760   effect.Connect( this );
761
762   Dali::ShaderEffect::GeometryHints hints = effect.GetGeometryHints();
763
764   int shaderHints = Dali::Shader::HINT_NONE;
765
766   if( hints & Dali::ShaderEffect::HINT_DEPTH_BUFFER )
767   {
768     shaderHints |= Dali::Shader::HINT_REQUIRES_SELF_DEPTH_TEST;
769   }
770   if( hints & Dali::ShaderEffect::HINT_BLENDING )
771   {
772     shaderHints |= Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT;
773   }
774   if( !(hints & Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY) )
775   {
776     shaderHints |= Dali::Shader::HINT_MODIFIES_GEOMETRY;
777   }
778
779   ShaderPtr shader = Shader::New( effect.GetVertexShader(), effect.GetFragmentShader(), static_cast< Dali::Shader::ShaderHints >( shaderHints ) );
780   mRenderer->GetMaterial()->SetShader( *shader );
781
782   //get the uniforms and apply them to the renderer
783   const ShaderEffect::UniformArray& uniforms = mShaderEffect->GetUniforms();
784   for( ShaderEffect::UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it )
785   {
786     const ShaderEffect::Uniform& uniform = *it;
787     EffectUniformUpdated( uniform );
788   }
789
790   if( mShaderEffect->GetEffectImage() )
791   {
792     EffectImageUpdated();
793   }
794 }
795
796 void ImageActor::EffectUniformUpdated( const ShaderEffect::Uniform& uniform )
797 {
798   if( !mShaderEffect )
799   {
800     return;
801   }
802
803   Shader* shader = mRenderer->GetMaterial()->GetShader();
804
805   Property::Index index = shader->GetPropertyIndex( uniform.mName );
806   if( index == Property::INVALID_INDEX )
807   {
808     index = shader->RegisterProperty( uniform.mName, uniform.mValue );
809
810     //Constrain the shader's uniform properties to the ShaderEffect properties
811     Internal::ConstraintBase* constraint = NULL;
812     Internal::SourceContainer sources;
813
814     switch( uniform.mValue.GetType() )
815     {
816       case Property::INTEGER:
817       case Property::FLOAT:
818       {
819         constraint = CreateEqualConstraint< float >(*shader, index, sources );
820         break;
821       }
822       case Property::VECTOR2:
823       {
824         constraint = CreateEqualConstraint< Vector2 >(*shader, index, sources );
825         break;
826       }
827       case Property::VECTOR3:
828       {
829         constraint = CreateEqualConstraint< Vector3 >(*shader, index, sources );
830         break;
831       }
832       case Property::VECTOR4:
833       {
834         constraint = CreateEqualConstraint< Vector4 >(*shader, index, sources );
835         break;
836       }
837       case Property::MATRIX3:
838       {
839         constraint = CreateEqualConstraint< Matrix3 >(*shader, index, sources );
840         break;
841       }
842       case Property::MATRIX:
843       {
844         constraint = CreateEqualConstraint< Matrix >(*shader, index, sources );
845         break;
846       }
847       case Property::BOOLEAN:
848       case Property::ARRAY:
849       case Property::ROTATION:
850       case Property::STRING:
851       case Property::RECTANGLE:
852       case Property::MAP:
853       case Property::NONE:
854         //not supported
855         break;
856     }
857
858     //constrain the renderers property to the ShaderEffect
859     if( constraint )
860     {
861       Source source;
862       source.sourceType = OBJECT_PROPERTY;
863       source.propertyIndex = uniform.mIndex;
864       source.object = mShaderEffect.Get();
865
866       constraint->AddSource( source );
867       constraint->Apply();
868     }
869   }
870   else
871   {
872     shader->SetProperty( index, uniform.mValue );
873   }
874 }
875
876 ShaderEffectPtr ImageActor::GetShaderEffect() const
877 {
878   return mShaderEffect;
879 }
880
881 void ImageActor::RemoveShaderEffect()
882 {
883   //if we previously had a subdivided grid then we need to reset the geometry as well
884   if( mShaderEffect )
885   {
886     mShaderEffect->Disconnect( this );
887
888     Dali::ShaderEffect::GeometryHints hints = mShaderEffect->GetGeometryHints();
889     if( ( hints & Dali::ShaderEffect::HINT_GRID_X ) ||
890         ( hints & Dali::ShaderEffect::HINT_GRID_Y ) )
891     {
892       RelayoutRequest();
893     }
894   }
895
896   ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
897   mRenderer->GetMaterial()->SetShader( *shader );
898   mShaderEffect.Reset();
899 }
900
901 void ImageActor::EffectImageUpdated()
902 {
903   if( mShaderEffect )
904   {
905     Dali::Image effectImage = mShaderEffect->GetEffectImage();
906     if( effectImage )
907     {
908       Image& effectImageImpl = GetImplementation( effectImage );
909
910       if( mEffectTextureIndex == INVALID_TEXTURE_ID )
911       {
912         mEffectTextureIndex = mRenderer->GetMaterial()->AddTexture( &effectImageImpl, "sEffect", NULL );
913       }
914       else
915       {
916         mRenderer->GetMaterial()->SetTextureImage( mEffectTextureIndex, &effectImageImpl );
917       }
918     }
919     else
920     {
921       if( mEffectTextureIndex != INVALID_TEXTURE_ID )
922       {
923         mRenderer->GetMaterial()->RemoveTexture( mEffectTextureIndex );
924       }
925       mEffectTextureIndex = INVALID_TEXTURE_ID;
926     }
927
928     //ensure that the sEffectRect uniform is set
929     Shader* shader = mRenderer->GetMaterial()->GetShader();
930     Property::Index index = shader->GetPropertyIndex( "sEffectRect" );
931     if( index == Property::INVALID_INDEX )
932     {
933       shader->RegisterProperty( "sEffectRect", Vector4( 0.f, 0.f, 1.f, 1.f) );
934     }
935   }
936 }
937
938 } // namespace Internal
939
940 } // namespace Dali