2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/actors/image-actor-impl.h>
22 #include <cstring> // for strcmp
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>
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 )
55 return Dali::ImageActor::New();
58 TypeRegistration mType( typeid( Dali::ImageActor ), typeid( Dali::Actor ), Create );
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 )
69 Vector2 mTextureCoord;
72 GeometryPtr CreateGeometry( unsigned int gridWidth, unsigned int gridHeight, const Vector2& size )
75 std::vector< GridVertex > vertices;
76 vertices.reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
78 for( unsigned int y = 0u; y < gridHeight + 1; ++y )
80 float yPos = (float)y / gridHeight;
81 for( unsigned int x = 0u; x < gridWidth + 1; ++x )
83 float xPos = (float)x / gridWidth;
84 vertices.push_back( GridVertex( xPos - 0.5f, yPos - 0.5f, size ) );
89 Vector< unsigned int > indices;
90 indices.Reserve( ( gridWidth + 2 ) * gridHeight * 2 - 2);
92 for( unsigned int row = 0u; row < gridHeight; ++row )
94 unsigned int rowStartIndex = row*(gridWidth+1u);
95 unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
97 if( row != 0u ) // degenerate index on non-first row
99 indices.PushBack( rowStartIndex );
102 for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
104 indices.PushBack( rowStartIndex + column);
105 indices.PushBack( nextRowStartIndex + column);
108 if( row != gridHeight-1u ) // degenerate index on non-last row
110 indices.PushBack( nextRowStartIndex + gridWidth );
114 Property::Map vertexFormat;
115 vertexFormat[ "aPosition" ] = Property::VECTOR3;
116 vertexFormat[ "aTexCoord" ] = Property::VECTOR2;
117 PropertyBufferPtr vertexPropertyBuffer = PropertyBuffer::New( vertexFormat );
118 if( vertices.size() > 0 )
120 vertexPropertyBuffer->SetData( &vertices[ 0 ], vertices.size() );
123 Property::Map indexFormat;
124 indexFormat[ "indices" ] = Property::INTEGER;
125 PropertyBufferPtr indexPropertyBuffer = PropertyBuffer::New( indexFormat );
126 if( indices.Size() > 0 )
128 indexPropertyBuffer->SetData( &indices[ 0 ], indices.Size() );
131 // Create the geometry object
132 GeometryPtr geometry = Geometry::New();
133 geometry->AddVertexBuffer( *vertexPropertyBuffer );
134 geometry->SetIndexBuffer( *indexPropertyBuffer );
135 geometry->SetGeometryType( Dali::Geometry::TRIANGLE_STRIP );
140 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
141 attribute mediump vec3 aPosition;\n
142 attribute mediump vec2 aTexCoord;\n
143 varying mediump vec2 vTexCoord;\n
144 uniform mediump mat4 uMvpMatrix;\n
145 uniform mediump vec3 uSize;\n
146 uniform mediump vec4 sTextureRect;\n
150 gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n
151 vTexCoord = aTexCoord;\n
155 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
156 varying mediump vec2 vTexCoord;\n
157 uniform sampler2D sTexture;\n
158 uniform lowp vec4 uColor;\n
162 gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
166 const char * const TEXTURE_RECT_UNIFORM_NAME( "sTextureRect" );
168 const size_t INVALID_TEXTURE_ID = (size_t)-1;
169 const int INVALID_RENDERER_ID = -1;
170 const uint16_t MAXIMUM_GRID_SIZE = 2048;
173 ImageActorPtr ImageActor::New()
175 ImageActorPtr actor( new ImageActor );
177 // Second-phase construction of base class
180 //Create the renderer
181 actor->mRenderer = Renderer::New();
183 GeometryPtr quad = CreateGeometry( 1u, 1u, Vector2::ONE );
184 actor->mRenderer->SetGeometry( *quad );
186 ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
187 MaterialPtr material = Material::New();
188 material->SetShader( *shader );
189 actor->mRenderer->SetMaterial( *material );
194 void ImageActor::OnInitialize()
196 // TODO: Remove this, at the moment its needed for size negotiation to work
197 SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
200 void ImageActor::SetImage( ImagePtr& image )
204 if( mRendererIndex != INVALID_RENDERER_ID )
206 RemoveRenderer( mRendererIndex );
207 mRendererIndex = INVALID_RENDERER_ID;
212 SamplerPtr sampler = Sampler::New();
213 sampler->SetFilterMode( mMinFilter, mMagFilter );
215 mTextureIndex = mRenderer->GetMaterial()->AddTexture( image, "sTexture", sampler );
217 if( mRendererIndex == INVALID_RENDERER_ID )
219 mRendererIndex = AddRenderer( *mRenderer );
222 if( !mIsPixelAreaSet )
224 mPixelArea = PixelArea( 0, 0, image->GetWidth(), image->GetHeight() );
232 ImagePtr ImageActor::GetImage() const
234 return mRenderer->GetMaterial()->GetTexture( mTextureIndex );
237 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
239 mPixelArea = pixelArea;
240 mIsPixelAreaSet = true;
246 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
251 bool ImageActor::IsPixelAreaSet() const
253 return mIsPixelAreaSet;
256 void ImageActor::ClearPixelArea()
258 mIsPixelAreaSet = false;
262 ImagePtr image = GetImage();
265 imageWidth = image->GetWidth();
266 imageHeight = image->GetHeight();
269 mPixelArea = PixelArea( 0, 0, imageWidth, imageHeight );
275 void ImageActor::SetStyle( Dali::ImageActor::Style style )
277 DALI_LOG_WARNING( "SetStyle Deprecated. Only STYLE_QUAD supported." );
281 Dali::ImageActor::Style ImageActor::GetStyle() const
283 DALI_LOG_WARNING( "GetStyle Deprecated. Only STYLE_QUAD supported." );
287 void ImageActor::SetNinePatchBorder( const Vector4& border )
289 DALI_LOG_WARNING( "SetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
290 mNinePatchBorder = border;
293 Vector4 ImageActor::GetNinePatchBorder() const
295 DALI_LOG_WARNING( "GetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
296 return mNinePatchBorder;
299 ImageActor::ImageActor()
300 : Actor( Actor::BASIC ),
301 mActorSize( Vector2::ZERO ),
303 mRendererIndex( INVALID_RENDERER_ID ),
304 mTextureIndex( INVALID_TEXTURE_ID ),
305 mEffectTextureIndex( INVALID_TEXTURE_ID ),
306 mMinFilter( FilterMode::DEFAULT ),
307 mMagFilter( FilterMode::DEFAULT ),
308 mStyle( Dali::ImageActor::STYLE_QUAD ),
309 mIsPixelAreaSet( false )
313 ImageActor::~ImageActor()
317 Vector3 ImageActor::GetNaturalSize() const
319 Vector2 naturalSize( CalculateNaturalSize() );
320 return Vector3( naturalSize.width, naturalSize.height, 0.f );
323 Vector2 ImageActor::CalculateNaturalSize() const
325 // if no image then natural size is 0
326 Vector2 size( 0.0f, 0.0f );
328 ImagePtr image = GetImage();
331 if( IsPixelAreaSet() )
333 PixelArea area(GetPixelArea());
334 size.width = area.width;
335 size.height = area.height;
339 size = image->GetNaturalSize();
346 void ImageActor::UpdateGeometry()
348 uint16_t gridWidth = 1u;
349 uint16_t gridHeight = 1u;
353 Vector2 gridSize = mShaderEffect->GetGridSize( Vector2(mPixelArea.width, mPixelArea.height) );
355 //limit the grid size
356 gridWidth = std::min( MAXIMUM_GRID_SIZE, static_cast<uint16_t>(gridSize.width) );
357 gridHeight = std::min( MAXIMUM_GRID_SIZE, static_cast<uint16_t>(gridSize.height) );
360 mGridSize.SetWidth( gridWidth );
361 mGridSize.SetHeight( gridHeight );
363 GeometryPtr geometry = CreateGeometry( gridWidth, gridHeight, mActorSize );
364 mRenderer->SetGeometry( *geometry );
366 void ImageActor::UpdateTexureRect()
368 Vector4 textureRect( 0.f, 0.f, 1.f, 1.f );
370 ImagePtr image = GetImage();
371 if( mIsPixelAreaSet && image )
373 const float uScale = 1.0f / float(image->GetWidth());
374 const float vScale = 1.0f / float(image->GetHeight());
376 textureRect.x = uScale * float(mPixelArea.x);
377 textureRect.y = vScale * float(mPixelArea.y);
379 textureRect.z = uScale * float(mPixelArea.x + mPixelArea.width);
380 textureRect.w = vScale * float(mPixelArea.y + mPixelArea.height);
383 Material* material = mRenderer->GetMaterial();
384 material->RegisterProperty( TEXTURE_RECT_UNIFORM_NAME, textureRect );
387 unsigned int ImageActor::GetDefaultPropertyCount() const
389 return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
392 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
394 Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
396 indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
398 int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
399 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
401 indices.PushBack( index );
405 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
407 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
409 return Actor::IsDefaultPropertyWritable(index);
412 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
413 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
415 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
421 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
423 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
425 return Actor::IsDefaultPropertyAnimatable( index );
428 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
429 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
431 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
437 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
439 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
441 return Actor::IsDefaultPropertyAConstraintInput( index );
444 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
445 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
447 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
453 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
455 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
457 return Actor::GetDefaultPropertyType( index );
460 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
461 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
463 return DEFAULT_PROPERTY_DETAILS[index].type;
466 // index out-of-bounds
467 return Property::NONE;
470 const char* ImageActor::GetDefaultPropertyName( Property::Index index ) const
472 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
474 return Actor::GetDefaultPropertyName(index);
477 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
478 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
480 return DEFAULT_PROPERTY_DETAILS[index].name;
483 // index out-of-bounds
487 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
489 Property::Index index = Property::INVALID_INDEX;
491 // Look for name in default properties
492 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
494 const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
495 if( 0 == strcmp( name.c_str(), property->name ) ) // Don't want to convert rhs to string
497 index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
502 // If not found, check in base class
503 if( Property::INVALID_INDEX == index )
505 index = Actor::GetDefaultPropertyIndex( name );
510 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
512 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
514 Actor::SetDefaultProperty( index, propertyValue );
520 case Dali::ImageActor::Property::PIXEL_AREA:
522 SetPixelArea(propertyValue.Get<Rect<int> >());
525 case Dali::ImageActor::Property::STYLE:
530 case Dali::ImageActor::Property::BORDER:
535 case Dali::ImageActor::Property::IMAGE:
537 Dali::Image img = Scripting::NewImage( propertyValue );
540 ImagePtr image( &GetImplementation(img) );
545 DALI_LOG_WARNING("Cannot create image from property value\n");
551 DALI_LOG_WARNING("Unknown property (%d)\n", index);
559 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
562 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
564 ret = Actor::GetDefaultProperty( index );
570 case Dali::ImageActor::Property::PIXEL_AREA:
572 Rect<int> r = GetPixelArea();
576 case Dali::ImageActor::Property::STYLE:
581 case Dali::ImageActor::Property::BORDER:
586 case Dali::ImageActor::Property::IMAGE:
589 Scripting::CreatePropertyMap( Dali::Image( GetImage().Get() ), map );
590 ret = Property::Value( map );
595 DALI_LOG_WARNING( "Unknown property (%d)\n", index );
604 void ImageActor::SetSortModifier(float modifier)
606 mRenderer->SetDepthIndex( modifier );
609 float ImageActor::GetSortModifier() const
611 return mRenderer->GetDepthIndex();
614 void ImageActor::SetCullFace(CullFaceMode mode)
616 mRenderer->SetFaceCullingMode( static_cast< Dali::Renderer::FaceCullingMode >( mode ) );
619 CullFaceMode ImageActor::GetCullFace() const
621 return static_cast< CullFaceMode >( mRenderer->GetFaceCullingMode() );
624 void ImageActor::SetBlendMode( BlendingMode::Type mode )
626 mRenderer->SetBlendMode( mode );
629 BlendingMode::Type ImageActor::GetBlendMode() const
631 return mRenderer->GetBlendMode();
634 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgba, BlendingFactor::Type destFactorRgba )
636 mRenderer->SetBlendFunc( srcFactorRgba, destFactorRgba, srcFactorRgba, destFactorRgba );
639 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgb, BlendingFactor::Type destFactorRgb,
640 BlendingFactor::Type srcFactorAlpha, BlendingFactor::Type destFactorAlpha )
642 mRenderer->SetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
645 void ImageActor::GetBlendFunc( BlendingFactor::Type& srcFactorRgb, BlendingFactor::Type& destFactorRgb,
646 BlendingFactor::Type& srcFactorAlpha, BlendingFactor::Type& destFactorAlpha ) const
648 mRenderer->GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
651 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgba )
653 mRenderer->SetBlendEquation( equationRgba, equationRgba );
656 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgb, BlendingEquation::Type equationAlpha )
658 mRenderer->SetBlendEquation( equationRgb, equationAlpha );
661 void ImageActor::GetBlendEquation( BlendingEquation::Type& equationRgb, BlendingEquation::Type& equationAlpha ) const
663 mRenderer->GetBlendEquation( equationRgb, equationAlpha );
666 void ImageActor::SetBlendColor( const Vector4& color )
669 mRenderer->SetBlendColor( mBlendColor );
672 const Vector4& ImageActor::GetBlendColor() const
677 void ImageActor::SetFilterMode( FilterMode::Type minFilter, FilterMode::Type magFilter )
679 mMinFilter = minFilter;
680 mMagFilter = magFilter;
682 if( mTextureIndex != INVALID_TEXTURE_ID )
684 SamplerPtr sampler = Sampler::New();
685 sampler->SetFilterMode( minFilter, magFilter );
687 mRenderer->GetMaterial()->SetTextureSampler( mTextureIndex, sampler.Get() );
691 void ImageActor::GetFilterMode( FilterMode::Type& minFilter, FilterMode::Type& magFilter ) const
693 minFilter = mMinFilter;
694 magFilter = mMagFilter;
697 void ImageActor::SetShaderEffect( ShaderEffect& effect )
701 mShaderEffect->Disconnect( this );
704 mShaderEffect = ShaderEffectPtr( &effect );
705 effect.Connect( this );
707 ShaderPtr shader = mShaderEffect->GetShader();
708 mRenderer->GetMaterial()->SetShader( *shader );
710 EffectImageUpdated();
715 ShaderEffectPtr ImageActor::GetShaderEffect() const
717 return mShaderEffect;
720 void ImageActor::RemoveShaderEffect()
724 mShaderEffect->Disconnect( this );
725 // change to the standard shader and quad geometry
726 ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
727 mRenderer->GetMaterial()->SetShader( *shader );
728 mShaderEffect.Reset();
734 void ImageActor::EffectImageUpdated()
738 Dali::Image effectImage = mShaderEffect->GetEffectImage();
741 Image& effectImageImpl = GetImplementation( effectImage );
743 if( mEffectTextureIndex == INVALID_TEXTURE_ID )
745 mEffectTextureIndex = mRenderer->GetMaterial()->AddTexture( &effectImageImpl, "sEffect", NULL );
749 mRenderer->GetMaterial()->SetTextureImage( mEffectTextureIndex, &effectImageImpl );
754 if( mEffectTextureIndex != INVALID_TEXTURE_ID )
756 mRenderer->GetMaterial()->RemoveTexture( mEffectTextureIndex );
758 mEffectTextureIndex = INVALID_TEXTURE_ID;
764 void ImageActor::OnRelayout( const Vector2& size, RelayoutContainer& container )
766 if( mActorSize != size )
773 void ImageActor::OnSizeSet( const Vector3& targetSize )
775 Vector2 size( targetSize.x, targetSize.y );
776 if( mActorSize != size )
783 } // namespace Internal