2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/text/rendering/basic/text-basic-renderer.h>
22 #include <dali/public-api/text-abstraction/font-client.h>
23 #include <dali/public-api/actors/image-actor.h>
24 #include <dali/public-api/actors/mesh-actor.h>
25 #include <dali/public-api/images/atlas.h>
26 #include <dali/public-api/geometry/mesh.h>
27 #include <dali/integration-api/debug.h>
30 #include <dali-toolkit/internal/text/line-run.h>
31 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
32 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
36 using namespace Dali::Toolkit;
37 using namespace Dali::Toolkit::Text;
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
46 const std::size_t PADDING = 2; //< To avoid GL filtering artefacts
48 struct TextureCoordinates
51 : topLeft( 0.0f, 0.0f ),
52 topRight( 1.0f, 0.0f ),
53 bottomLeft( 0.0f, 1.0f ),
54 bottomRight( 1.0f, 1.0f )
75 AtlasGlyph( FontId id,
76 GlyphIndex glyphIndex,
78 std::size_t widthPixels,
79 std::size_t heightPixels,
85 height( heightPixels ),
96 TextureCoordinates coords;
99 } // unnamed namespace
101 struct BasicRenderer::Impl
104 * @brief Create the renderer implementation.
109 mWidthBGRA8888( 0.0f ),
110 mHeightBGRA8888( 0.0f )
112 mFontClient = TextAbstraction::FontClient::Get();
116 * @brief Reset the previous glyph calculations.
118 * @param[in] size The glyph space to reserve.
120 void Reset( std::size_t size )
124 mWidthBGRA8888 = 0.0f;
125 mHeightBGRA8888 = 0.0f;
127 mGlyphs.reserve( size );
129 mAtlasBGRA8888.Reset();
133 * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
135 * @param[in] glyphs The glyphs to upload.
137 void CreateAtlases( const Vector<GlyphInfo>& glyphs )
139 // Clear previous atlas
140 Reset( glyphs.Count() );
142 for( unsigned int i=0; i<glyphs.Count(); ++i )
144 float width = glyphs[i].width;
145 float height = glyphs[i].height;
148 height > 0 ) // skip whitespace
150 if( !GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
152 AddGlyph( glyphs[i] );
157 mAtlasL8 = CreateAtlas( mWidthL8, mHeightL8, Pixel::L8 );
158 mAtlasBGRA8888 = CreateAtlas( mWidthBGRA8888, mHeightBGRA8888, Pixel::BGRA8888 );
161 Atlas CreateAtlas( unsigned int width, unsigned int height, Pixel::Format format )
165 if( width > 0 && height > 0 )
167 atlas = Atlas::New( width, height, format );
169 for( unsigned int i=0; i<mGlyphs.size(); ++i )
171 AtlasGlyph& glyph = mGlyphs[i];
173 const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
175 if( format == glyphFormat )
177 atlas.Upload( glyph.mBitmap, glyph.xOffset, 0 );
179 TextureCoordinates& coords = glyph.coords;
180 coords.topLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
181 coords.topLeft.y = 0.0f;
182 coords.topRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
183 coords.topRight.y = 0.0f;
184 coords.bottomLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
185 coords.bottomLeft.y = static_cast<float>(glyph.height) / static_cast<float>(height);
186 coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
187 coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(height);
196 * @brief Check whether we already have the glyph.
198 bool GlyphFound( FontId fontId, GlyphIndex index ) const
200 for( unsigned int i=0; i<mGlyphs.size(); ++i )
202 const AtlasGlyph& glyph = mGlyphs[i];
204 if( fontId == glyph.fontId &&
205 index == glyph.index )
215 * @brief Add the glyph.
217 void AddGlyph( const GlyphInfo& glyphInfo )
219 BufferImage bitmap = mFontClient.CreateBitmap( glyphInfo.fontId, glyphInfo.index );
221 const Pixel::Format format = bitmap.GetPixelFormat();
223 if( Pixel::L8 == format )
225 mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthL8, glyphInfo.width, glyphInfo.height, bitmap ) );
227 // Increase the Atlas width/height
228 mWidthL8 += glyphInfo.width + PADDING;
229 if( mHeightL8 < glyphInfo.height + PADDING )
231 mHeightL8 = glyphInfo.height + PADDING;
234 else if ( Pixel::BGRA8888 == format )
236 mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthBGRA8888, glyphInfo.width, glyphInfo.height, bitmap ) );
238 // A separate Atlas is used for color Emojis
239 mWidthBGRA8888 += glyphInfo.width + PADDING;
240 if( mHeightBGRA8888 < glyphInfo.height + PADDING )
242 mHeightBGRA8888 = glyphInfo.height + PADDING;
248 * @brief Get the texture coordinates for a glyph.
250 bool GetTextureCoordinates( Pixel::Format format, FontId fontId, GlyphIndex index, TextureCoordinates& coords )
252 for( unsigned int i=0; i<mGlyphs.size(); ++i )
254 const AtlasGlyph& glyph = mGlyphs[i];
256 const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
258 if( format == glyphFormat &&
259 fontId == glyph.fontId &&
260 index == glyph.index )
262 coords = glyph.coords;
271 * @brief Helper method to create a mesh with one quad per glyph.
273 * @param[in] glyphs The glyphs to display.
274 * @param[in] positions The 2D positions of the glyphs.
275 * @param[in] image The material uses this as a diffuse texture.
277 Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Pixel::Format format, Image image )
279 MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
281 MeshData::FaceIndices faces;
282 faces.reserve( 6 * glyphs.Count() ); // 2 triangles per quad
284 for( unsigned int i=0; i<glyphs.Count(); ++i )
286 float width = glyphs[i].width;
287 float height = glyphs[i].height;
290 height > 0 ) // skip whitespace
292 const Vector2& position = positions[i];
294 TextureCoordinates coords;
295 if( GetTextureCoordinates( format, glyphs[i].fontId, glyphs[i].index, coords ) )
297 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 ) );
298 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 ) );
299 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 ) );
300 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 ) );
302 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
303 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
308 Material material = Material::New( "Material" );
309 material.SetDiffuseTexture( image );
311 // Create the mesh data from the vertices and faces
313 meshData.SetHasColor( false );
314 meshData.SetMaterial( material );
315 meshData.SetVertices( vertices );
316 meshData.SetFaceIndices( faces );
318 // Create a mesh from the data
319 Dali::Mesh mesh = Mesh::New( meshData );
323 RenderableActor mActor; ///< The actor which renders the text
326 unsigned int mWidthL8;
327 unsigned int mHeightL8;
329 // A separate Atlas is used for color Emojis
330 Atlas mAtlasBGRA8888;
331 unsigned int mWidthBGRA8888;
332 unsigned int mHeightBGRA8888;
334 std::vector<AtlasGlyph> mGlyphs;
336 TextAbstraction::FontClient mFontClient;
339 Text::RendererPtr BasicRenderer::New()
341 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::BasicRenderer::New()\n" );
343 return Text::RendererPtr( new BasicRenderer() );
346 RenderableActor BasicRenderer::Render( Text::ViewInterface& view )
348 // Remove the previous text
349 UnparentAndReset( mImpl->mActor );
351 Length numberOfGlyphs = view.GetNumberOfGlyphs();
353 if( numberOfGlyphs > 0u )
355 Vector<GlyphInfo> glyphs;
356 glyphs.Resize( numberOfGlyphs );
358 std::vector<Vector2> positions;
359 positions.resize( numberOfGlyphs );
361 numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
366 glyphs.Resize( numberOfGlyphs );
367 positions.resize( numberOfGlyphs );
369 mImpl->CreateAtlases( glyphs );
372 if( mImpl->mAtlasL8 )
374 actorL8 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::L8, mImpl->mAtlasL8 ) );
375 actorL8.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
377 ShaderEffect shader = BasicShader::New();
378 actorL8.SetShaderEffect( shader );
381 MeshActor actorBGRA8888;
382 if( mImpl->mAtlasBGRA8888 )
384 actorBGRA8888 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::BGRA8888, mImpl->mAtlasBGRA8888 ) );
385 actorBGRA8888.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
387 ShaderEffect shader = BgraShader::New();
388 actorBGRA8888.SetShaderEffect( shader );
391 // If we have both monochrome & color glyphs, two mesh actors are returned in a container
392 if( actorL8 && actorBGRA8888 )
394 mImpl->mActor = ImageActor::New();
395 mImpl->mActor.Add( actorL8 );
396 mImpl->mActor.Add( actorBGRA8888 );
402 mImpl->mActor = actorL8;
404 else if( actorBGRA8888 )
406 mImpl->mActor = actorBGRA8888;
411 return mImpl->mActor;
414 BasicRenderer::BasicRenderer()
419 BasicRenderer::~BasicRenderer()