77c6732beccdacacb3c2860730429890377e1b23
[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
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
26 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
27 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
28 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
29
30 using namespace Dali;
31 using namespace Dali::Toolkit;
32 using namespace Dali::Toolkit::Text;
33
34 namespace
35 {
36   const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
37   const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f );
38   const Vector2 PADDING( 2.0f, 2.0f );
39 }
40
41 struct AtlasRenderer::Impl
42 {
43
44   struct MeshRecord
45   {
46     uint32_t mAtlasId;
47     MeshData mMeshData;
48   };
49
50   struct AtlasRecord
51   {
52     uint32_t mImageId;
53     Text::GlyphIndex mIndex;
54   };
55
56   struct MaxBlockSize
57   {
58     FontId mFontId;
59     Vector2 mNeededBlockSize;
60   };
61
62   Impl()
63   : mSlotDelegate( this )
64   {
65     mGlyphManager = AtlasGlyphManager::Get();
66     mFontClient = TextAbstraction::FontClient::Get();
67     mGlyphManager.SetAtlasSize( DEFAULT_ATLAS_SIZE, DEFAULT_BLOCK_SIZE );
68     mBasicShader = BasicShader::New();
69     mBGRAShader = BgraShader::New();
70   }
71
72   void AddGlyphs( const std::vector<Vector2>& positions, const Vector<GlyphInfo>& glyphs )
73   {
74     AtlasManager::AtlasSlot slot;
75     std::vector< MeshRecord > meshContainer;
76     FontId lastFontId = 0;
77
78     if (mImageIds.Size() )
79     {
80       // Unreference any currently used glyphs
81       RemoveText();
82     }
83
84     CalculateBlocksSize( glyphs );
85
86     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
87     {
88       GlyphInfo glyph = glyphs[ i ];
89
90       // No operation for white space
91       if ( glyph.width && glyph.height )
92       {
93         Vector2 position = positions[ i ];
94         MeshData newMeshData;
95         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
96
97         if ( slot.mImageId )
98         {
99           // This glyph already exists so generate mesh data plugging in our supplied position
100           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
101           mImageIds.PushBack( slot.mImageId );
102         }
103         else
104         {
105
106           // Select correct size for new atlas if needed....?
107           if ( lastFontId != glyph.fontId )
108           {
109             for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
110             {
111               if ( mBlockSizes[ j ].mFontId == glyph.fontId )
112               {
113                 mGlyphManager.SetAtlasSize( DEFAULT_ATLAS_SIZE, mBlockSizes[ j ].mNeededBlockSize );
114               }
115             }
116             lastFontId = glyph.fontId;
117           }
118
119           // Glyph doesn't currently exist in atlas so upload
120           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
121
122           // Locate a new slot for our glyph
123           mGlyphManager.Add( glyph, bitmap, slot );
124
125           // Generate mesh data for this quad, plugging in our supplied position
126           if ( slot.mImageId )
127           {
128             mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
129             mImageIds.PushBack( slot.mImageId );
130           }
131         }
132         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
133         StitchTextMesh( meshContainer, newMeshData, slot );
134       }
135     }
136
137     // For each MeshData object, create a mesh actor and add to the renderable actor
138     if ( meshContainer.size() )
139     {
140       for ( uint32_t i = 0; i < meshContainer.size(); ++i )
141       {
142         Mesh mesh = Mesh::New( meshContainer[ i ].mMeshData );
143         MeshActor actor = MeshActor::New( mesh );
144         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
145         actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );;
146
147         // Check to see what pixel format the shader should be
148         if ( mGlyphManager.GetPixelFormat( meshContainer[ i ].mAtlasId ) == Pixel::L8 )
149         {
150           actor.SetShaderEffect( mBasicShader );
151         }
152         else
153         {
154           actor.SetShaderEffect( mBGRAShader );
155         }
156
157         if ( i )
158         {
159           mActor.Add( actor );
160         }
161         else
162         {
163           mActor = actor;
164         }
165       }
166       mActor.OffStageSignal().Connect( mSlotDelegate, &AtlasRenderer::Impl::OffStageDisconnect );
167     }
168   }
169
170   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
171                        MeshData& newMeshData,
172                        AtlasManager::AtlasSlot& slot )
173   {
174     if ( slot.mImageId )
175     {
176       // Check to see if there's a mesh data object that references the same atlas ?
177       for ( uint32_t i = 0; i < meshContainer.size(); ++i )
178       {
179         if ( slot.mAtlasId == meshContainer[ i ].mAtlasId )
180         {
181           // Stitch the mesh to the existing mesh
182           mGlyphManager.StitchMesh( meshContainer[ i ].mMeshData, newMeshData );
183           return;
184         }
185       }
186
187       // No mesh data object currently exists that references this atlas, so create a new one
188       MeshRecord meshRecord;
189       meshRecord.mAtlasId = slot.mAtlasId;
190       meshRecord.mMeshData = newMeshData;
191       meshContainer.push_back( meshRecord );
192     }
193   }
194
195   // Unreference any glyphs that were used with this actor
196   void OffStageDisconnect( Dali::Actor actor )
197   {
198     RemoveText();
199   }
200
201   void RemoveText()
202   {
203     for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
204     {
205       mGlyphManager.Remove( mImageIds[ i ] );
206     }
207     mImageIds.Resize( 0 );
208   }
209
210   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
211   {
212     MaxBlockSize maxBlockSize;
213     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
214     {
215       // Get the fontId of this glyph and check to see if a max size exists?
216       FontId fontId = glyphs[ i ].fontId;
217       float paddedWidth = glyphs[ i ].width + PADDING.x;
218       float paddedHeight = glyphs[ i ].height + PADDING.y;
219       bool foundFont = false;
220
221       for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
222       {
223         if ( mBlockSizes[ j ].mFontId == fontId )
224         {
225           foundFont = true;
226           if ( mBlockSizes[ j ].mNeededBlockSize.x < paddedWidth )
227           {
228             mBlockSizes[ j ].mNeededBlockSize.x = paddedWidth;
229           }
230           if ( mBlockSizes[ j ].mNeededBlockSize.y < paddedHeight )
231           {
232             mBlockSizes[ j ].mNeededBlockSize.y = paddedHeight;
233           }
234         }
235       }
236
237       if ( !foundFont )
238       {
239         maxBlockSize.mNeededBlockSize = Vector2( paddedWidth, paddedHeight );
240         maxBlockSize.mFontId = fontId;
241         mBlockSizes.push_back( maxBlockSize );
242       }
243     }
244   }
245
246   RenderableActor mActor;                             ///< The actor parent which renders the text
247   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
248   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
249   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
250   SlotDelegate< AtlasRenderer::Impl > mSlotDelegate;  ///> Signal generated to unreference glyphs when renderable actor is removed
251   ShaderEffect mBasicShader;                          ///> Shader to render L8 glyphs
252   ShaderEffect mBGRAShader;                           ///> Shader to render BGRA glyphs
253   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
254 };
255
256 Text::RendererPtr AtlasRenderer::New()
257 {
258   return Text::RendererPtr( new AtlasRenderer() );
259 }
260
261 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
262 {
263
264   UnparentAndReset( mImpl->mActor );
265
266   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
267
268   if( numberOfGlyphs > 0 )
269   {
270     Vector<GlyphInfo> glyphs;
271     glyphs.Resize( numberOfGlyphs );
272
273     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
274
275     std::vector<Vector2> positions;
276     positions.resize( numberOfGlyphs );
277     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
278     mImpl->AddGlyphs( positions, glyphs );
279   }
280   return mImpl->mActor;
281 }
282
283 AtlasRenderer::AtlasRenderer()
284 {
285   mImpl = new Impl();
286
287 }
288
289 AtlasRenderer::~AtlasRenderer()
290 {
291   delete mImpl;
292 }