Vector-based text rendering
[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/integration-api/debug.h>
23 #include <dali/devel-api/rendering/renderer.h>
24 #include <dali/devel-api/rendering/geometry.h>
25 #include <dali/devel-api/text-abstraction/font-client.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 };
54
55 void AddVertex( Vector<Vertex2D>& vertices, float x, float y, float u, float v )
56 {
57   Vertex2D meshVertex;
58   meshVertex.x = x;
59   meshVertex.y = y;
60   meshVertex.u = u;
61   meshVertex.v = v;
62   vertices.PushBack( meshVertex );
63 }
64
65 void AddTriangle( Vector<unsigned int>& indices, unsigned int v0, unsigned int v1, unsigned int v2 )
66 {
67   indices.PushBack( v0 );
68   indices.PushBack( v1 );
69   indices.PushBack( v2 );
70 }
71
72 bool CreateGeometry( const Vector<GlyphInfo>& glyphs,
73                      unsigned int numberOfGlyphs,
74                      const Vector<Vector2>& positions,
75                      float xOffset,
76                      float yOffset,
77                      VectorBlobAtlas& atlas,
78                      Dali::TextAbstraction::FontClient& fontClient,
79                      Vector< Vertex2D >& vertices,
80                      Vector< unsigned int >& indices )
81 {
82   bool atlasFull( false );
83
84   for( unsigned int i=0, idx=0; i<numberOfGlyphs && !atlasFull; ++i )
85   {
86     if( glyphs[i].width  > 0 &&
87         glyphs[i].height > 0 )
88     {
89       bool foundBlob( true );
90
91       BlobCoordinate blobCoords[4];
92
93       if( ! atlas.FindGlyph( glyphs[i].fontId, glyphs[i].index, blobCoords )  )
94       {
95         // Add blob to atlas
96         VectorBlob* blob( NULL );
97         unsigned int blobLength( 0 );
98         unsigned int nominalWidth( 0 );
99         unsigned int nominalHeight( 0 );
100         fontClient.CreateVectorBlob( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight );
101
102         if( 0 != blobLength )
103         {
104           bool glyphAdded = atlas.AddGlyph( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight, blobCoords );
105
106           foundBlob = glyphAdded;
107           atlasFull = !glyphAdded;
108         }
109         else
110         {
111           foundBlob = false;
112         }
113       }
114
115       if( foundBlob )
116       {
117         const float x1( xOffset + positions[i].x );
118         const float x2( xOffset + positions[i].x + glyphs[i].width );
119         const float y1( yOffset + positions[i].y );
120         const float y2( yOffset + positions[i].y + glyphs[i].height );
121
122         AddVertex( vertices, x1, y2, blobCoords[0].u, blobCoords[0].v );
123         AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v );
124         AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v );
125         AddTriangle( indices, idx, idx+1, idx+2 );
126         idx+=3;
127
128         AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v );
129         AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v );
130         AddVertex( vertices, x2, y1, blobCoords[3].u, blobCoords[3].v );
131         AddTriangle( indices, idx, idx+1, idx+2 );
132         idx+=3;
133       }
134     }
135   }
136
137   // If the atlas is still partially empty, all the glyphs were added
138   return !atlasFull;
139 }
140
141 } // unnamed namespace
142
143 struct VectorBasedRenderer::Impl
144 {
145   Impl()
146   {
147     mFontClient = TextAbstraction::FontClient::Get();
148
149     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
150     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
151     mQuadIndexFormat[ "indices" ] = Property::INTEGER;
152   }
153
154   Actor mActor;                            ///< The actor parent which renders the text
155
156   TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
157
158   Property::Map mQuadVertexFormat;         ///> Describes the vertex format for text
159   Property::Map mQuadIndexFormat;          ///> Describes the index format for text
160
161   Shader mShaderEffect;
162
163   IntrusivePtr<VectorBlobAtlas> mAtlas;
164 };
165
166 Text::RendererPtr VectorBasedRenderer::New()
167 {
168   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::VectorBasedRenderer::New()\n" );
169
170   return Text::RendererPtr( new VectorBasedRenderer() );
171 }
172
173 Actor VectorBasedRenderer::Render( Text::ViewInterface& view, int /*depth*/ )
174 {
175   UnparentAndReset( mImpl->mActor );
176
177   mImpl->mActor = Actor::New();
178   mImpl->mActor.SetParentOrigin( ParentOrigin::CENTER );
179   mImpl->mActor.SetSize( view.GetControlSize() );
180   mImpl->mActor.SetColor( Color::BLACK );
181 #if defined(DEBUG_ENABLED)
182   mImpl->mActor.SetName( "Text renderable actor" );
183 #endif
184
185   Length numberOfGlyphs = view.GetNumberOfGlyphs();
186
187   if( numberOfGlyphs > 0u )
188   {
189     Vector<GlyphInfo> glyphs;
190     glyphs.Resize( numberOfGlyphs );
191
192     Vector<Vector2> positions;
193     positions.Resize( numberOfGlyphs );
194
195     Vector<Vector4> colors;
196     colors.Resize( numberOfGlyphs, view.GetTextColor() );
197
198     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
199                                      positions.Begin(),
200                                      colors.Begin(),
201                                      0u,
202                                      numberOfGlyphs );
203     glyphs.Resize( numberOfGlyphs );
204     positions.Resize( numberOfGlyphs );
205
206     Vector< Vertex2D > vertices;
207     Vector< unsigned int > indices;
208
209     const Vector2& controlSize = view.GetControlSize();
210     float xOffset = controlSize.width  * -0.5f;
211     float yOffset = controlSize.height * -0.5f;
212
213     if( ! mImpl->mAtlas ||
214           mImpl->mAtlas->IsFull() )
215     {
216       VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
217       mImpl->mAtlas = atlasShare.GetCurrentAtlas();
218     }
219
220     // First try adding the glyphs to the previous shared atlas
221     bool allGlyphsAdded = CreateGeometry( glyphs, numberOfGlyphs, positions, xOffset, yOffset, *mImpl->mAtlas, mImpl->mFontClient, vertices, indices );
222
223     if( ! allGlyphsAdded )
224     {
225       // The current atlas is full, abandon it and use a new one
226       mImpl->mAtlas.Reset();
227       vertices.Clear();
228       indices.Clear();
229
230       VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
231       mImpl->mAtlas = atlasShare.GetNewAtlas();
232
233       CreateGeometry( glyphs, numberOfGlyphs, positions, xOffset, yOffset, *mImpl->mAtlas, mImpl->mFontClient, vertices, indices );
234       // Return value ignored; using more than an entire new atlas is not supported
235     }
236
237     if( 0 != vertices.Count() )
238     {
239       PropertyBuffer quadVertices = PropertyBuffer::New( mImpl->mQuadVertexFormat );
240       PropertyBuffer quadIndices = PropertyBuffer::New( mImpl->mQuadIndexFormat );
241
242       quadVertices.SetData( &vertices[ 0 ], vertices.Size() );
243       quadIndices.SetData( &indices[ 0 ], indices.Size() );
244
245       Geometry quadGeometry = Geometry::New();
246       quadGeometry.AddVertexBuffer( quadVertices );
247       quadGeometry.SetIndexBuffer( quadIndices );
248
249       TextureSet texture = mImpl->mAtlas->GetTextureSet();
250
251       const Vector4 atlasInfo = mImpl->mAtlas->GetInfo();
252       mImpl->mShaderEffect = GlyphyShader::New( atlasInfo );
253
254       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mImpl->mShaderEffect );
255       renderer.SetTextures( texture );
256       mImpl->mActor.AddRenderer( renderer );
257     }
258   }
259
260   return mImpl->mActor;
261 }
262
263 VectorBasedRenderer::VectorBasedRenderer()
264 {
265   mImpl = new Impl();
266 }
267
268 VectorBasedRenderer::~VectorBasedRenderer()
269 {
270   delete mImpl;
271 }
272