2 * Copyright (c) 2016 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/public-api/rendering/renderer.h>
28 #include <dali/devel-api/scripting/scripting.h>
29 #include <dali/internal/event/animation/constraint-impl.h>
30 #include <dali/internal/event/common/property-helper.h>
31 #include <dali/internal/event/effects/shader-effect-impl.h>
32 #include <dali/internal/event/images/image-connector.h>
33 #include <dali/internal/event/images/nine-patch-image-impl.h>
46 // Name Type writable animatable constraint-input enum for index-checking
47 DALI_PROPERTY_TABLE_BEGIN
48 DALI_PROPERTY( "pixelArea", RECTANGLE, true, false, true, Dali::ImageActor::Property::PIXEL_AREA )
49 DALI_PROPERTY( "style", STRING, true, false, true, Dali::ImageActor::Property::STYLE )
50 DALI_PROPERTY( "border", VECTOR4, true, false, true, Dali::ImageActor::Property::BORDER )
51 DALI_PROPERTY( "image", MAP, true, false, false, Dali::ImageActor::Property::IMAGE )
52 DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX )
56 return Dali::ImageActor::New();
59 TypeRegistration mType( typeid( Dali::ImageActor ), typeid( Dali::Actor ), Create );
63 GridVertex( float positionX, float positionY, const Vector2& size )
64 : mPosition( positionX*size.x, positionY*size.y, 0.f ),
65 mTextureCoord( positionX+0.5f, positionY+0.5f )
70 Vector2 mTextureCoord;
73 GeometryPtr CreateGeometry( unsigned int gridWidth, unsigned int gridHeight, const Vector2& size )
76 std::vector< GridVertex > vertices;
77 vertices.reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
79 for( unsigned int y = 0u; y < gridHeight + 1; ++y )
81 float yPos = (float)y / gridHeight;
82 for( unsigned int x = 0u; x < gridWidth + 1; ++x )
84 float xPos = (float)x / gridWidth;
85 vertices.push_back( GridVertex( xPos - 0.5f, yPos - 0.5f, size ) );
90 Vector< unsigned short > indices;
91 indices.Reserve( ( gridWidth + 2 ) * gridHeight * 2 - 2);
93 for( unsigned int row = 0u; row < gridHeight; ++row )
95 unsigned int rowStartIndex = row*(gridWidth+1u);
96 unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
98 if( row != 0u ) // degenerate index on non-first row
100 indices.PushBack( rowStartIndex );
103 for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
105 indices.PushBack( rowStartIndex + column);
106 indices.PushBack( nextRowStartIndex + column);
109 if( row != gridHeight-1u ) // degenerate index on non-last row
111 indices.PushBack( nextRowStartIndex + gridWidth );
115 Property::Map vertexFormat;
116 vertexFormat[ "aPosition" ] = Property::VECTOR3;
117 vertexFormat[ "aTexCoord" ] = Property::VECTOR2;
118 PropertyBufferPtr vertexPropertyBuffer = PropertyBuffer::New( vertexFormat );
119 if( vertices.size() > 0 )
121 vertexPropertyBuffer->SetData( &vertices[ 0 ], vertices.size() );
124 // Create the geometry object
125 GeometryPtr geometry = Geometry::New();
126 geometry->AddVertexBuffer( *vertexPropertyBuffer );
127 if( indices.Size() > 0 )
129 geometry->SetIndexBuffer( &indices[0], indices.Size() );
131 geometry->SetGeometryType( Dali::Geometry::TRIANGLE_STRIP );
136 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
137 attribute mediump vec3 aPosition;\n
138 attribute mediump vec2 aTexCoord;\n
139 varying mediump vec2 vTexCoord;\n
140 uniform mediump mat4 uMvpMatrix;\n
141 uniform mediump vec3 uSize;\n
142 uniform mediump vec4 sTextureRect;\n
146 gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n
147 vTexCoord = aTexCoord;\n
151 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
152 varying mediump vec2 vTexCoord;\n
153 uniform sampler2D sTexture;\n
154 uniform lowp vec4 uColor;\n
158 gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
162 const char * const TEXTURE_RECT_UNIFORM_NAME( "sTextureRect" );
164 const int INVALID_RENDERER_ID = -1;
165 const uint16_t MAXIMUM_GRID_SIZE = 2048;
168 ImageActorPtr ImageActor::New()
170 ImageActorPtr actor( new ImageActor );
172 // Second-phase construction of base class
175 //Create the renderer
176 actor->mRenderer = Renderer::New();
178 GeometryPtr quad = CreateGeometry( 1u, 1u, Vector2::ONE );
179 actor->mRenderer->SetGeometry( *quad );
181 ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
182 actor->mRenderer->SetShader( *shader );
183 TextureSetPtr textureSet = TextureSet::New();
184 actor->mRenderer->SetTextures( *textureSet );
189 void ImageActor::OnInitialize()
191 // TODO: Remove this, at the moment its needed for size negotiation to work
192 SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
195 void ImageActor::SetImage( ImagePtr& image )
199 if( mRendererIndex != INVALID_RENDERER_ID )
201 RemoveRenderer( mRendererIndex );
202 mRendererIndex = INVALID_RENDERER_ID;
207 SamplerPtr sampler = Sampler::New();
208 sampler->SetFilterMode( mMinFilter, mMagFilter );
210 TextureSet* textureSet( mRenderer->GetTextures() );
211 textureSet->SetImage( 0u, image.Get() );
212 textureSet->SetSampler( 0u, sampler );
214 if( mRendererIndex == INVALID_RENDERER_ID )
216 mRendererIndex = AddRenderer( *mRenderer );
219 if( !mIsPixelAreaSet )
221 mPixelArea = PixelArea( 0, 0, image->GetWidth(), image->GetHeight() );
229 ImagePtr ImageActor::GetImage() const
231 return mRenderer->GetTextures()->GetImage( 0u );
234 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
236 mPixelArea = pixelArea;
237 mIsPixelAreaSet = true;
243 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
248 bool ImageActor::IsPixelAreaSet() const
250 return mIsPixelAreaSet;
253 void ImageActor::ClearPixelArea()
255 mIsPixelAreaSet = false;
259 ImagePtr image = GetImage();
262 imageWidth = image->GetWidth();
263 imageHeight = image->GetHeight();
266 mPixelArea = PixelArea( 0, 0, imageWidth, imageHeight );
272 void ImageActor::SetStyle( Dali::ImageActor::Style style )
274 DALI_LOG_WARNING( "SetStyle Deprecated. Only STYLE_QUAD supported." );
278 Dali::ImageActor::Style ImageActor::GetStyle() const
280 DALI_LOG_WARNING( "GetStyle Deprecated. Only STYLE_QUAD supported." );
284 void ImageActor::SetNinePatchBorder( const Vector4& border )
286 DALI_LOG_WARNING( "SetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
287 mNinePatchBorder = border;
290 Vector4 ImageActor::GetNinePatchBorder() const
292 DALI_LOG_WARNING( "GetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
293 return mNinePatchBorder;
296 ImageActor::ImageActor()
297 : Actor( Actor::BASIC ),
298 mActorSize( Vector2::ZERO ),
300 mRendererIndex( INVALID_RENDERER_ID ),
301 mMinFilter( FilterMode::DEFAULT ),
302 mMagFilter( FilterMode::DEFAULT ),
303 mStyle( Dali::ImageActor::STYLE_QUAD ),
304 mIsPixelAreaSet( false )
308 ImageActor::~ImageActor()
312 Vector3 ImageActor::GetNaturalSize() const
314 Vector2 naturalSize( CalculateNaturalSize() );
315 return Vector3( naturalSize.width, naturalSize.height, 0.f );
318 Vector2 ImageActor::CalculateNaturalSize() const
320 // if no image then natural size is 0
321 Vector2 size( 0.0f, 0.0f );
323 ImagePtr image = GetImage();
326 if( IsPixelAreaSet() )
328 PixelArea area(GetPixelArea());
329 size.width = area.width;
330 size.height = area.height;
334 size = image->GetNaturalSize();
341 void ImageActor::UpdateGeometry()
343 uint16_t gridWidth = 1u;
344 uint16_t gridHeight = 1u;
348 Vector2 gridSize = mShaderEffect->GetGridSize( Vector2(mPixelArea.width, mPixelArea.height) );
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) );
355 mGridSize.SetWidth( gridWidth );
356 mGridSize.SetHeight( gridHeight );
358 GeometryPtr geometry = CreateGeometry( gridWidth, gridHeight, mActorSize );
359 mRenderer->SetGeometry( *geometry );
361 void ImageActor::UpdateTexureRect()
363 Vector4 textureRect( 0.f, 0.f, 1.f, 1.f );
365 ImagePtr image = GetImage();
366 if( mIsPixelAreaSet && image )
368 const float uScale = 1.0f / float(image->GetWidth());
369 const float vScale = 1.0f / float(image->GetHeight());
371 textureRect.x = uScale * float(mPixelArea.x);
372 textureRect.y = vScale * float(mPixelArea.y);
374 textureRect.z = uScale * float(mPixelArea.x + mPixelArea.width);
375 textureRect.w = vScale * float(mPixelArea.y + mPixelArea.height);
378 mRenderer->RegisterProperty( TEXTURE_RECT_UNIFORM_NAME, textureRect );
381 unsigned int ImageActor::GetDefaultPropertyCount() const
383 return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
386 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
388 Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
390 indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
392 int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
393 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
395 indices.PushBack( index );
399 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
401 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
403 return Actor::IsDefaultPropertyWritable(index);
406 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
407 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
409 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
415 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
417 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
419 return Actor::IsDefaultPropertyAnimatable( index );
422 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
423 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
425 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
431 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
433 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
435 return Actor::IsDefaultPropertyAConstraintInput( index );
438 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
439 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
441 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
447 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
449 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
451 return Actor::GetDefaultPropertyType( index );
454 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
455 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
457 return DEFAULT_PROPERTY_DETAILS[index].type;
460 // index out-of-bounds
461 return Property::NONE;
464 const char* ImageActor::GetDefaultPropertyName( Property::Index index ) const
466 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
468 return Actor::GetDefaultPropertyName(index);
471 index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
472 if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
474 return DEFAULT_PROPERTY_DETAILS[index].name;
477 // index out-of-bounds
481 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
483 Property::Index index = Property::INVALID_INDEX;
485 // Look for name in default properties
486 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
488 const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
489 if( 0 == strcmp( name.c_str(), property->name ) ) // Don't want to convert rhs to string
491 index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
496 // If not found, check in base class
497 if( Property::INVALID_INDEX == index )
499 index = Actor::GetDefaultPropertyIndex( name );
504 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
506 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
508 Actor::SetDefaultProperty( index, propertyValue );
514 case Dali::ImageActor::Property::PIXEL_AREA:
516 SetPixelArea(propertyValue.Get<Rect<int> >());
519 case Dali::ImageActor::Property::STYLE:
524 case Dali::ImageActor::Property::BORDER:
529 case Dali::ImageActor::Property::IMAGE:
531 Dali::Image img = Scripting::NewImage( propertyValue );
534 ImagePtr image( &GetImplementation(img) );
539 DALI_LOG_WARNING("Cannot create image from property value\n");
545 DALI_LOG_WARNING("Unknown property (%d)\n", index);
553 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
556 if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
558 ret = Actor::GetDefaultProperty( index );
564 case Dali::ImageActor::Property::PIXEL_AREA:
566 Rect<int> r = GetPixelArea();
570 case Dali::ImageActor::Property::STYLE:
575 case Dali::ImageActor::Property::BORDER:
580 case Dali::ImageActor::Property::IMAGE:
583 Scripting::CreatePropertyMap( Dali::Image( GetImage().Get() ), map );
584 ret = Property::Value( map );
589 DALI_LOG_WARNING( "Unknown property (%d)\n", index );
598 void ImageActor::SetSortModifier(float modifier)
600 mRenderer->SetDepthIndex( modifier );
603 float ImageActor::GetSortModifier() const
605 return mRenderer->GetDepthIndex();
608 void ImageActor::SetBlendMode( BlendingMode::Type mode )
610 mRenderer->SetBlendMode( static_cast<BlendMode::Type>( mode ) );
613 BlendingMode::Type ImageActor::GetBlendMode() const
615 return static_cast<BlendingMode::Type>( mRenderer->GetBlendMode() );
618 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgba, BlendingFactor::Type destFactorRgba )
620 mRenderer->SetBlendFunc( static_cast<BlendFactor::Type>(srcFactorRgba), static_cast<BlendFactor::Type>(destFactorRgba), static_cast<BlendFactor::Type>(srcFactorRgba), static_cast<BlendFactor::Type>(destFactorRgba) );
623 void ImageActor::SetBlendFunc( BlendingFactor::Type srcFactorRgb, BlendingFactor::Type destFactorRgb,
624 BlendingFactor::Type srcFactorAlpha, BlendingFactor::Type destFactorAlpha )
626 mRenderer->SetBlendFunc( static_cast<BlendFactor::Type>(srcFactorRgb), static_cast<BlendFactor::Type>(destFactorRgb), static_cast<BlendFactor::Type>(srcFactorAlpha), static_cast<BlendFactor::Type>(destFactorAlpha) );
629 void ImageActor::GetBlendFunc( BlendingFactor::Type& srcFactorRgb, BlendingFactor::Type& destFactorRgb,
630 BlendingFactor::Type& srcFactorAlpha, BlendingFactor::Type& destFactorAlpha ) const
632 mRenderer->GetBlendFunc( reinterpret_cast<BlendFactor::Type&>(srcFactorRgb), reinterpret_cast<BlendFactor::Type&>(destFactorRgb), reinterpret_cast<BlendFactor::Type&>(srcFactorAlpha), reinterpret_cast<BlendFactor::Type&>(destFactorAlpha) );
635 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgba )
637 mRenderer->SetBlendEquation( static_cast<BlendEquation::Type>(equationRgba), static_cast<BlendEquation::Type>(equationRgba) );
640 void ImageActor::SetBlendEquation( BlendingEquation::Type equationRgb, BlendingEquation::Type equationAlpha )
642 mRenderer->SetBlendEquation( static_cast<BlendEquation::Type>(equationRgb), static_cast<BlendEquation::Type>(equationAlpha) );
645 void ImageActor::GetBlendEquation( BlendingEquation::Type& equationRgb, BlendingEquation::Type& equationAlpha ) const
647 mRenderer->GetBlendEquation( reinterpret_cast<BlendEquation::Type&>(equationRgb), reinterpret_cast<BlendEquation::Type&>(equationAlpha) );
650 void ImageActor::SetBlendColor( const Vector4& color )
653 mRenderer->SetBlendColor( mBlendColor );
656 const Vector4& ImageActor::GetBlendColor() const
661 void ImageActor::SetFilterMode( FilterMode::Type minFilter, FilterMode::Type magFilter )
663 mMinFilter = minFilter;
664 mMagFilter = magFilter;
666 SamplerPtr sampler = Sampler::New();
667 sampler->SetFilterMode( minFilter, magFilter );
668 mRenderer->GetTextures()->SetSampler( 0u, sampler.Get() );
671 void ImageActor::GetFilterMode( FilterMode::Type& minFilter, FilterMode::Type& magFilter ) const
673 minFilter = mMinFilter;
674 magFilter = mMagFilter;
677 void ImageActor::SetShaderEffect( ShaderEffect& effect )
681 mShaderEffect->Disconnect( this );
684 mShaderEffect = ShaderEffectPtr( &effect );
685 effect.Connect( this );
687 ShaderPtr shader = mShaderEffect->GetShader();
688 mRenderer->SetShader( *shader );
690 EffectImageUpdated();
695 ShaderEffectPtr ImageActor::GetShaderEffect() const
697 return mShaderEffect;
700 void ImageActor::RemoveShaderEffect()
704 mShaderEffect->Disconnect( this );
705 // change to the standard shader and quad geometry
706 ShaderPtr shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Dali::Shader::HINT_NONE );
707 mRenderer->SetShader( *shader );
708 mShaderEffect.Reset();
714 void ImageActor::EffectImageUpdated()
718 Dali::Image effectImage = mShaderEffect->GetEffectImage();
721 Image& effectImageImpl = GetImplementation( effectImage );
722 mRenderer->GetTextures()->SetImage( 1u, &effectImageImpl );
726 mRenderer->GetTextures()->SetImage( 1u, 0 );
731 void ImageActor::OnRelayout( const Vector2& size, RelayoutContainer& container )
733 if( mActorSize != size )
740 void ImageActor::OnSizeSet( const Vector3& targetSize )
742 Vector2 size( targetSize.x, targetSize.y );
743 if( mActorSize != size )
750 } // namespace Internal