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