Fixes for text related actors after new size negotiation.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-renderer.cpp
1 /*
2  * Copyright (c) 2015 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-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/dali.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
27 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
28 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
29 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
30 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shadow-shader.h>
31 #if defined(DEBUG_ENABLED)
32 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_ATLAS_RENDERER");
33 #endif
34
35 using namespace Dali;
36 using namespace Dali::Toolkit;
37 using namespace Dali::Toolkit::Text;
38
39 namespace
40 {
41   const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
42   const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f );
43   const Vector2 PADDING( 4.0f, 4.0f ); // Allow for variation in font glyphs
44 }
45
46 struct AtlasRenderer::Impl : public ConnectionTracker
47 {
48
49   enum Style
50   {
51     STYLE_NORMAL,
52     STYLE_DROP_SHADOW
53   };
54
55   struct MeshRecord
56   {
57     uint32_t mAtlasId;
58     MeshData mMeshData;
59     FrameBufferImage mBuffer;
60   };
61
62   struct AtlasRecord
63   {
64     uint32_t mImageId;
65     Text::GlyphIndex mIndex;
66   };
67
68   struct MaxBlockSize
69   {
70     FontId mFontId;
71     Vector2 mNeededBlockSize;
72   };
73
74   Impl()
75   {
76     mGlyphManager = AtlasGlyphManager::Get();
77     mFontClient = TextAbstraction::FontClient::Get();
78     mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, DEFAULT_BLOCK_SIZE );
79     mBasicShader = BasicShader::New();
80     mBgraShader = BgraShader::New();
81     mBasicShadowShader = BasicShadowShader::New();
82   }
83
84   void AddGlyphs( const std::vector<Vector2>& positions,
85                   const Vector<GlyphInfo>& glyphs,
86                   const Vector2& shadowOffset,
87                   const Vector4& shadowColor )
88   {
89     AtlasManager::AtlasSlot slot;
90     std::vector< MeshRecord > meshContainer;
91     FontId lastFontId = 0;
92     Style style = STYLE_NORMAL;
93
94     if ( shadowOffset.x > 0.0f || shadowOffset.y > 0.0f )
95     {
96       style = STYLE_DROP_SHADOW;
97     }
98
99     if ( mImageIds.Size() )
100     {
101       // Unreference any currently used glyphs
102       RemoveText();
103     }
104
105     CalculateBlocksSize( glyphs );
106
107     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
108     {
109       GlyphInfo glyph = glyphs[ i ];
110
111       // No operation for white space
112       if ( glyph.width && glyph.height )
113       {
114         Vector2 position = positions[ i ];
115         MeshData newMeshData;
116         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
117
118         if ( slot.mImageId )
119         {
120           // This glyph already exists so generate mesh data plugging in our supplied position
121           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
122           mImageIds.PushBack( slot.mImageId );
123         }
124         else
125         {
126
127           // Select correct size for new atlas if needed....?
128           if ( lastFontId != glyph.fontId )
129           {
130             for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
131             {
132               if ( mBlockSizes[ j ].mFontId == glyph.fontId )
133               {
134                 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, mBlockSizes[ j ].mNeededBlockSize );
135               }
136             }
137             lastFontId = glyph.fontId;
138           }
139
140           // Glyph doesn't currently exist in atlas so upload
141           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
142
143           // Locate a new slot for our glyph
144           mGlyphManager.Add( glyph, bitmap, slot );
145
146           // Generate mesh data for this quad, plugging in our supplied position
147           if ( slot.mImageId )
148           {
149             mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
150             mImageIds.PushBack( slot.mImageId );
151           }
152         }
153         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
154         StitchTextMesh( meshContainer, newMeshData, slot );
155       }
156     }
157
158     // For each MeshData object, create a mesh actor and add to the renderable actor
159     if ( meshContainer.size() )
160     {
161       for ( uint32_t i = 0; i < meshContainer.size(); ++i )
162       {
163         MeshActor actor = MeshActor::New( Mesh::New( meshContainer[ i ].mMeshData ) );
164         actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
165
166         // Check to see what pixel format the shader should be
167         if ( mGlyphManager.GetPixelFormat( meshContainer[ i ].mAtlasId ) == Pixel::L8 )
168         {
169           // Create an effect if necessary
170           if ( style == STYLE_DROP_SHADOW )
171           {
172             actor.Add( GenerateEffect( meshContainer[ i ], shadowOffset, shadowColor ) );
173           }
174           actor.SetShaderEffect( mBasicShader );
175         }
176         else
177         {
178           actor.SetShaderEffect( mBgraShader );
179         }
180
181         if ( i )
182         {
183           mActor.Add( actor );
184         }
185         else
186         {
187           mActor = actor;
188         }
189       }
190       mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
191     }
192 #if defined(DEBUG_ENABLED)
193     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
194     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
195                                                 metrics.mGlyphCount,
196                                                 metrics.mAtlasMetrics.mAtlasCount,
197                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
198     for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
199     {
200       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
201                                                  i + 1, i > 8 ? "" : " ",
202                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
203                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mWidth,
204                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mHeight,
205                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlockWidth,
206                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlockHeight,
207                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
208                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
209     }
210 #endif
211   }
212
213   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
214                        MeshData& newMeshData,
215                        AtlasManager::AtlasSlot& slot )
216   {
217     if ( slot.mImageId )
218     {
219       // Check to see if there's a mesh data object that references the same atlas ?
220       for ( uint32_t i = 0; i < meshContainer.size(); ++i )
221       {
222         if ( slot.mAtlasId == meshContainer[ i ].mAtlasId )
223         {
224           // Stitch the mesh to the existing mesh
225           mGlyphManager.StitchMesh( meshContainer[ i ].mMeshData, newMeshData );
226           return;
227         }
228       }
229
230       // No mesh data object currently exists that references this atlas, so create a new one
231       MeshRecord meshRecord;
232       meshRecord.mAtlasId = slot.mAtlasId;
233       meshRecord.mMeshData = newMeshData;
234       meshContainer.push_back( meshRecord );
235     }
236   }
237
238   // Unreference any glyphs that were used with this actor
239   void OffStageDisconnect( Dali::Actor actor )
240   {
241     RemoveText();
242   }
243
244   void RemoveText()
245   {
246     for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
247     {
248       mGlyphManager.Remove( mImageIds[ i ] );
249     }
250     mImageIds.Resize( 0 );
251   }
252
253   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
254   {
255     MaxBlockSize maxBlockSize;
256     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
257     {
258       // Get the fontId of this glyph and check to see if a max size exists?
259       FontId fontId = glyphs[ i ].fontId;
260       float paddedWidth = glyphs[ i ].width + PADDING.x;
261       float paddedHeight = glyphs[ i ].height + PADDING.y;
262       bool foundFont = false;
263
264       for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
265       {
266         if ( mBlockSizes[ j ].mFontId == fontId )
267         {
268           foundFont = true;
269           if ( mBlockSizes[ j ].mNeededBlockSize.x < paddedWidth )
270           {
271             mBlockSizes[ j ].mNeededBlockSize.x = paddedWidth;
272           }
273           if ( mBlockSizes[ j ].mNeededBlockSize.y < paddedHeight )
274           {
275             mBlockSizes[ j ].mNeededBlockSize.y = paddedHeight;
276           }
277         }
278       }
279
280       if ( !foundFont )
281       {
282         maxBlockSize.mNeededBlockSize = Vector2( paddedWidth, paddedHeight );
283         maxBlockSize.mFontId = fontId;
284         mBlockSizes.push_back( maxBlockSize );
285       }
286     }
287   }
288
289   MeshActor GenerateEffect( MeshRecord& meshRecord,
290                             const Vector2& shadowOffset,
291                             const Vector4& shadowColor )
292   {
293     // Scan vertex buffer to determine width and height of effect buffer needed
294     MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices();
295     const float zero = 0.0f;
296     const float one = 1.0f;
297     float tlx = verts[ 0 ].x;
298     float tly = verts[ 0 ].y;
299     float brx = zero;
300     float bry = zero;
301
302     for ( uint32_t i = 0; i < verts.size(); ++i )
303     {
304       if ( verts[ i ].x < tlx )
305       {
306         tlx = verts[ i ].x;
307       }
308       if ( verts[ i ].y < tly )
309       {
310         tly = verts[ i ].y;
311       }
312       if ( verts[ i ].x > brx )
313       {
314         brx = verts[ i ].x;
315       }
316       if ( verts[ i ].y > bry )
317       {
318         bry = verts[ i ].y;
319       }
320     }
321
322     float width = brx - tlx;
323     float height = bry - tly;
324     float divWidth = 2.0f / width;
325     float divHeight = 2.0f / height;
326
327     // Create a buffer to render to
328     // TODO bloom style filter from this buffer
329     meshRecord.mBuffer = FrameBufferImage::New( width, height );
330
331     // Create a mesh actor to contain the post-effect render
332     MeshData::VertexContainer vertices;
333     MeshData::FaceIndices face;
334
335     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, zero ),
336                                           Vector2( zero, zero ),
337                                           Vector3( zero, zero, zero ) ) );
338
339     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, zero ),
340                                           Vector2( one, zero ),
341                                           Vector3( zero, zero, zero ) ) );
342
343     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, zero ),
344                                           Vector2( zero, one ),
345                                           Vector3( zero, zero, zero ) ) );
346
347     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, zero ),
348                                           Vector2( one, one ),
349                                           Vector3( zero, zero, zero ) ) );
350
351     face.push_back( 0 ); face.push_back( 2u ); face.push_back( 1u );
352     face.push_back( 1u ); face.push_back( 2u ); face.push_back( 3u );
353
354     MeshData meshData;
355     Material newMaterial = Material::New("effect buffer");
356     newMaterial.SetDiffuseTexture( meshRecord.mBuffer );
357     meshData.SetMaterial( newMaterial );
358     meshData.SetVertices( vertices );
359     meshData.SetFaceIndices( face );
360     meshData.SetHasNormals( true );
361     meshData.SetHasColor( false );
362     meshData.SetHasTextureCoords( true );
363     MeshActor actor = MeshActor::New( Mesh::New( meshData ) );
364     actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
365     actor.SetShaderEffect( mBgraShader );
366     actor.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
367     actor.SetSortModifier( one ); // force behind main text
368
369     // Create a sub actor to render once with normalized vertex positions
370     MeshData newMeshData;
371     MeshData::VertexContainer newVerts;
372     MeshData::FaceIndices newFaces;
373     MeshData::FaceIndices faces = meshRecord.mMeshData.GetFaces();
374     for ( uint32_t i = 0; i < verts.size(); ++i )
375     {
376       MeshData::Vertex vertex = verts[ i ];
377       vertex.x = ( ( vertex.x - tlx ) * divWidth ) - one;
378       vertex.y = ( ( vertex.y - tly ) * divHeight ) - one;
379       newVerts.push_back( vertex );
380     }
381
382     // Reverse triangle winding order
383     uint32_t faceCount = faces.size() / 3;
384     for ( uint32_t i = 0; i < faceCount; ++i )
385     {
386       uint32_t index = i * 3;
387       newFaces.push_back( faces[ index + 2 ] );
388       newFaces.push_back( faces[ index + 1 ] );
389       newFaces.push_back( faces[ index ] );
390     }
391
392     newMeshData.SetMaterial( meshRecord.mMeshData.GetMaterial() );
393     newMeshData.SetVertices( newVerts );
394     newMeshData.SetFaceIndices( newFaces );
395     newMeshData.SetHasNormals( true );
396     newMeshData.SetHasColor( false );
397     newMeshData.SetHasTextureCoords( true );
398
399     MeshActor subActor = MeshActor::New( Mesh::New( newMeshData ) );
400     subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
401     subActor.SetColor( shadowColor );
402     subActor.SetShaderEffect( mBasicShadowShader );
403     subActor.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
404
405     // Create a render task to render the effect
406     RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask();
407     task.SetTargetFrameBuffer( meshRecord.mBuffer );
408     task.SetSourceActor( subActor );
409     task.SetClearEnabled( true );
410     task.SetClearColor( Vector4::ZERO );
411     task.SetExclusive( true );
412     task.SetRefreshRate( RenderTask::REFRESH_ONCE );
413     task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
414     actor.Add( subActor );
415     return actor;
416   }
417
418   void RenderComplete( RenderTask& renderTask )
419   {
420     // Disconnect and remove this single shot render task
421     renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
422     Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
423
424     // Get the actor used for render to buffer and remove it from the parent
425     Actor renderActor = renderTask.GetSourceActor();
426     if ( renderActor )
427     {
428       Actor parent = renderActor.GetParent();
429       if ( parent )
430       {
431         parent.Remove( renderActor );
432       }
433     }
434   }
435
436   RenderableActor mActor;                             ///< The actor parent which renders the text
437   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
438   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
439   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
440   ShaderEffect mBasicShader;                          ///> Shader used to render L8 glyphs
441   ShaderEffect mBgraShader;                           ///> Shader used to render BGRA glyphs
442   ShaderEffect mBasicShadowShader;                    ///> Shader used to render drop shadow into buffer
443   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
444 };
445
446 Text::RendererPtr AtlasRenderer::New()
447 {
448   return Text::RendererPtr( new AtlasRenderer() );
449 }
450
451 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
452 {
453
454   UnparentAndReset( mImpl->mActor );
455
456   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
457
458   if( numberOfGlyphs > 0 )
459   {
460     Vector<GlyphInfo> glyphs;
461     glyphs.Resize( numberOfGlyphs );
462
463     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
464
465     std::vector<Vector2> positions;
466     positions.resize( numberOfGlyphs );
467     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
468     mImpl->AddGlyphs( positions,
469                       glyphs,
470                       view.GetShadowOffset(),
471                       view.GetShadowColor() );
472   }
473   return mImpl->mActor;
474 }
475
476 AtlasRenderer::AtlasRenderer()
477 {
478   mImpl = new Impl();
479
480 }
481
482 AtlasRenderer::~AtlasRenderer()
483 {
484   delete mImpl;
485 }