0ed74bdd41723f8a32e646281f71e0dece64da4c
[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   Impl()
57   : mSlotDelegate( this )
58   {
59     mGlyphManager = AtlasGlyphManager::Get();
60     mFontClient = TextAbstraction::FontClient::Get();
61     mGlyphManager.SetAtlasSize( DEFAULT_ATLAS_SIZE, DEFAULT_BLOCK_SIZE );
62     mBasicShader = BasicShader::New();
63     mBGRAShader = BgraShader::New();
64   }
65
66   void AddGlyphs( const std::vector<Vector2>& positions, const Vector<GlyphInfo>& glyphs )
67   {
68     AtlasManager::AtlasSlot slot;
69     std::vector< MeshRecord > meshContainer;
70
71     if (mImageIds.Size() )
72     {
73       // Unreference any currently used glyphs
74       RemoveText();
75     }
76
77     // Set the block size to use, if an atlas is created
78     mGlyphManager.SetAtlasSize( DEFAULT_ATLAS_SIZE, CalculateBlockSize( glyphs ) );
79
80     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
81     {
82       GlyphInfo glyph = glyphs[ i ];
83
84       // No operation for white space
85       if ( glyph.width && glyph.height )
86       {
87         Vector2 position = positions[ i ];
88         MeshData newMeshData;
89         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
90
91         if ( slot.mImageId )
92         {
93           // This glyph already exists so generate mesh data plugging in our supplied position
94           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
95           mImageIds.PushBack( slot.mImageId );
96         }
97         else
98         {
99           // Glyph doesn't currently exist in atlas so upload
100           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
101
102           // Locate a new slot for our glyph
103           mGlyphManager.Add( glyph, bitmap, slot );
104
105           // Generate mesh data for this quad, plugging in our supplied position
106           if ( slot.mImageId )
107           {
108             mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
109             mImageIds.PushBack( slot.mImageId );
110           }
111         }
112         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
113         StitchTextMesh( meshContainer, newMeshData, slot );
114       }
115     }
116
117     // For each MeshData object, create a mesh actor and add to the renderable actor
118     if ( meshContainer.size() )
119     {
120       for ( uint32_t i = 0; i < meshContainer.size(); ++i )
121       {
122         Mesh mesh = Mesh::New( meshContainer[ i ].mMeshData );
123         MeshActor actor = MeshActor::New( mesh );
124         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
125         actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );;
126
127         // Check to see what pixel format the shader should be
128         if ( mGlyphManager.GetPixelFormat( meshContainer[ i ].mAtlasId ) == Pixel::L8 )
129         {
130           actor.SetShaderEffect( mBasicShader );
131         }
132         else
133         {
134           actor.SetShaderEffect( mBGRAShader );
135         }
136
137         if ( i )
138         {
139           mActor.Add( actor );
140         }
141         else
142         {
143           mActor = actor;
144         }
145       }
146       mActor.OffStageSignal().Connect( mSlotDelegate, &AtlasRenderer::Impl::OffStageDisconnect );
147     }
148   }
149
150   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
151                        MeshData& newMeshData,
152                        AtlasManager::AtlasSlot& slot )
153   {
154     if ( slot.mImageId )
155     {
156       // Check to see if there's a mesh data object that references the same atlas ?
157       for ( uint32_t i = 0; i < meshContainer.size(); ++i )
158       {
159         if ( slot.mAtlasId == meshContainer[ i ].mAtlasId )
160         {
161           // Stitch the mesh to the existing mesh
162           mGlyphManager.StitchMesh( meshContainer[ i ].mMeshData, newMeshData );
163           return;
164         }
165       }
166
167       // No mesh data object currently exists that references this atlas, so create a new one
168       MeshRecord meshRecord;
169       meshRecord.mAtlasId = slot.mAtlasId;
170       meshRecord.mMeshData = newMeshData;
171       meshContainer.push_back( meshRecord );
172     }
173   }
174
175   // Unreference any glyphs that were used with this actor
176   void OffStageDisconnect( Dali::Actor actor )
177   {
178     RemoveText();
179   }
180
181   void RemoveText()
182   {
183     for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
184     {
185       mGlyphManager.Remove( mImageIds[ i ] );
186     }
187     mImageIds.Resize( 0 );
188   }
189
190   Vector2 CalculateBlockSize( const Vector<GlyphInfo>& glyphs )
191   {
192     float maxWidth = glyphs[ 0 ].width;
193     float maxHeight = glyphs[ 0 ].height;
194
195     for ( uint32_t i = 1u; i < glyphs.Size(); ++i )
196     {
197       if ( maxWidth < glyphs[ i ].width )
198       {
199         maxWidth = glyphs[ i ].width;
200       }
201       if ( maxHeight < glyphs[ i ].height )
202       {
203         maxHeight = glyphs[ i ].height;
204       }
205     }
206     return Vector2( maxWidth + PADDING.x, maxHeight + PADDING.y );
207   }
208
209   RenderableActor mActor;                             ///< The actor parent which renders the text
210   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
211   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
212   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
213   SlotDelegate< AtlasRenderer::Impl > mSlotDelegate;  ///> Signal generated to unreference glyphs when renderable actor is removed
214   ShaderEffect mBasicShader;                          ///> Shader to render L8 glyphs
215   ShaderEffect mBGRAShader;                           ///> Shader to render BGRA glyphs
216 };
217
218 Text::RendererPtr AtlasRenderer::New()
219 {
220   return Text::RendererPtr( new AtlasRenderer() );
221 }
222
223 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
224 {
225
226   UnparentAndReset( mImpl->mActor );
227
228   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
229
230   if( numberOfGlyphs > 0 )
231   {
232     Vector<GlyphInfo> glyphs;
233     glyphs.Resize( numberOfGlyphs );
234
235     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
236
237     std::vector<Vector2> positions;
238     positions.resize( numberOfGlyphs );
239     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
240     mImpl->AddGlyphs( positions, glyphs );
241   }
242   return mImpl->mActor;
243 }
244
245 AtlasRenderer::AtlasRenderer()
246 {
247   mImpl = new Impl();
248
249 }
250
251 AtlasRenderer::~AtlasRenderer()
252 {
253   delete mImpl;
254 }