Revert to tizen branch.
[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 #include <dali/public-api/text-abstraction/text-abstraction.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
28 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
29 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
30 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
31 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shadow-shader.h>
32 #if defined(DEBUG_ENABLED)
33 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_ATLAS_RENDERER");
34 #endif
35
36 using namespace Dali;
37 using namespace Dali::Toolkit;
38 using namespace Dali::Toolkit::Text;
39
40 namespace
41 {
42   const float ZERO( 0.0f );
43   const float HALF( 0.5f );
44   const float ONE( 1.0f );
45   const float TWO( 2.0f );
46   const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
47   const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
48 }
49
50 struct AtlasRenderer::Impl : public ConnectionTracker
51 {
52
53   enum Style
54   {
55     STYLE_NORMAL,
56     STYLE_DROP_SHADOW
57   };
58
59   struct MeshRecord
60   {
61     Vector4 mColor;
62     uint32_t mAtlasId;
63     MeshData mMeshData;
64     FrameBufferImage mBuffer;
65     bool mIsUnderline;
66   };
67
68   struct Extent
69   {
70     float mBaseLine;
71     float mLeft;
72     float mRight;
73     float mUnderlinePosition;
74     float mUnderlineThickness;
75     uint32_t mMeshRecordIndex;
76   };
77
78   struct AtlasRecord
79   {
80     uint32_t mImageId;
81     Text::GlyphIndex mIndex;
82   };
83
84   struct MaxBlockSize
85   {
86     FontId mFontId;
87     uint32_t mNeededBlockWidth;
88     uint32_t mNeededBlockHeight;
89   };
90
91   Impl()
92   {
93     mGlyphManager = AtlasGlyphManager::Get();
94     mFontClient = TextAbstraction::FontClient::Get();
95     mBasicShader = BasicShader::New();
96     mBgraShader = BgraShader::New();
97     mBasicShadowShader = BasicShadowShader::New();
98
99     mFace.reserve( 6u );
100     mFace.push_back( 0 ); mFace.push_back( 2u ); mFace.push_back( 1u );
101     mFace.push_back( 1u ); mFace.push_back( 2u ); mFace.push_back( 3u );
102   }
103
104   void AddGlyphs( const std::vector<Vector2>& positions,
105                   const Vector<GlyphInfo>& glyphs,
106                   const Vector4& textColor,
107                   const Vector2& shadowOffset,
108                   const Vector4& shadowColor,
109                   bool underlineEnabled,
110                   const Vector4& underlineColor,
111                   float underlineHeight )
112   {
113     AtlasManager::AtlasSlot slot;
114     std::vector< MeshRecord > meshContainer;
115     Vector< Extent > extents;
116
117     float currentUnderlinePosition = ZERO;
118     float currentUnderlineThickness = underlineHeight;
119     uint32_t currentBlockSize = 0;
120     FontId lastFontId = 0;
121     Style style = STYLE_NORMAL;
122
123     if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
124     {
125       style = STYLE_DROP_SHADOW;
126     }
127
128     if ( mImageIds.Size() )
129     {
130       // Unreference any currently used glyphs
131       RemoveText();
132     }
133
134     CalculateBlocksSize( glyphs );
135
136     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
137     {
138       GlyphInfo glyph = glyphs[ i ];
139
140       // No operation for white space
141       if ( glyph.width && glyph.height )
142       {
143         // Are we still using the same fontId as previous
144         if ( glyph.fontId != lastFontId )
145         {
146           // We need to fetch fresh font underline metrics
147           FontMetrics fontMetrics;
148           mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
149           currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
150           float descender = ceil( fabsf( fontMetrics.descender ) );
151
152           if ( underlineHeight == ZERO )
153           {
154             currentUnderlineThickness = fontMetrics.underlineThickness;
155
156             // Ensure underline will be at least a pixel high
157             if ( currentUnderlineThickness < ONE )
158             {
159               currentUnderlineThickness = ONE;
160             }
161             else
162             {
163               currentUnderlineThickness = ceil( currentUnderlineThickness );
164             }
165           }
166
167           // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
168           if ( currentUnderlinePosition > descender )
169           {
170             currentUnderlinePosition = descender;
171           }
172           if ( ZERO == currentUnderlinePosition )
173           {
174             // Move offset down by one ( EFL behavior )
175             currentUnderlinePosition = ONE;
176           }
177         }
178
179         Vector2 position = positions[ i ];
180         MeshData newMeshData;
181         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
182
183         if ( slot.mImageId )
184         {
185           // This glyph already exists so generate mesh data plugging in our supplied position
186           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
187           mImageIds.PushBack( slot.mImageId );
188         }
189         else
190         {
191
192           // Select correct size for new atlas if needed....?
193           if ( lastFontId != glyph.fontId )
194           {
195             for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
196             {
197               if ( mBlockSizes[ j ].mFontId == glyph.fontId )
198               {
199                 currentBlockSize = j;
200                 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
201                                                DEFAULT_ATLAS_HEIGHT,
202                                                mBlockSizes[ j ].mNeededBlockWidth,
203                                                mBlockSizes[ j ].mNeededBlockHeight );
204               }
205             }
206           }
207
208           // Create a new image for the glyph
209           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
210
211           // Ensure that the next image will fit into the current block size
212           bool setSize = false;
213           if ( bitmap.GetWidth() > mBlockSizes[ currentBlockSize ].mNeededBlockWidth )
214           {
215             setSize = true;
216             mBlockSizes[ currentBlockSize ].mNeededBlockWidth = bitmap.GetWidth();
217           }
218           if ( bitmap.GetHeight() > mBlockSizes[ currentBlockSize ].mNeededBlockHeight )
219           {
220             setSize = true;
221             mBlockSizes[ currentBlockSize ].mNeededBlockHeight = bitmap.GetHeight();
222           }
223
224           if ( setSize )
225           {
226             mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
227                                            DEFAULT_ATLAS_HEIGHT,
228                                            mBlockSizes[ currentBlockSize ].mNeededBlockWidth,
229                                            mBlockSizes[ currentBlockSize ].mNeededBlockHeight );
230           }
231
232           // Locate a new slot for our glyph
233           mGlyphManager.Add( glyph, bitmap, slot );
234
235           // Generate mesh data for this quad, plugging in our supplied position
236           if ( slot.mImageId )
237           {
238             mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
239             mImageIds.PushBack( slot.mImageId );
240           }
241         }
242         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
243         StitchTextMesh( meshContainer,
244                         newMeshData,
245                         extents,
246                         textColor,
247                         position.y + glyph.yBearing,
248                         currentUnderlinePosition,
249                         currentUnderlineThickness,
250                         slot );
251        lastFontId = glyph.fontId;
252       }
253     }
254
255     if ( underlineEnabled )
256     {
257       // Check to see if any of the text needs an underline
258       GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
259     }
260
261     // For each MeshData object, create a mesh actor and add to the renderable actor
262     if ( meshContainer.size() )
263     {
264       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
265       {
266         MeshActor actor = MeshActor::New( Mesh::New( mIt->mMeshData ) );
267         actor.SetColor( mIt->mColor );
268
269         // Ensure that text rendering is unfiltered
270         actor.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
271         if ( mIt->mIsUnderline )
272         {
273           actor.SetColorMode( USE_OWN_COLOR );
274         }
275         else
276         {
277           actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
278         }
279
280         // Check to see what pixel format the shader should be
281         if ( mGlyphManager.GetPixelFormat( mIt->mAtlasId ) == Pixel::L8 )
282         {
283           // Create an effect if necessary
284           if ( style == STYLE_DROP_SHADOW )
285           {
286             actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
287           }
288           actor.SetShaderEffect( mBasicShader );
289         }
290         else
291         {
292           actor.SetShaderEffect( mBgraShader );
293         }
294
295         if ( mActor )
296         {
297           mActor.Add( actor );
298         }
299         else
300         {
301           mActor = actor;
302         }
303       }
304       mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
305     }
306 #if defined(DEBUG_ENABLED)
307     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
308     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
309                                                 metrics.mGlyphCount,
310                                                 metrics.mAtlasMetrics.mAtlasCount,
311                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
312     for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
313     {
314       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
315                                                  i + 1, i > 8 ? "" : " ",
316                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
317                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
318                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mHeight,
319                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockWidth,
320                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockHeight,
321                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
322                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
323     }
324 #endif
325   }
326
327   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
328                        MeshData& newMeshData,
329                        Vector< Extent >& extents,
330                        const Vector4& color,
331                        float baseLine,
332                        float underlinePosition,
333                        float underlineThickness,
334                        AtlasManager::AtlasSlot& slot )
335   {
336     if ( slot.mImageId )
337     {
338       MeshData::VertexContainer verts = newMeshData.GetVertices();
339       float left = verts[ 0 ].x;
340       float right = verts[ 1 ].x;
341
342       // Check to see if there's a mesh data object that references the same atlas ?
343       uint32_t index = 0;
344       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index )
345       {
346         if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
347         {
348           // Stitch the mesh to the existing mesh and adjust any extents
349           mGlyphManager.StitchMesh( mIt->mMeshData, newMeshData );
350           AdjustExtents( extents,
351                          meshContainer,
352                          index,
353                          left,
354                          right,
355                          baseLine,
356                          underlinePosition,
357                          underlineThickness );
358           return;
359         }
360       }
361
362       // No mesh data object currently exists that references this atlas, so create a new one
363       MeshRecord meshRecord;
364       meshRecord.mAtlasId = slot.mAtlasId;
365       meshRecord.mMeshData = newMeshData;
366       meshRecord.mColor = color;
367       meshRecord.mIsUnderline = false;
368       meshContainer.push_back( meshRecord );
369
370       // Adjust extents for this new meshrecord
371       AdjustExtents( extents,
372                      meshContainer,
373                      meshContainer.size() - 1u,
374                      left,
375                      right,
376                      baseLine,
377                      underlinePosition,
378                      underlineThickness );
379
380     }
381   }
382
383   void AdjustExtents( Vector< Extent >& extents,
384                       std::vector< MeshRecord>& meshRecords,
385                       uint32_t index,
386                       float left,
387                       float right,
388                       float baseLine,
389                       float underlinePosition,
390                       float underlineThickness )
391   {
392     bool foundExtent = false;
393     for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
394     {
395       if ( Equals( baseLine, eIt->mBaseLine ) )
396       {
397         foundExtent = true;
398         if ( left < eIt->mLeft )
399         {
400           eIt->mLeft = left;
401         }
402         if ( right > eIt->mRight  )
403         {
404           eIt->mRight = right;
405         }
406
407         if ( underlinePosition > eIt->mUnderlinePosition )
408         {
409           eIt->mUnderlinePosition = underlinePosition;
410         }
411         if ( underlineThickness > eIt->mUnderlineThickness )
412         {
413           eIt->mUnderlineThickness = underlineThickness;
414         }
415       }
416     }
417     if ( !foundExtent )
418     {
419       Extent extent;
420       extent.mLeft = left;
421       extent.mRight = right;
422       extent.mBaseLine = baseLine;
423       extent.mUnderlinePosition = underlinePosition;
424       extent.mUnderlineThickness = underlineThickness;
425       extent.mMeshRecordIndex = index;
426       extents.PushBack( extent );
427     }
428   }
429
430   // Unreference any glyphs that were used with this actor
431   void OffStageDisconnect( Dali::Actor actor )
432   {
433     RemoveText();
434   }
435
436   void RemoveText()
437   {
438     for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
439     {
440       mGlyphManager.Remove( mImageIds[ i ] );
441     }
442     mImageIds.Resize( 0 );
443   }
444
445   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
446   {
447     MaxBlockSize maxBlockSize;
448     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
449     {
450       FontId fontId = glyphs[ i ].fontId;
451       bool foundFont = false;
452       for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
453       {
454         if ( mBlockSizes[ j ].mFontId == fontId )
455         {
456           foundFont = true;
457         }
458       }
459       if ( !foundFont )
460       {
461         FontMetrics fontMetrics;
462         mFontClient.GetFontMetrics( fontId, fontMetrics );
463         maxBlockSize.mNeededBlockWidth = static_cast< uint32_t >( fontMetrics.height );
464         maxBlockSize.mNeededBlockHeight = static_cast< uint32_t >( fontMetrics.height );
465         maxBlockSize.mFontId = fontId;
466         mBlockSizes.push_back( maxBlockSize );
467       }
468     }
469   }
470
471   void GenerateUnderlines( std::vector< MeshRecord>& meshRecords,
472                            Vector< Extent >& extents,
473                            const Vector4& underlineColor,
474                            const Vector4& textColor )
475   {
476     MeshData newMeshData;
477     for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
478     {
479       MeshData::VertexContainer newVerts;
480       newVerts.reserve( 4u );
481       uint32_t index = eIt->mMeshRecordIndex;
482       Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId );
483
484       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
485       float u = HALF / uv.x;
486       float v = HALF / uv.y;
487       float thickness = eIt->mUnderlineThickness;
488       float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF );
489       float tlx = eIt->mLeft;
490       float brx = eIt->mRight;
491
492       newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine, ZERO ),
493                                             Vector2::ZERO,
494                                             Vector3::ZERO ) );
495
496       newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, ZERO ),
497                                             Vector2( u, ZERO ),
498                                             Vector3::ZERO ) );
499
500       newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, ZERO ),
501                                             Vector2( ZERO, v ),
502                                             Vector3::ZERO ) );
503
504       newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, ZERO ),
505                                             Vector2( u, v ),
506                                             Vector3::ZERO ) );
507
508       newMeshData.SetVertices( newVerts );
509       newMeshData.SetFaceIndices( mFace );
510
511       if ( underlineColor == textColor )
512       {
513         mGlyphManager.StitchMesh( meshRecords[ index ].mMeshData, newMeshData );
514       }
515       else
516       {
517         MeshRecord record;
518         newMeshData.SetMaterial( meshRecords[ index ].mMeshData.GetMaterial() );
519         newMeshData.SetHasNormals( true );
520         newMeshData.SetHasColor( false );
521         newMeshData.SetHasTextureCoords( true );
522         record.mMeshData = newMeshData;
523         record.mAtlasId = meshRecords[ index ].mAtlasId;
524         record.mColor = underlineColor;
525         record.mIsUnderline = true;
526         meshRecords.push_back( record );
527       }
528     }
529   }
530
531   MeshActor GenerateShadow( MeshRecord& meshRecord,
532                             const Vector2& shadowOffset,
533                             const Vector4& shadowColor )
534   {
535     // Scan vertex buffer to determine width and height of effect buffer needed
536     MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices();
537     float tlx = verts[ 0 ].x;
538     float tly = verts[ 0 ].y;
539     float brx = ZERO;
540     float bry = ZERO;
541
542     for ( uint32_t i = 0; i < verts.size(); ++i )
543     {
544       if ( verts[ i ].x < tlx )
545       {
546         tlx = verts[ i ].x;
547       }
548       if ( verts[ i ].y < tly )
549       {
550         tly = verts[ i ].y;
551       }
552       if ( verts[ i ].x > brx )
553       {
554         brx = verts[ i ].x;
555       }
556       if ( verts[ i ].y > bry )
557       {
558         bry = verts[ i ].y;
559       }
560     }
561
562     float width = brx - tlx;
563     float height = bry - tly;
564     float divWidth = TWO / width;
565     float divHeight = TWO / height;
566
567     // Create a buffer to render to
568     meshRecord.mBuffer = FrameBufferImage::New( width, height );
569
570     // Create a mesh actor to contain the post-effect render
571     MeshData::VertexContainer vertices;
572     MeshData::FaceIndices face;
573
574     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, ZERO ),
575                                           Vector2::ZERO,
576                                           Vector3::ZERO ) );
577
578     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, ZERO ),
579                                           Vector2( ONE, ZERO ),
580                                           Vector3::ZERO ) );
581
582     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, ZERO ),
583                                           Vector2( ZERO, ONE ),
584                                           Vector3::ZERO ) );
585
586     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, ZERO ),
587                                           Vector2::ONE,
588                                           Vector3::ZERO ) );
589
590     MeshData meshData;
591     Material newMaterial = Material::New("effect buffer");
592     newMaterial.SetDiffuseTexture( meshRecord.mBuffer );
593     meshData.SetMaterial( newMaterial );
594     meshData.SetVertices( vertices );
595     meshData.SetFaceIndices( mFace );
596     meshData.SetHasNormals( true );
597     meshData.SetHasColor( false );
598     meshData.SetHasTextureCoords( true );
599     MeshActor actor = MeshActor::New( Mesh::New( meshData ) );
600     actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
601     actor.SetShaderEffect( mBgraShader );
602     actor.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
603     actor.SetSortModifier( 0.1f ); // force behind main text
604
605     // Create a sub actor to render once with normalized vertex positions
606     MeshData newMeshData;
607     MeshData::VertexContainer newVerts;
608     MeshData::FaceIndices newFaces;
609     MeshData::FaceIndices faces = meshRecord.mMeshData.GetFaces();
610     for ( uint32_t i = 0; i < verts.size(); ++i )
611     {
612       MeshData::Vertex vertex = verts[ i ];
613       vertex.x = ( ( vertex.x - tlx ) * divWidth ) - ONE;
614       vertex.y = ( ( vertex.y - tly ) * divHeight ) - ONE;
615       newVerts.push_back( vertex );
616     }
617
618     // Reverse triangle winding order
619     uint32_t faceCount = faces.size() / 3;
620     for ( uint32_t i = 0; i < faceCount; ++i )
621     {
622       uint32_t index = i * 3;
623       newFaces.push_back( faces[ index + 2 ] );
624       newFaces.push_back( faces[ index + 1 ] );
625       newFaces.push_back( faces[ index ] );
626     }
627
628     newMeshData.SetMaterial( meshRecord.mMeshData.GetMaterial() );
629     newMeshData.SetVertices( newVerts );
630     newMeshData.SetFaceIndices( newFaces );
631     newMeshData.SetHasNormals( true );
632     newMeshData.SetHasColor( false );
633     newMeshData.SetHasTextureCoords( true );
634
635     MeshActor subActor = MeshActor::New( Mesh::New( newMeshData ) );
636     subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
637     subActor.SetColor( shadowColor );
638     subActor.SetShaderEffect( mBasicShadowShader );
639     subActor.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
640
641     // Create a render task to render the effect
642     RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask();
643     task.SetTargetFrameBuffer( meshRecord.mBuffer );
644     task.SetSourceActor( subActor );
645     task.SetClearEnabled( true );
646     task.SetClearColor( Vector4::ZERO );
647     task.SetExclusive( true );
648     task.SetRefreshRate( RenderTask::REFRESH_ONCE );
649     task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
650     actor.Add( subActor );
651     return actor;
652   }
653
654   void RenderComplete( RenderTask& renderTask )
655   {
656     // Disconnect and remove this single shot render task
657     renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
658     Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
659
660     // Get the actor used for render to buffer and remove it from the parent
661     Actor renderActor = renderTask.GetSourceActor();
662     if ( renderActor )
663     {
664       Actor parent = renderActor.GetParent();
665       if ( parent )
666       {
667         parent.Remove( renderActor );
668       }
669     }
670   }
671
672   RenderableActor mActor;                             ///< The actor parent which renders the text
673   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
674   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
675   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
676   ShaderEffect mBasicShader;                          ///> Shader used to render L8 glyphs
677   ShaderEffect mBgraShader;                           ///> Shader used to render BGRA glyphs
678   ShaderEffect mBasicShadowShader;                    ///> Shader used to render drop shadow into buffer
679   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
680   std::vector< MeshData::FaceIndex > mFace;           ///> Face indices for a quad
681 };
682
683 Text::RendererPtr AtlasRenderer::New()
684 {
685   return Text::RendererPtr( new AtlasRenderer() );
686 }
687
688 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
689 {
690
691   UnparentAndReset( mImpl->mActor );
692
693   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
694
695   if( numberOfGlyphs > 0 )
696   {
697     Vector<GlyphInfo> glyphs;
698     glyphs.Resize( numberOfGlyphs );
699
700     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
701
702     std::vector<Vector2> positions;
703     positions.resize( numberOfGlyphs );
704     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
705     mImpl->AddGlyphs( positions,
706                       glyphs,
707                       view.GetTextColor(),
708                       view.GetShadowOffset(),
709                       view.GetShadowColor(),
710                       view.IsUnderlineEnabled(),
711                       view.GetUnderlineColor(),
712                       view.GetUnderlineHeight() );
713   }
714   return mImpl->mActor;
715 }
716
717 AtlasRenderer::AtlasRenderer()
718 {
719   mImpl = new Impl();
720
721 }
722
723 AtlasRenderer::~AtlasRenderer()
724 {
725   delete mImpl;
726 }