a291096e545a0e87567c6251596b284d3d857c0b
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / public-api / text / rendering / basic / text-basic-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/public-api/text/rendering/basic/text-basic-renderer.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/dali.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/public-api/text/rendering/shaders/text-basic-shader.h>
26
27 using namespace Dali;
28 using namespace Dali::Toolkit;
29 using namespace Dali::Toolkit::Text;
30
31 #define NO_MESH 1
32
33 namespace
34 {
35
36 const std::size_t PADDING = 2; //< To avoid GL filtering artefacts
37
38 struct TextureCoordinates
39 {
40   TextureCoordinates()
41   : topLeft( 0.0f, 0.0f ),
42     topRight( 1.0f, 0.0f ),
43     bottomLeft( 0.0f, 1.0f ),
44     bottomRight( 1.0f, 1.0f )
45   {
46   }
47
48   Vector2 topLeft;
49   Vector2 topRight;
50   Vector2 bottomLeft;
51   Vector2 bottomRight;
52 };
53
54 struct AtlasHelperGlyph
55 {
56   AtlasHelperGlyph()
57   : fontId( 0 ),
58     index( 0 ),
59     xOffset( 0 ),
60     width( 0 ),
61     height( 0 )
62   {
63   }
64
65   AtlasHelperGlyph( FontId id,
66                     GlyphIndex glyphIndex,
67                     std::size_t offset,
68                     std::size_t widthPixels,
69                     std::size_t heightPixels )
70   : fontId( id ),
71     index( glyphIndex ),
72     xOffset( offset ),
73     width( widthPixels ),
74     height( heightPixels )
75   {
76   }
77
78   FontId fontId;
79   GlyphIndex index;
80   std::size_t xOffset;
81   std::size_t width;
82   std::size_t height;
83   TextureCoordinates coords;
84 };
85
86 struct AtlasHelper
87 {
88   AtlasHelper()
89   : mWidth( 0.0f ),
90     mHeight( 0.0f )
91   {
92     mFontClient = TextAbstraction::FontClient::Get();
93   }
94
95   void Reset()
96   {
97     mWidth = 0.0f;
98     mHeight = 0.0f;
99     mGlyphs.clear();
100   }
101
102   void Reserve( std::size_t size )
103   {
104     mGlyphs.reserve( size );
105   }
106
107   bool GlyphFound( FontId fontId, GlyphIndex index ) const
108   {
109     for( unsigned int i=0; i<mGlyphs.size(); ++i )
110     {
111       const AtlasHelperGlyph& glyph = mGlyphs[i];
112
113       if( fontId == glyph.fontId &&
114           index  == glyph.index )
115       {
116         return true;
117       }
118     }
119
120     return false;
121   }
122
123   void AddGlyph( const GlyphInfo& glyphInfo )
124   {
125     mGlyphs.push_back( AtlasHelperGlyph( glyphInfo.fontId, glyphInfo.index, mWidth, glyphInfo.width, glyphInfo.height ) );
126
127     mWidth += glyphInfo.width + PADDING;
128     if( mHeight < glyphInfo.height + PADDING )
129     {
130       mHeight = glyphInfo.height + PADDING;
131     }
132   }
133
134   Atlas CreateAtlas()
135   {
136     Atlas atlas = Atlas::New( mWidth, mHeight, Pixel::L8 );
137
138     for( unsigned int i=0; i<mGlyphs.size(); ++i )
139     {
140       AtlasHelperGlyph& glyph = mGlyphs[i];
141       BitmapImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
142       atlas.Upload( bitmap, glyph.xOffset, 0 );
143
144       TextureCoordinates& coords = glyph.coords;
145       coords.topLeft.x     = static_cast<float>(glyph.xOffset) / static_cast<float>(mWidth);
146       coords.topLeft.y     = 0.0f;
147       coords.topRight.x    = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(mWidth);
148       coords.topRight.y    = 0.0f;
149       coords.bottomLeft.x  = static_cast<float>(glyph.xOffset) / static_cast<float>(mWidth);
150       coords.bottomLeft.y  = static_cast<float>(glyph.height) / static_cast<float>(mHeight);
151       coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(mWidth);
152       coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(mHeight);
153     }
154
155     return atlas;
156   }
157
158   void GetTextureCoordinates( FontId fontId, GlyphIndex index, TextureCoordinates& coords )
159   {
160     for( unsigned int i=0; i<mGlyphs.size(); ++i )
161     {
162       const AtlasHelperGlyph& glyph = mGlyphs[i];
163
164       if( fontId == glyph.fontId &&
165           index  == glyph.index )
166       {
167         coords = glyph.coords;
168         return;
169       }
170     }
171   }
172
173 private: // Data
174
175   std::size_t mWidth;
176   std::size_t mHeight;
177
178   std::vector<AtlasHelperGlyph> mGlyphs;
179
180   TextAbstraction::FontClient mFontClient;
181 };
182
183 } // unnamed namespace
184
185 struct BasicRenderer::Impl
186 {
187   /**
188    * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
189    *
190    * @param[in] glyphs The glyphs to upload.
191    */
192   Atlas CreateAtlas( const Vector<GlyphInfo>& glyphs )
193   {
194     AtlasHelper& helper = mAtlasHelper;
195
196     // Clear previous atlas
197     helper.Reset();
198     helper.Reserve( glyphs.Count() );
199
200     for( unsigned int i=0; i<glyphs.Count(); ++i )
201     {
202       float width  = glyphs[i].width;
203       float height = glyphs[i].height;
204
205       if( width > 0 &&
206           height > 0 ) // skip whitespace
207       {
208         if( !helper.GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
209         {
210           helper.AddGlyph( glyphs[i] );
211         }
212       }
213     }
214
215     // Uploads the bitmaps to Dali
216     return helper.CreateAtlas();
217   }
218
219
220 #if ! defined( NO_MESH )
221   /**
222    * @brief Helper method to create a mesh with one quad per glyph.
223    *
224    * @param[in] glyphs The glyphs to display.
225    * @param[in] positions The 2D positions of the glyphs.
226    * @param[in] image The material uses this as a diffuse texture.
227    */
228   Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Image image )
229   {
230     MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
231
232     MeshData::FaceIndices faces;
233     faces.reserve( 6 * glyphs.Count() ); // 2 triangles per quad
234
235     for( unsigned int i=0; i<glyphs.Count(); ++i )
236     {
237       float width  = glyphs[i].width;
238       float height = glyphs[i].height;
239
240       if( width > 0 &&
241           height > 0 ) // skip whitespace
242       {
243         const Vector2& position = positions[i];
244
245         TextureCoordinates coords;
246         mAtlasHelper.GetTextureCoordinates( glyphs[i].fontId, glyphs[i].index, coords );
247
248         vertices[ i*4 + 0 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 0.0f*height, 0.0f ), coords.topLeft,     Vector3( 1.0f, 0.0f, 0.0f ) );
249         vertices[ i*4 + 1 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 0.0f*height, 0.0f ), coords.topRight,    Vector3( 1.0f, 1.0f, 0.0f ) );
250         vertices[ i*4 + 2 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomLeft,  Vector3( 0.0f, 1.0f, 0.0f ) );
251         vertices[ i*4 + 3 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomRight, Vector3( 0.0f, 0.0f, 1.0f ) );
252
253         faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
254         faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
255       }
256     }
257
258     Material material = Material::New( "Material" );
259     material.SetDiffuseTexture( image );
260
261     // Create the mesh data from the vertices and faces
262     MeshData meshData;
263     meshData.SetHasColor( false );
264     meshData.SetMaterial( material );
265     meshData.SetVertices( vertices );
266     meshData.SetFaceIndices( faces );
267
268     // Create a mesh from the data
269     Dali::Mesh mesh = Mesh::New( meshData );
270     return mesh;
271   }
272 #endif
273
274   RenderableActor mActor; ///< The actor which renders the text
275
276   AtlasHelper mAtlasHelper; ///< A helper class for storing atlas positions etc.
277 };
278
279 Text::RendererPtr BasicRenderer::New()
280 {
281   return Text::RendererPtr( new BasicRenderer() );
282 }
283
284 RenderableActor BasicRenderer::Render( Text::ViewInterface& view )
285 {
286   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
287
288   if( numberOfGlyphs > 0 )
289   {
290     Vector<GlyphInfo> glyphs;
291     glyphs.Resize( numberOfGlyphs );
292
293     view.GetGlyphs( 0, &glyphs[0], numberOfGlyphs );
294
295     std::vector<Vector2> positions;
296     positions.resize( numberOfGlyphs );
297     view.GetGlyphPositions( 0, &positions[0], numberOfGlyphs );
298
299     Atlas atlas = mImpl->CreateAtlas( glyphs );
300
301 #if ! defined( NO_MESH )
302     MeshActor actor = MeshActor::New( mImpl->CreateMesh( glyphs, positions, atlas ) );
303     actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
304     actor.SetAffectedByLighting( false );
305
306     ShaderEffect shader = BasicShader::New();
307     actor.SetShaderEffect( shader );
308
309     mImpl->mActor = actor;
310 #endif
311   }
312
313   return mImpl->mActor;
314 }
315
316 BasicRenderer::BasicRenderer()
317 {
318   mImpl = new Impl();
319 }
320
321 BasicRenderer::~BasicRenderer()
322 {
323   delete mImpl;
324 }