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/devel-api/text-abstraction/font-client.h>
23 #include <dali/public-api/actors/image-actor.h>
24 #include <dali/devel-api/images/atlas.h>
25 #include <dali/integration-api/debug.h>
28 #include <dali-toolkit/internal/text/line-run.h>
29 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
30 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
34 using namespace Dali::Toolkit;
35 using namespace Dali::Toolkit::Text;
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
44 const std::size_t PADDING = 2; //< To avoid GL filtering artefacts
46 struct TextureCoordinates
49 : topLeft( 0.0f, 0.0f ),
50 topRight( 1.0f, 0.0f ),
51 bottomLeft( 0.0f, 1.0f ),
52 bottomRight( 1.0f, 1.0f )
73 AtlasGlyph( FontId id,
74 GlyphIndex glyphIndex,
76 std::size_t widthPixels,
77 std::size_t heightPixels,
83 height( heightPixels ),
94 TextureCoordinates coords;
97 } // unnamed namespace
99 struct BasicRenderer::Impl
102 * @brief Create the renderer implementation.
107 mWidthBGRA8888( 0.0f ),
108 mHeightBGRA8888( 0.0f )
110 mFontClient = TextAbstraction::FontClient::Get();
114 * @brief Reset the previous glyph calculations.
116 * @param[in] size The glyph space to reserve.
118 void Reset( std::size_t size )
122 mWidthBGRA8888 = 0.0f;
123 mHeightBGRA8888 = 0.0f;
125 mGlyphs.reserve( size );
127 mAtlasBGRA8888.Reset();
131 * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
133 * @param[in] glyphs The glyphs to upload.
135 void CreateAtlases( const Vector<GlyphInfo>& glyphs )
137 // Clear previous atlas
138 Reset( glyphs.Count() );
140 for( unsigned int i=0; i<glyphs.Count(); ++i )
142 float width = glyphs[i].width;
143 float height = glyphs[i].height;
146 height > 0 ) // skip whitespace
148 if( !GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
150 AddGlyph( glyphs[i] );
155 mAtlasL8 = CreateAtlas( mWidthL8, mHeightL8, Pixel::L8 );
156 mAtlasBGRA8888 = CreateAtlas( mWidthBGRA8888, mHeightBGRA8888, Pixel::BGRA8888 );
159 Atlas CreateAtlas( unsigned int width, unsigned int height, Pixel::Format format )
163 if( width > 0 && height > 0 )
165 atlas = Atlas::New( width, height, format );
167 for( unsigned int i=0; i<mGlyphs.size(); ++i )
169 AtlasGlyph& glyph = mGlyphs[i];
171 const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
173 if( format == glyphFormat )
175 atlas.Upload( glyph.mBitmap, glyph.xOffset, 0 );
177 TextureCoordinates& coords = glyph.coords;
178 coords.topLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
179 coords.topLeft.y = 0.0f;
180 coords.topRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
181 coords.topRight.y = 0.0f;
182 coords.bottomLeft.x = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
183 coords.bottomLeft.y = static_cast<float>(glyph.height) / static_cast<float>(height);
184 coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
185 coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(height);
194 * @brief Check whether we already have the glyph.
196 bool GlyphFound( FontId fontId, GlyphIndex index ) const
198 for( unsigned int i=0; i<mGlyphs.size(); ++i )
200 const AtlasGlyph& glyph = mGlyphs[i];
202 if( fontId == glyph.fontId &&
203 index == glyph.index )
213 * @brief Add the glyph.
215 void AddGlyph( const GlyphInfo& glyphInfo )
217 BufferImage bitmap = mFontClient.CreateBitmap( glyphInfo.fontId, glyphInfo.index );
219 const Pixel::Format format = bitmap.GetPixelFormat();
221 if( Pixel::L8 == format )
223 mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthL8, glyphInfo.width, glyphInfo.height, bitmap ) );
225 // Increase the Atlas width/height
226 mWidthL8 += glyphInfo.width + PADDING;
227 if( mHeightL8 < glyphInfo.height + PADDING )
229 mHeightL8 = glyphInfo.height + PADDING;
232 else if ( Pixel::BGRA8888 == format )
234 mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthBGRA8888, glyphInfo.width, glyphInfo.height, bitmap ) );
236 // A separate Atlas is used for color Emojis
237 mWidthBGRA8888 += glyphInfo.width + PADDING;
238 if( mHeightBGRA8888 < glyphInfo.height + PADDING )
240 mHeightBGRA8888 = glyphInfo.height + PADDING;
246 * @brief Get the texture coordinates for a glyph.
248 bool GetTextureCoordinates( Pixel::Format format, FontId fontId, GlyphIndex index, TextureCoordinates& coords )
250 for( unsigned int i=0; i<mGlyphs.size(); ++i )
252 const AtlasGlyph& glyph = mGlyphs[i];
254 const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
256 if( format == glyphFormat &&
257 fontId == glyph.fontId &&
258 index == glyph.index )
260 coords = glyph.coords;
269 * @brief Helper method to create a mesh with one quad per glyph.
271 * @param[in] glyphs The glyphs to display.
272 * @param[in] positions The 2D positions of the glyphs.
273 * @param[in] image The material uses this as a diffuse texture.
276 Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Pixel::Format format, Image image )
278 MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
280 MeshData::FaceIndices faces;
281 faces.reserve( 6 * glyphs.Count() ); // 2 triangles per quad
283 for( unsigned int i=0; i<glyphs.Count(); ++i )
285 float width = glyphs[i].width;
286 float height = glyphs[i].height;
289 height > 0 ) // skip whitespace
291 const Vector2& position = positions[i];
293 TextureCoordinates coords;
294 if( GetTextureCoordinates( format, glyphs[i].fontId, glyphs[i].index, coords ) )
296 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 ) );
297 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 ) );
298 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 ) );
299 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 ) );
301 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
302 faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
307 Material material = Material::New( "Material" );
308 material.SetDiffuseTexture( image );
310 // Create the mesh data from the vertices and faces
312 meshData.SetHasColor( false );
313 meshData.SetMaterial( material );
314 meshData.SetVertices( vertices );
315 meshData.SetFaceIndices( faces );
317 // Create a mesh from the data
318 Dali::Mesh mesh = Mesh::New( meshData );
322 Actor mActor; ///< The actor which renders the text
325 unsigned int mWidthL8;
326 unsigned int mHeightL8;
328 // A separate Atlas is used for color Emojis
329 Atlas mAtlasBGRA8888;
330 unsigned int mWidthBGRA8888;
331 unsigned int mHeightBGRA8888;
333 std::vector<AtlasGlyph> mGlyphs;
335 TextAbstraction::FontClient mFontClient;
338 Text::RendererPtr BasicRenderer::New()
340 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::BasicRenderer::New()\n" );
342 return Text::RendererPtr( new BasicRenderer() );
345 Actor BasicRenderer::Render( Text::ViewInterface& view, unsigned int depth )
347 // Remove the previous text
348 UnparentAndReset( mImpl->mActor );
350 Length numberOfGlyphs = view.GetNumberOfGlyphs();
352 if( numberOfGlyphs > 0u )
354 Vector<GlyphInfo> glyphs;
355 glyphs.Resize( numberOfGlyphs );
357 std::vector<Vector2> positions;
358 positions.resize( numberOfGlyphs );
360 numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
365 glyphs.Resize( numberOfGlyphs );
366 positions.resize( numberOfGlyphs );
368 mImpl->CreateAtlases( glyphs );
371 if( mImpl->mAtlasL8 )
373 //actorL8 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::L8, mImpl->mAtlasL8 ) );
374 actorL8.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
376 ShaderEffect shader = BasicShader::New();
377 //actorL8.SetShaderEffect( shader );
381 if( mImpl->mAtlasBGRA8888 )
383 //actorBGRA8888 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::BGRA8888, mImpl->mAtlasBGRA8888 ) );
384 actorBGRA8888.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
386 ShaderEffect shader = BgraShader::New();
387 //actorBGRA8888.SetShaderEffect( shader );
390 // If we have both monochrome & color glyphs, two mesh actors are returned in a container
391 if( actorL8 && actorBGRA8888 )
393 mImpl->mActor = ImageActor::New();
394 mImpl->mActor.Add( actorL8 );
395 mImpl->mActor.Add( actorBGRA8888 );
401 mImpl->mActor = actorL8;
403 else if( actorBGRA8888 )
405 mImpl->mActor = actorBGRA8888;
410 return mImpl->mActor;
413 BasicRenderer::BasicRenderer()
418 BasicRenderer::~BasicRenderer()