(ImageActor) Added new nine patch style to render the image border only
[platform/core/uifw/dali-core.git] / dali / internal / update / node-attachments / scene-graph-image-attachment.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/update/node-attachments/scene-graph-image-attachment.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/common/internal-constants.h>
25
26 #include <dali/internal/update/resources/resource-manager.h>
27 #include <dali/internal/update/resources/complete-status-manager.h>
28
29 #include <dali/internal/update/controllers/render-message-dispatcher.h>
30 #include <dali/internal/update/controllers/scene-controller.h>
31 #include <dali/internal/update/nodes/node.h>
32
33 #include <dali/internal/render/queue/render-queue.h>
34 #include <dali/internal/render/common/vertex.h>
35 #include <dali/internal/render/common/performance-monitor.h>
36 #include <dali/internal/render/renderers/scene-graph-image-renderer.h>
37 #include <dali/internal/render/renderers/scene-graph-renderer-declarations.h>
38 #include <dali/internal/render/shaders/shader.h>
39
40 #include <dali/internal/update/node-attachments/scene-graph-image-attachment-debug.h>
41
42 using namespace std;
43
44 namespace Dali
45 {
46
47 namespace Internal
48 {
49
50 // value types used by messages
51 template <> struct ParameterType< SceneGraph::ImageRenderer::MeshType >
52 : public BasicType< SceneGraph::ImageRenderer::MeshType > {};
53
54 namespace SceneGraph
55 {
56
57 ImageAttachment* ImageAttachment::New( unsigned int textureId )
58 {
59   return new ImageAttachment( textureId );
60 }
61
62 ImageAttachment::ImageAttachment( unsigned int textureId )
63 : RenderableAttachment( false ), // no scaling
64   mImageRenderer( NULL ),
65   mTextureId( textureId ),
66   mRefreshMeshData( true ),
67   mIsPixelAreaSet( false ),
68   mPreviousRefreshHints( 0 ),
69   mStyle( Dali::ImageActor::STYLE_QUAD )
70 {
71 }
72
73 void ImageAttachment::ConnectToSceneGraph2( BufferIndex updateBufferIndex )
74 {
75   DALI_ASSERT_DEBUG( NULL != mSceneController );
76
77   // Create main renderer, passing ownership to the render-thread
78   mImageRenderer = ImageRenderer::New( *mParent );
79
80   mSceneController->GetRenderMessageDispatcher().AddRenderer( *mImageRenderer );
81
82   ATTACHMENT_LOG_FMT(Debug::General, " renderer: %p\n", mImageRenderer);
83
84   if( mTextureId != 0 )
85   {
86     typedef MessageValue1< ImageRenderer, ResourceId > DerivedType;
87
88     // Reserve some memory inside the render queue
89     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
90
91     // Construct message in the render queue memory; note that delete should not be called on the return value
92     new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetTextureId, mTextureId );
93   }
94 }
95
96 void ImageAttachment::OnDestroy2()
97 {
98   DALI_ASSERT_DEBUG( NULL != mSceneController );
99
100   // Request deletion in the next Render
101   mSceneController->GetRenderMessageDispatcher().RemoveRenderer( *mImageRenderer );
102   mImageRenderer = NULL;
103 }
104
105 ImageAttachment::~ImageAttachment()
106 {
107 }
108
109 Renderer& ImageAttachment::GetRenderer()
110 {
111   return *mImageRenderer;
112 }
113
114 const Renderer& ImageAttachment::GetRenderer() const
115 {
116   return *mImageRenderer;
117 }
118
119 void ImageAttachment::SetTextureId( BufferIndex updateBufferIndex, unsigned int textureId )
120 {
121   DALI_ASSERT_DEBUG(mSceneController);
122   ATTACHMENT_LOG_FMT(Debug::General, " textureid: %d)\n", textureId);
123
124   mTextureId = textureId;
125   mFinishedResourceAcquisition = false;
126
127   if( mImageRenderer )
128   {
129     typedef MessageValue1< ImageRenderer, ResourceId > DerivedType;
130
131     // Reserve some memory inside the render queue
132     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
133
134     // Construct message in the render queue memory; note that delete should not be called on the return value
135     new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetTextureId, mTextureId );
136   }
137 }
138
139 void ImageAttachment::SetPixelArea( BufferIndex updateBufferIndex, const PixelArea& pixelArea )
140 {
141   // update the pixel area information
142   mIsPixelAreaSet = true;
143
144   {
145     typedef MessageValue1< ImageRenderer, ImageRenderer::PixelArea > DerivedType;
146
147     // Reserve some memory inside the render queue
148     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
149
150     // Construct message in the render queue memory; note that delete should not be called on the return value
151     new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetPixelArea, pixelArea );
152   }
153
154   // we rely on attachment to not call us unless it actually did change
155   mRefreshMeshData = true;
156 }
157
158 void ImageAttachment::ClearPixelArea()
159 {
160   mIsPixelAreaSet = false;
161   mRefreshMeshData = true;
162 }
163
164 void ImageAttachment::SetStyle( Dali::ImageActor::Style style )
165 {
166   if (mStyle != style)
167   {
168     mStyle = style;
169     mRefreshMeshData = true;
170   }
171 }
172
173 void ImageAttachment::SetBorder( BufferIndex updateBufferIndex, const Vector4& border, bool inPixels )
174 {
175   // update the 9 patch border information
176
177   typedef MessageValue2< ImageRenderer, Vector4, bool > DerivedType;
178
179   // Reserve some memory inside the render queue
180   unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
181
182   // Construct message in the render queue memory; note that delete should not be called on the return value
183   new (slot) DerivedType( mImageRenderer, &ImageRenderer::SetNinePatchBorder, border, inPixels );
184
185   if (mStyle != Dali::ImageActor::STYLE_QUAD)
186   {
187     mRefreshMeshData = true;
188   }
189 }
190
191 void ImageAttachment::ShaderChanged( BufferIndex updateBufferIndex )
192 {
193   DALI_ASSERT_DEBUG( mShader != NULL );
194   DALI_ASSERT_DEBUG( mSceneController );
195
196   int hints = mShader->GetGeometryHints();
197
198   if ( hints != mPreviousRefreshHints )
199   {
200     mPreviousRefreshHints = hints;
201     // (may) need to change geometry
202     mRefreshMeshData = true;
203   }
204 }
205
206 void ImageAttachment::SizeChanged( BufferIndex updateBufferIndex )
207 {
208   // avoid regenerating geometry if the size did not actually change (visibility change can accumulate a false SizeChanged)
209   const Vector3& actorSize = GetParent().GetSize( updateBufferIndex );
210   if( fabsf( actorSize.width  - mGeometrySize.width  ) > Math::MACHINE_EPSILON_1 ||
211       fabsf( actorSize.height - mGeometrySize.height ) > Math::MACHINE_EPSILON_1 )
212   {
213     mRefreshMeshData = true;
214   }
215 }
216
217 bool ImageAttachment::DoPrepareResources( BufferIndex updateBufferIndex, ResourceManager& resourceManager )
218 {
219   DALI_LOG_TRACE_METHOD_FMT(gImageAttachmentLogFilter, "this:%p", this);
220   bool ready = false;
221
222   // The metadata is used by IsFullyOpaque(), below.
223   mBitmapMetadata = resourceManager.GetBitmapMetadata( mTextureId );
224
225   CompleteStatusManager& completeStatusManager = mSceneController->GetCompleteStatusManager();
226   CompleteStatusManager::CompleteState status = completeStatusManager.GetStatus( mTextureId );
227
228   switch( status )
229   {
230     case CompleteStatusManager::NOT_READY:
231     {
232       ready = false;
233
234       if( mBitmapMetadata.GetIsFramebuffer() )
235       {
236         ready = true;
237       }
238       mFinishedResourceAcquisition = false;
239       FollowTracker( mTextureId );
240     }
241     break;
242
243     case CompleteStatusManager::COMPLETE:
244     {
245       ready = true;
246       mFinishedResourceAcquisition = true;
247     }
248     break;
249
250     case CompleteStatusManager::NEVER:
251     {
252       ready = false;
253       mFinishedResourceAcquisition = true;
254     }
255     break;
256   }
257
258   ATTACHMENT_LOG_FMT(Debug::General, " finished:%s ready:%s \n", mFinishedResourceAcquisition?"T":"F", ready?"T":"F");
259
260   return ready;
261 }
262
263 void ImageAttachment::DoPrepareRender( BufferIndex updateBufferIndex )
264 {
265   DALI_ASSERT_DEBUG( mSceneController && mImageRenderer );
266
267   ATTACHMENT_LOG_FMT(Debug::General, " textureId:%d\n", mTextureId);
268
269   // Check whether we need to refresh the vertex buffer.
270   if ( mRefreshMeshData )
271   {
272     const Vector3& actorSize = GetParent().GetSize( updateBufferIndex );
273     mGeometrySize.x = actorSize.x;
274     mGeometrySize.y = actorSize.y;
275
276     ImageRenderer::MeshType meshType = ImageRenderer::GRID_QUAD;
277
278     if ( !PreviousHintEnabled( Dali::ShaderEffect::HINT_GRID ) )
279     {
280       if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
281       {
282         meshType = ImageRenderer::NINE_PATCH;
283       }
284       else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
285       {
286         meshType = ImageRenderer::NINE_PATCH_NO_CENTER;
287       }
288       else
289       {
290         meshType = ImageRenderer::QUAD;
291       }
292     }
293     else
294     {
295       if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH )
296       {
297         meshType = ImageRenderer::GRID_NINE_PATCH;
298       }
299       else if ( mStyle == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER )
300       {
301         meshType = ImageRenderer::GRID_NINE_PATCH_NO_CENTER;
302       }
303       else
304       {
305         meshType = ImageRenderer::GRID_QUAD;
306       }
307     }
308
309     // Recalculate the mesh data in the next render
310     {
311       typedef MessageValue3< ImageRenderer, ImageRenderer::MeshType, Vector2, bool > DerivedType;
312
313       // Reserve some memory inside the render queue
314       unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
315
316       // Construct message in the render queue memory; note that delete should not be called on the return value
317       new (slot) DerivedType( mImageRenderer, &ImageRenderer::CalculateMeshData, meshType, mGeometrySize, mIsPixelAreaSet );
318     }
319
320     mRefreshMeshData = false;
321   }
322 }
323
324 bool ImageAttachment::IsFullyOpaque( BufferIndex updateBufferIndex )
325 {
326   /**
327    * Fully opaque when...
328    *   1) not using the alpha channel from the image data
329    *   2) the inherited color is not transparent nor semi-transparent
330    *   3) the shader doesn't require blending
331    */
332   bool opaque = mBitmapMetadata.IsFullyOpaque();
333
334   if ( opaque && mParent )
335   {
336     opaque = ( mParent->GetWorldColor(updateBufferIndex).a >= FULLY_OPAQUE );
337
338     if ( opaque && mShader != NULL )
339     {
340       opaque = !PreviousHintEnabled( Dali::ShaderEffect::HINT_BLENDING );
341     }
342   }
343
344   return opaque;
345 }
346
347 } // namespace SceneGraph
348
349 } // namespace Internal
350
351 } // namespace Dali