DALi Version 1.2.50
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / vector-based / vector-based-renderer.cpp
1 /*
2  * Copyright (c) 2016 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/vector-based/vector-based-renderer.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/rendering/geometry.h>
23 #include <dali/public-api/rendering/renderer.h>
24 #include <dali/devel-api/text-abstraction/font-client.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/text/glyph-run.h>
29 #include <dali-toolkit/internal/text/text-view.h>
30 #include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h>
31 #include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
32 #include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h>
33
34 using namespace Dali;
35 using namespace Dali::Toolkit;
36 using namespace Dali::Toolkit::Text;
37
38 namespace
39 {
40
41 #if defined(DEBUG_ENABLED)
42   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
43 #endif
44
45 const float DEFAULT_POINT_SIZE = 13.f;
46
47 struct Vertex2D
48 {
49   float x;
50   float y;
51   float u;
52   float v;
53   Vector4 color;
54 };
55
56 void AddVertex( Vector<Vertex2D>& vertices, float x, float y, float u, float v, const Vector4& color )
57 {
58   Vertex2D meshVertex;
59   meshVertex.x = x;
60   meshVertex.y = y;
61   meshVertex.u = u;
62   meshVertex.v = v;
63   meshVertex.color = color;
64   vertices.PushBack( meshVertex );
65 }
66
67 void AddTriangle( Vector<unsigned short>& indices, unsigned int v0, unsigned int v1, unsigned int v2 )
68 {
69   indices.PushBack( v0 );
70   indices.PushBack( v1 );
71   indices.PushBack( v2 );
72 }
73
74 bool CreateGeometry( const Vector<GlyphInfo>& glyphs,
75                      unsigned int numberOfGlyphs,
76                      const Vector<Vector2>& positions,
77                      float xOffset,
78                      float yOffset,
79                      VectorBlobAtlas& atlas,
80                      Dali::TextAbstraction::FontClient& fontClient,
81                      Vector< Vertex2D >& vertices,
82                      Vector< unsigned short >& indices,
83                      const Vector4* const colorsBuffer,
84                      const ColorIndex* const colorIndicesBuffer,
85                      const Vector4& defaultColor )
86 {
87   // Whether the default color is used.
88   const bool useDefaultColor = ( NULL == colorsBuffer );
89
90   bool atlasFull( false );
91
92   for( unsigned int i=0, idx=0; i<numberOfGlyphs && !atlasFull; ++i )
93   {
94     if( glyphs[i].width  > 0 &&
95         glyphs[i].height > 0 )
96     {
97       bool foundBlob( true );
98
99       BlobCoordinate blobCoords[4];
100
101       if( ! atlas.FindGlyph( glyphs[i].fontId, glyphs[i].index, blobCoords )  )
102       {
103         // Add blob to atlas
104         VectorBlob* blob( NULL );
105         unsigned int blobLength( 0 );
106         unsigned int nominalWidth( 0 );
107         unsigned int nominalHeight( 0 );
108         fontClient.CreateVectorBlob( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight );
109
110         if( 0 != blobLength )
111         {
112           bool glyphAdded = atlas.AddGlyph( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight, blobCoords );
113
114           foundBlob = glyphAdded;
115           atlasFull = !glyphAdded;
116         }
117         else
118         {
119           foundBlob = false;
120         }
121       }
122
123       if( foundBlob )
124       {
125         // Get the color of the character.
126         const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i );
127         const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u );
128
129         const float x1( xOffset + positions[i].x );
130         const float x2( xOffset + positions[i].x + glyphs[i].width );
131         const float y1( yOffset + positions[i].y );
132         const float y2( yOffset + positions[i].y + glyphs[i].height );
133
134         AddVertex( vertices, x1, y2, blobCoords[0].u, blobCoords[0].v, color );
135         AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v, color );
136         AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v, color );
137         AddTriangle( indices, idx, idx+1, idx+2 );
138         idx+=3;
139
140         AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v, color );
141         AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v, color );
142         AddVertex( vertices, x2, y1, blobCoords[3].u, blobCoords[3].v, color );
143         AddTriangle( indices, idx, idx+1, idx+2 );
144         idx+=3;
145       }
146     }
147   }
148
149   // If the atlas is still partially empty, all the glyphs were added
150   return !atlasFull;
151 }
152
153 } // unnamed namespace
154
155 struct VectorBasedRenderer::Impl
156 {
157   Impl()
158   {
159     mFontClient = TextAbstraction::FontClient::Get();
160
161     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
162     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
163     mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
164   }
165
166   Actor mActor;                            ///< The actor parent which renders the text
167
168   TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
169
170   Property::Map mQuadVertexFormat;         ///> Describes the vertex format for text
171
172   Shader mShaderEffect;
173
174   IntrusivePtr<VectorBlobAtlas> mAtlas;
175 };
176
177 Text::RendererPtr VectorBasedRenderer::New()
178 {
179   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::VectorBasedRenderer::New()\n" );
180
181   return Text::RendererPtr( new VectorBasedRenderer() );
182 }
183
184 Actor VectorBasedRenderer::Render( Text::ViewInterface& view,
185                                    float& alignmentOffset,
186                                    int /*depth*/ )
187 {
188   UnparentAndReset( mImpl->mActor );
189
190   mImpl->mActor = Actor::New();
191   mImpl->mActor.SetParentOrigin( ParentOrigin::CENTER );
192   mImpl->mActor.SetSize( view.GetControlSize() );
193   mImpl->mActor.SetColor( Color::WHITE );
194 #if defined(DEBUG_ENABLED)
195   mImpl->mActor.SetName( "Text renderable actor" );
196 #endif
197
198   Length numberOfGlyphs = view.GetNumberOfGlyphs();
199
200   if( numberOfGlyphs > 0u )
201   {
202     Vector<GlyphInfo> glyphs;
203     glyphs.Resize( numberOfGlyphs );
204
205     Vector<Vector2> positions;
206     positions.Resize( numberOfGlyphs );
207
208     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
209                                      positions.Begin(),
210                                      alignmentOffset,
211                                      0u,
212                                      numberOfGlyphs );
213
214     glyphs.Resize( numberOfGlyphs );
215     positions.Resize( numberOfGlyphs );
216
217     const Vector4* const colorsBuffer = view.GetColors();
218     const ColorIndex* const colorIndicesBuffer = view.GetColorIndices();
219     const Vector4& defaultColor = view.GetTextColor();
220
221     Vector< Vertex2D > vertices;
222     Vector< unsigned short > indices;
223
224     const Vector2& controlSize = view.GetControlSize();
225     float xOffset = -alignmentOffset + controlSize.width * -0.5f;
226     float yOffset = controlSize.height * -0.5f;
227
228     if( ! mImpl->mAtlas ||
229           mImpl->mAtlas->IsFull() )
230     {
231       VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
232       mImpl->mAtlas = atlasShare.GetCurrentAtlas();
233     }
234
235     // First try adding the glyphs to the previous shared atlas
236     bool allGlyphsAdded = CreateGeometry( glyphs,
237                                           numberOfGlyphs,
238                                           positions,
239                                           xOffset,
240                                           yOffset,
241                                           *mImpl->mAtlas,
242                                           mImpl->mFontClient,
243                                           vertices,
244                                           indices,
245                                           colorsBuffer,
246                                           colorIndicesBuffer,
247                                           defaultColor );
248
249     if( ! allGlyphsAdded )
250     {
251       // The current atlas is full, abandon it and use a new one
252       mImpl->mAtlas.Reset();
253       vertices.Clear();
254       indices.Clear();
255
256       VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
257       mImpl->mAtlas = atlasShare.GetNewAtlas();
258
259       CreateGeometry( glyphs,
260                       numberOfGlyphs,
261                       positions,
262                       xOffset,
263                       yOffset,
264                       *mImpl->mAtlas,
265                       mImpl->mFontClient,
266                       vertices,
267                       indices,
268                       colorsBuffer,
269                       colorIndicesBuffer,
270                       defaultColor );
271       // Return value ignored; using more than an entire new atlas is not supported
272     }
273
274     if( 0 != vertices.Count() )
275     {
276       PropertyBuffer quadVertices = PropertyBuffer::New( mImpl->mQuadVertexFormat );
277
278       quadVertices.SetData( &vertices[ 0 ], vertices.Size() );
279
280
281       Geometry quadGeometry = Geometry::New();
282       quadGeometry.AddVertexBuffer( quadVertices );
283       quadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
284
285       TextureSet texture = mImpl->mAtlas->GetTextureSet();
286
287       const Vector4 atlasInfo = mImpl->mAtlas->GetInfo();
288       mImpl->mShaderEffect = GlyphyShader::New( atlasInfo );
289
290       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mImpl->mShaderEffect );
291       renderer.SetTextures( texture );
292       mImpl->mActor.AddRenderer( renderer );
293     }
294   }
295
296   return mImpl->mActor;
297 }
298
299 VectorBasedRenderer::VectorBasedRenderer()
300 {
301   mImpl = new Impl();
302 }
303
304 VectorBasedRenderer::~VectorBasedRenderer()
305 {
306   delete mImpl;
307 }
308