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/mesh-actor.h>
24 #include <dali/public-api/images/atlas.h>
25 #include <dali/public-api/geometry/mesh.h>
26 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
29 using namespace Dali::Toolkit;
30 using namespace Dali::Toolkit::Text;
35 const std::size_t PADDING = 2; //< To avoid GL filtering artefacts
37 struct TextureCoordinates
40 : topLeft( 0.0f, 0.0f ),
41 topRight( 1.0f, 0.0f ),
42 bottomLeft( 0.0f, 1.0f ),
43 bottomRight( 1.0f, 1.0f )
53 struct AtlasHelperGlyph
64 AtlasHelperGlyph( FontId id,
65 GlyphIndex glyphIndex,
67 std::size_t widthPixels,
68 std::size_t heightPixels )
73 height( heightPixels )
82 TextureCoordinates coords;
91 mFontClient = TextAbstraction::FontClient::Get();
101 void Reserve( std::size_t size )
103 mGlyphs.reserve( size );
106 bool GlyphFound( FontId fontId, GlyphIndex index ) const
108 for( unsigned int i=0; i<mGlyphs.size(); ++i )
110 const AtlasHelperGlyph& glyph = mGlyphs[i];
112 if( fontId == glyph.fontId &&
113 index == glyph.index )
122 void AddGlyph( const GlyphInfo& glyphInfo )
124 mGlyphs.push_back( AtlasHelperGlyph( glyphInfo.fontId, glyphInfo.index, mWidth, glyphInfo.width, glyphInfo.height ) );
126 mWidth += glyphInfo.width + PADDING;
127 if( mHeight < glyphInfo.height + PADDING )
129 mHeight = glyphInfo.height + PADDING;
135 Atlas atlas = Atlas::New( mWidth, mHeight, Pixel::L8 );
137 for( unsigned int i=0; i<mGlyphs.size(); ++i )
139 AtlasHelperGlyph& glyph = mGlyphs[i];
140 BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
141 atlas.Upload( bitmap, glyph.xOffset, 0 );
143 TextureCoordinates& coords = glyph.coords;
144 coords.topLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(mWidth);
145 coords.topLeft.y = 0.0f;
146 coords.topRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(mWidth);
147 coords.topRight.y = 0.0f;
148 coords.bottomLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(mWidth);
149 coords.bottomLeft.y = static_cast<float>(glyph.height) / static_cast<float>(mHeight);
150 coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(mWidth);
151 coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(mHeight);
157 void GetTextureCoordinates( FontId fontId, GlyphIndex index, TextureCoordinates& coords )
159 for( unsigned int i=0; i<mGlyphs.size(); ++i )
161 const AtlasHelperGlyph& glyph = mGlyphs[i];
163 if( fontId == glyph.fontId &&
164 index == glyph.index )
166 coords = glyph.coords;
177 std::vector<AtlasHelperGlyph> mGlyphs;
179 TextAbstraction::FontClient mFontClient;
182 } // unnamed namespace
184 struct BasicRenderer::Impl
187 * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
189 * @param[in] glyphs The glyphs to upload.
191 Atlas CreateAtlas( const Vector<GlyphInfo>& glyphs )
193 AtlasHelper& helper = mAtlasHelper;
195 // Clear previous atlas
197 helper.Reserve( glyphs.Count() );
199 for( unsigned int i=0; i<glyphs.Count(); ++i )
201 float width = glyphs[i].width;
202 float height = glyphs[i].height;
205 height > 0 ) // skip whitespace
207 if( !helper.GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
209 helper.AddGlyph( glyphs[i] );
214 // Uploads the bitmaps to Dali
215 return helper.CreateAtlas();
219 * @brief Helper method to create a mesh with one quad per glyph.
221 * @param[in] glyphs The glyphs to display.
222 * @param[in] positions The 2D positions of the glyphs.
223 * @param[in] image The material uses this as a diffuse texture.
225 Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Image image )
227 MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
229 MeshData::FaceIndices faces;
230 faces.reserve( 6 * glyphs.Count() ); // 2 triangles per quad
232 for( unsigned int i=0; i<glyphs.Count(); ++i )
234 float width = glyphs[i].width;
235 float height = glyphs[i].height;
238 height > 0 ) // skip whitespace
240 const Vector2& position = positions[i];
242 TextureCoordinates coords;
243 mAtlasHelper.GetTextureCoordinates( glyphs[i].fontId, glyphs[i].index, coords );
245 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 ) );
246 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 ) );
247 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 ) );
248 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 ) );
250 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
251 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
255 Material material = Material::New( "Material" );
256 material.SetDiffuseTexture( image );
258 // Create the mesh data from the vertices and faces
260 meshData.SetHasColor( false );
261 meshData.SetMaterial( material );
262 meshData.SetVertices( vertices );
263 meshData.SetFaceIndices( faces );
265 // Create a mesh from the data
266 Dali::Mesh mesh = Mesh::New( meshData );
270 RenderableActor mActor; ///< The actor which renders the text
272 AtlasHelper mAtlasHelper; ///< A helper class for storing atlas positions etc.
275 Text::RendererPtr BasicRenderer::New()
277 return Text::RendererPtr( new BasicRenderer() );
280 RenderableActor BasicRenderer::Render( Text::ViewInterface& view )
282 UnparentAndReset( mImpl->mActor );
284 Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
286 if( numberOfGlyphs > 0 )
288 Vector<GlyphInfo> glyphs;
289 glyphs.Resize( numberOfGlyphs );
291 view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
293 std::vector<Vector2> positions;
294 positions.resize( numberOfGlyphs );
295 view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
297 Atlas atlas = mImpl->CreateAtlas( glyphs );
299 MeshActor actor = MeshActor::New( mImpl->CreateMesh( glyphs, positions, atlas ) );
300 actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
301 actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
303 ShaderEffect shader = BasicShader::New();
304 actor.SetShaderEffect( shader );
306 mImpl->mActor = actor;
309 return mImpl->mActor;
312 BasicRenderer::BasicRenderer()
317 BasicRenderer::~BasicRenderer()