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/atlas/text-atlas-renderer.h>
22 #include <dali/dali.h>
23 #include <dali/integration-api/debug.h>
26 #include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
27 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
28 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
29 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
31 #if defined(DEBUG_ENABLED)
32 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_ATLAS_RENDERER");
36 using namespace Dali::Toolkit;
37 using namespace Dali::Toolkit::Text;
41 const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
42 const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f );
43 const Vector2 PADDING( 4.0f, 4.0f ); // Allow for variation in font glyphs
46 struct AtlasRenderer::Impl
58 Text::GlyphIndex mIndex;
64 Vector2 mNeededBlockSize;
68 : mSlotDelegate( this )
70 mGlyphManager = AtlasGlyphManager::Get();
71 mFontClient = TextAbstraction::FontClient::Get();
72 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, DEFAULT_BLOCK_SIZE );
73 mBasicShader = BasicShader::New();
74 mBGRAShader = BgraShader::New();
77 void AddGlyphs( const std::vector<Vector2>& positions, const Vector<GlyphInfo>& glyphs )
79 AtlasManager::AtlasSlot slot;
80 std::vector< MeshRecord > meshContainer;
81 FontId lastFontId = 0;
83 if (mImageIds.Size() )
85 // Unreference any currently used glyphs
89 CalculateBlocksSize( glyphs );
91 for ( uint32_t i = 0; i < glyphs.Size(); ++i )
93 GlyphInfo glyph = glyphs[ i ];
95 // No operation for white space
96 if ( glyph.width && glyph.height )
98 Vector2 position = positions[ i ];
100 mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
104 // This glyph already exists so generate mesh data plugging in our supplied position
105 mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
106 mImageIds.PushBack( slot.mImageId );
111 // Select correct size for new atlas if needed....?
112 if ( lastFontId != glyph.fontId )
114 for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
116 if ( mBlockSizes[ j ].mFontId == glyph.fontId )
118 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, mBlockSizes[ j ].mNeededBlockSize );
121 lastFontId = glyph.fontId;
124 // Glyph doesn't currently exist in atlas so upload
125 BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
127 // Locate a new slot for our glyph
128 mGlyphManager.Add( glyph, bitmap, slot );
130 // Generate mesh data for this quad, plugging in our supplied position
133 mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
134 mImageIds.PushBack( slot.mImageId );
137 // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
138 StitchTextMesh( meshContainer, newMeshData, slot );
142 // For each MeshData object, create a mesh actor and add to the renderable actor
143 if ( meshContainer.size() )
145 for ( uint32_t i = 0; i < meshContainer.size(); ++i )
147 Mesh mesh = Mesh::New( meshContainer[ i ].mMeshData );
148 MeshActor actor = MeshActor::New( mesh );
149 actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
150 actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );;
152 // Check to see what pixel format the shader should be
153 if ( mGlyphManager.GetPixelFormat( meshContainer[ i ].mAtlasId ) == Pixel::L8 )
155 actor.SetShaderEffect( mBasicShader );
159 actor.SetShaderEffect( mBGRAShader );
171 mActor.OffStageSignal().Connect( mSlotDelegate, &AtlasRenderer::Impl::OffStageDisconnect );
173 #if defined(DEBUG_ENABLED)
174 Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
175 DALI_LOG_INFO( gLogFilter, Debug::Concise, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
177 metrics.mAtlasMetrics.mAtlasCount,
178 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
179 for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
181 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
182 i + 1, i > 8 ? "" : " ",
183 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8 " : "BGRA",
184 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mWidth,
185 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mHeight,
186 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlockWidth,
187 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlockHeight,
188 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
189 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
194 void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
195 MeshData& newMeshData,
196 AtlasManager::AtlasSlot& slot )
200 // Check to see if there's a mesh data object that references the same atlas ?
201 for ( uint32_t i = 0; i < meshContainer.size(); ++i )
203 if ( slot.mAtlasId == meshContainer[ i ].mAtlasId )
205 // Stitch the mesh to the existing mesh
206 mGlyphManager.StitchMesh( meshContainer[ i ].mMeshData, newMeshData );
211 // No mesh data object currently exists that references this atlas, so create a new one
212 MeshRecord meshRecord;
213 meshRecord.mAtlasId = slot.mAtlasId;
214 meshRecord.mMeshData = newMeshData;
215 meshContainer.push_back( meshRecord );
219 // Unreference any glyphs that were used with this actor
220 void OffStageDisconnect( Dali::Actor actor )
227 for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
229 mGlyphManager.Remove( mImageIds[ i ] );
231 mImageIds.Resize( 0 );
234 void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
236 MaxBlockSize maxBlockSize;
237 for ( uint32_t i = 0; i < glyphs.Size(); ++i )
239 // Get the fontId of this glyph and check to see if a max size exists?
240 FontId fontId = glyphs[ i ].fontId;
241 float paddedWidth = glyphs[ i ].width + PADDING.x;
242 float paddedHeight = glyphs[ i ].height + PADDING.y;
243 bool foundFont = false;
245 for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
247 if ( mBlockSizes[ j ].mFontId == fontId )
250 if ( mBlockSizes[ j ].mNeededBlockSize.x < paddedWidth )
252 mBlockSizes[ j ].mNeededBlockSize.x = paddedWidth;
254 if ( mBlockSizes[ j ].mNeededBlockSize.y < paddedHeight )
256 mBlockSizes[ j ].mNeededBlockSize.y = paddedHeight;
263 maxBlockSize.mNeededBlockSize = Vector2( paddedWidth, paddedHeight );
264 maxBlockSize.mFontId = fontId;
265 mBlockSizes.push_back( maxBlockSize );
270 RenderableActor mActor; ///< The actor parent which renders the text
271 AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching
272 Vector< uint32_t > mImageIds; ///< A list of imageIDs used by the renderer
273 TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
274 SlotDelegate< AtlasRenderer::Impl > mSlotDelegate; ///> Signal generated to unreference glyphs when renderable actor is removed
275 ShaderEffect mBasicShader; ///> Shader to render L8 glyphs
276 ShaderEffect mBGRAShader; ///> Shader to render BGRA glyphs
277 std::vector< MaxBlockSize > mBlockSizes; ///> Maximum size needed to contain a glyph in a block within a new atlas
280 Text::RendererPtr AtlasRenderer::New()
282 return Text::RendererPtr( new AtlasRenderer() );
285 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
288 UnparentAndReset( mImpl->mActor );
290 Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
292 if( numberOfGlyphs > 0 )
294 Vector<GlyphInfo> glyphs;
295 glyphs.Resize( numberOfGlyphs );
297 view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
299 std::vector<Vector2> positions;
300 positions.resize( numberOfGlyphs );
301 view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
302 mImpl->AddGlyphs( positions, glyphs );
304 return mImpl->mActor;
307 AtlasRenderer::AtlasRenderer()
313 AtlasRenderer::~AtlasRenderer()