Dali 3D User Interface Engine
image-actor-impl.cpp
Go to the documentation of this file.
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
20 
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 
24 // INTERNAL INCLUDES
25 #include <dali/public-api/animation/constraints.h> // for EqualToConstraint
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
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 )
52 
54 {
55  return Dali::ImageActor::New();
56 }
57 
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 
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 
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 
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 
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 
201 {
202  // TODO: Remove this, at the moment its needed for size negotiation to work
204 }
205 
207 {
208  if( !image )
209  {
211  {
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 
224  {
226  }
227 
228  if( !mIsPixelAreaSet )
229  {
230  mPixelArea = PixelArea( 0, 0, image->GetWidth(), image->GetHeight() );
231  }
232 
233  RelayoutRequest();
235  }
236 }
237 
239 {
241 }
242 
243 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
244 {
245  mPixelArea = pixelArea;
246  mIsPixelAreaSet = true;
247 
248  RelayoutRequest();
250 }
251 
253 {
254  return mPixelArea;
255 }
256 
258 {
259  return mIsPixelAreaSet;
260 }
261 
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();
279 }
280 
282 {
283  DALI_LOG_WARNING( "SetStyle Deprecated. Only STYLE_QUAD supported." );
284  mStyle = style;
285 }
286 
288 {
289  DALI_LOG_WARNING( "GetStyle Deprecated. Only STYLE_QUAD supported." );
290  return mStyle;
291 }
292 
294 {
295  DALI_LOG_WARNING( "SetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
296  mNinePatchBorder = border;
297 }
298 
300 {
301  DALI_LOG_WARNING( "GetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
302  return mNinePatchBorder;
303 }
304 
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 
320 {
321 }
322 
324 {
325  Vector2 naturalSize( CalculateNaturalSize() );
326  return Vector3( naturalSize.width, naturalSize.height, 0.f );
327 }
328 
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 
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 }
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 
394 {
395  return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
396 }
397 
399 {
400  Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
401 
402  indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
403 
405  for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
406  {
407  indices.PushBack( index );
408  }
409 }
410 
412 {
414  {
415  return Actor::IsDefaultPropertyWritable(index);
416  }
417 
419  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
420  {
421  return DEFAULT_PROPERTY_DETAILS[ index ].writable;
422  }
423 
424  return false;
425 }
426 
428 {
430  {
431  return Actor::IsDefaultPropertyAnimatable( index );
432  }
433 
435  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
436  {
437  return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
438  }
439 
440  return false;
441 }
442 
444 {
446  {
448  }
449 
451  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
452  {
453  return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
454  }
455 
456  return false;
457 }
458 
460 {
462  {
463  return Actor::GetDefaultPropertyType( index );
464  }
465 
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 
477 {
479  {
480  return Actor::GetDefaultPropertyName(index);
481  }
482 
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 
494 {
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  {
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 
517 {
519  {
520  Actor::SetDefaultProperty( index, propertyValue );
521  }
522  else
523  {
524  switch(index)
525  {
527  {
528  SetPixelArea(propertyValue.Get<Rect<int> >());
529  break;
530  }
532  {
533  //not supported
534  break;
535  }
537  {
538  //not supported
539  break;
540  }
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 
566 {
567  Property::Value ret;
569  {
570  ret = Actor::GetDefaultProperty( index );
571  }
572  else
573  {
574  switch( index )
575  {
577  {
579  ret = r;
580  break;
581  }
583  {
584  //not supported
585  break;
586  }
588  {
589  //not supported
590  break;
591  }
593  {
594  Property::Map 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 
616 {
617  return mRenderer->GetDepthIndex();
618 }
619 
621 {
622  mRenderer->SetFaceCullingMode( static_cast< Dali::Renderer::FaceCullingMode >( mode ) );
623 }
624 
626 {
627  return static_cast< CullFaceMode >( mRenderer->GetFaceCullingMode() );
628 }
629 
631 {
632  mRenderer->SetBlendMode( mode );
633 }
634 
636 {
637  return mRenderer->GetBlendMode();
638 }
639 
641 {
642  mRenderer->SetBlendFunc( srcFactorRgba, destFactorRgba, srcFactorRgba, destFactorRgba );
643 }
644 
646  BlendingFactor::Type srcFactorAlpha, BlendingFactor::Type destFactorAlpha )
647 {
648  mRenderer->SetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
649 }
650 
652  BlendingFactor::Type& srcFactorAlpha, BlendingFactor::Type& destFactorAlpha ) const
653 {
654  mRenderer->GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
655 }
656 
658 {
659  mRenderer->SetBlendEquation( equationRgba, equationRgba );
660 }
661 
663 {
664  mRenderer->SetBlendEquation( equationRgb, equationAlpha );
665 }
666 
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 
679 {
680  return mBlendColor;
681 }
682 
684 {
685  mMinFilter = minFilter;
686  mMagFilter = magFilter;
687 
689  {
690  SamplerPtr sampler = Sampler::New();
691  sampler->SetFilterMode( minFilter, magFilter );
692 
694  }
695 }
696 
697 void ImageActor::GetFilterMode( FilterMode::Type& minFilter, FilterMode::Type& magFilter ) const
698 {
699  minFilter = mMinFilter;
700  magFilter = mMagFilter;
701 }
702 
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 
717 
718  UpdateGeometry();
719 }
720 
722 {
723  return mShaderEffect;
724 }
725 
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 );
735 
736  UpdateGeometry();
737  }
738 }
739 
741 {
742  if( mShaderEffect )
743  {
744  Dali::Image effectImage = mShaderEffect->GetEffectImage();
745  if( effectImage )
746  {
747  Image& effectImageImpl = GetImplementation( effectImage );
748 
750  {
751  mEffectTextureIndex = mRenderer->GetMaterial()->AddTexture( &effectImageImpl, "sEffect", NULL );
752  }
753  else
754  {
755  mRenderer->GetMaterial()->SetTextureImage( mEffectTextureIndex, &effectImageImpl );
756  }
757  }
758  else
759  {
761  {
763  }
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
Dali Docs Home
Read more about Dali