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