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-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
28 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
32 using namespace Dali::Toolkit;
33 using namespace Dali::Toolkit::Text;
38 const std::size_t PADDING = 2; //< To avoid GL filtering artefacts
40 struct TextureCoordinates
43 : topLeft( 0.0f, 0.0f ),
44 topRight( 1.0f, 0.0f ),
45 bottomLeft( 0.0f, 1.0f ),
46 bottomRight( 1.0f, 1.0f )
67 AtlasGlyph( FontId id,
68 GlyphIndex glyphIndex,
70 std::size_t widthPixels,
71 std::size_t heightPixels,
77 height( heightPixels ),
88 TextureCoordinates coords;
91 } // unnamed namespace
93 struct BasicRenderer::Impl
96 * @brief Create the renderer implementation.
101 mWidthBGRA8888( 0.0f ),
102 mHeightBGRA8888( 0.0f )
104 mFontClient = TextAbstraction::FontClient::Get();
108 * @brief Reset the previous glyph calculations.
110 * @param[in] size The glyph space to reserve.
112 void Reset( std::size_t size )
116 mWidthBGRA8888 = 0.0f;
117 mHeightBGRA8888 = 0.0f;
119 mGlyphs.reserve( size );
121 mAtlasBGRA8888.Reset();
125 * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
127 * @param[in] glyphs The glyphs to upload.
129 void CreateAtlases( const Vector<GlyphInfo>& glyphs )
131 // Clear previous atlas
132 Reset( glyphs.Count() );
134 for( unsigned int i=0; i<glyphs.Count(); ++i )
136 float width = glyphs[i].width;
137 float height = glyphs[i].height;
140 height > 0 ) // skip whitespace
142 if( !GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
144 AddGlyph( glyphs[i] );
149 mAtlasL8 = CreateAtlas( mWidthL8, mHeightL8, Pixel::L8 );
150 mAtlasBGRA8888 = CreateAtlas( mWidthBGRA8888, mHeightBGRA8888, Pixel::BGRA8888 );
153 Atlas CreateAtlas( unsigned int width, unsigned int height, Pixel::Format format )
157 if( width > 0 && height > 0 )
159 atlas = Atlas::New( width, height, format );
161 for( unsigned int i=0; i<mGlyphs.size(); ++i )
163 AtlasGlyph& glyph = mGlyphs[i];
165 const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
167 if( format == glyphFormat )
169 atlas.Upload( glyph.mBitmap, glyph.xOffset, 0 );
171 TextureCoordinates& coords = glyph.coords;
172 coords.topLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
173 coords.topLeft.y = 0.0f;
174 coords.topRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
175 coords.topRight.y = 0.0f;
176 coords.bottomLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
177 coords.bottomLeft.y = static_cast<float>(glyph.height) / static_cast<float>(height);
178 coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
179 coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(height);
188 * @brief Check whether we already have the glyph.
190 bool GlyphFound( FontId fontId, GlyphIndex index ) const
192 for( unsigned int i=0; i<mGlyphs.size(); ++i )
194 const AtlasGlyph& glyph = mGlyphs[i];
196 if( fontId == glyph.fontId &&
197 index == glyph.index )
207 * @brief Add the glyph.
209 void AddGlyph( const GlyphInfo& glyphInfo )
211 BufferImage bitmap = mFontClient.CreateBitmap( glyphInfo.fontId, glyphInfo.index );
213 const Pixel::Format format = bitmap.GetPixelFormat();
215 if( Pixel::L8 == format )
217 mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthL8, glyphInfo.width, glyphInfo.height, bitmap ) );
219 // Increase the Atlas width/height
220 mWidthL8 += glyphInfo.width + PADDING;
221 if( mHeightL8 < glyphInfo.height + PADDING )
223 mHeightL8 = glyphInfo.height + PADDING;
226 else if ( Pixel::BGRA8888 == format )
228 mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthBGRA8888, glyphInfo.width, glyphInfo.height, bitmap ) );
230 // A separate Atlas is used for color Emojis
231 mWidthBGRA8888 += glyphInfo.width + PADDING;
232 if( mHeightBGRA8888 < glyphInfo.height + PADDING )
234 mHeightBGRA8888 = glyphInfo.height + PADDING;
240 * @brief Get the texture coordinates for a glyph.
242 bool GetTextureCoordinates( Pixel::Format format, FontId fontId, GlyphIndex index, TextureCoordinates& coords )
244 for( unsigned int i=0; i<mGlyphs.size(); ++i )
246 const AtlasGlyph& glyph = mGlyphs[i];
248 const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
250 if( format == glyphFormat &&
251 fontId == glyph.fontId &&
252 index == glyph.index )
254 coords = glyph.coords;
263 * @brief Helper method to create a mesh with one quad per glyph.
265 * @param[in] glyphs The glyphs to display.
266 * @param[in] positions The 2D positions of the glyphs.
267 * @param[in] image The material uses this as a diffuse texture.
269 Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Pixel::Format format, Image image )
271 MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
273 MeshData::FaceIndices faces;
274 faces.reserve( 6 * glyphs.Count() ); // 2 triangles per quad
276 for( unsigned int i=0; i<glyphs.Count(); ++i )
278 float width = glyphs[i].width;
279 float height = glyphs[i].height;
282 height > 0 ) // skip whitespace
284 const Vector2& position = positions[i];
286 TextureCoordinates coords;
287 if( GetTextureCoordinates( format, glyphs[i].fontId, glyphs[i].index, coords ) )
289 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 ) );
290 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 ) );
291 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 ) );
292 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 ) );
294 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
295 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
300 Material material = Material::New( "Material" );
301 material.SetDiffuseTexture( image );
303 // Create the mesh data from the vertices and faces
305 meshData.SetHasColor( false );
306 meshData.SetMaterial( material );
307 meshData.SetVertices( vertices );
308 meshData.SetFaceIndices( faces );
310 // Create a mesh from the data
311 Dali::Mesh mesh = Mesh::New( meshData );
315 RenderableActor mActor; ///< The actor which renders the text
318 unsigned int mWidthL8;
319 unsigned int mHeightL8;
321 // A separate Atlas is used for color Emojis
322 Atlas mAtlasBGRA8888;
323 unsigned int mWidthBGRA8888;
324 unsigned int mHeightBGRA8888;
326 std::vector<AtlasGlyph> mGlyphs;
328 TextAbstraction::FontClient mFontClient;
331 Text::RendererPtr BasicRenderer::New()
333 return Text::RendererPtr( new BasicRenderer() );
336 RenderableActor BasicRenderer::Render( Text::ViewInterface& view )
338 // Remove the previous text
339 UnparentAndReset( mImpl->mActor );
341 Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
343 if( numberOfGlyphs > 0 )
345 Vector<GlyphInfo> glyphs;
346 glyphs.Resize( numberOfGlyphs );
348 view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
350 std::vector<Vector2> positions;
351 positions.resize( numberOfGlyphs );
352 view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
354 mImpl->CreateAtlases( glyphs );
357 if( mImpl->mAtlasL8 )
359 actorL8 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::L8, mImpl->mAtlasL8 ) );
360 actorL8.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
362 ShaderEffect shader = BasicShader::New();
363 actorL8.SetShaderEffect( shader );
366 MeshActor actorBGRA8888;
367 if( mImpl->mAtlasBGRA8888 )
369 actorBGRA8888 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::BGRA8888, mImpl->mAtlasBGRA8888 ) );
370 actorBGRA8888.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
372 ShaderEffect shader = BgraShader::New();
373 actorBGRA8888.SetShaderEffect( shader );
376 // If we have both monochrome & color glyphs, two mesh actors are returned in a container
377 if( actorL8 && actorBGRA8888 )
379 mImpl->mActor = ImageActor::New();
380 mImpl->mActor.Add( actorL8 );
381 mImpl->mActor.Add( actorBGRA8888 );
387 mImpl->mActor = actorL8;
389 else if( actorBGRA8888 )
391 mImpl->mActor = actorBGRA8888;
396 return mImpl->mActor;
399 BasicRenderer::BasicRenderer()
404 BasicRenderer::~BasicRenderer()