void AtlasManager::GenerateMeshData( ImageId id,
const Vector2& position,
- MeshData& meshData )
+ MeshData& meshData,
+ bool addReference )
{
// Read the atlas Id to use for this image
SizeType imageId = id - 1u;
CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
- // Mesh created so increase the reference count
- mImageList[ imageId ].mCount++;
+ // Mesh created so increase the reference count, if we're asked to
+ if ( addReference )
+ {
+ mImageList[ imageId ].mCount++;
+ }
}
Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
metrics.mTextureMemoryUsed = textureMemoryUsed;
}
-
} // namespace Internal
} // namespace Toolkit
*/
void GenerateMeshData( ImageId id,
const Vector2& position,
- MeshData& mesh );
+ MeshData& mesh,
+ bool addReference );
/**
* @copydoc Toolkit::AtlasManager::StitchMesh
void AtlasManager::GenerateMeshData( ImageId id,
const Vector2& position,
- MeshData& meshData)
+ MeshData& meshData,
+ bool addReference )
{
GetImplementation(*this).GenerateMeshData( id,
position,
- meshData );
+ meshData,
+ addReference );
}
void AtlasManager::StitchMesh( MeshData& first,
* @param[in] id Image Id returned in the AtlasSlot from the add operation
* @param[in] position position of the resulting mesh in model space
* @param[out] mesh Mesh Data Object to populate with mesh data
+ * @param[in] addReference Whether to increase the internal reference count for image or not
*/
void GenerateMeshData( ImageId id,
const Vector2& position,
- MeshData& mesh );
+ MeshData& mesh,
+ bool addReference = true );
/**
* @brief Append second mesh to the first mesh
AtlasGlyphManager::~AtlasGlyphManager()
{
+ // Clear up any remaining references
+ for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+ fontGlyphRecordIt != mFontGlyphRecords.end();
+ ++fontGlyphRecordIt )
+ {
+ for ( Vector< GlyphRecordEntry >::Iterator glyphRecordEntryIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+ glyphRecordEntryIt != fontGlyphRecordIt->mGlyphRecords.End();
+ ++glyphRecordEntryIt )
+ {
+ mAtlasManager.Remove( glyphRecordEntryIt->mImageId );
+ }
+ }
}
AtlasGlyphManagerPtr AtlasGlyphManager::New()
return internal;
}
-void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+void AtlasGlyphManager::Add( Text::FontId fontId,
+ const Text::GlyphInfo& glyph,
const BufferImage& bitmap,
Dali::Toolkit::AtlasManager::AtlasSlot& slot )
{
- GlyphRecord record;
- record.mFontId = glyph.fontId;
- record.mIndex = glyph.index;
-
mAtlasManager.Add( bitmap, slot );
+
+ GlyphRecordEntry record;
+ record.mIndex = glyph.index;
record.mImageId = slot.mImageId;
- mGlyphRecords.PushBack( record );
+ record.mCount = 1;
+
+ // Have glyph records been created for this fontId ?
+ bool foundGlyph = false;
+ for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+ fontGlyphRecordIt != mFontGlyphRecords.end(); ++fontGlyphRecordIt )
+ {
+ if ( fontGlyphRecordIt->mFontId == fontId )
+ {
+ fontGlyphRecordIt->mGlyphRecords.PushBack( record );
+ foundGlyph = true;
+ break;
+ }
+ }
+
+ if ( !foundGlyph )
+ {
+ // We need to add a new font entry
+ FontGlyphRecord fontGlyphRecord;
+ fontGlyphRecord.mFontId = fontId;
+ fontGlyphRecord.mGlyphRecords.PushBack( record );
+ mFontGlyphRecords.push_back( fontGlyphRecord );
+ }
#ifdef DISPLAY_ATLAS
{
const Vector2& position,
MeshData& meshData )
{
- mAtlasManager.GenerateMeshData( imageId, position, meshData );
+ // Generate mesh data and tell Atlas Manager not to handle reference counting ( we'll do it )
+ mAtlasManager.GenerateMeshData( imageId, position, meshData, false );
}
void AtlasGlyphManager::StitchMesh( MeshData& first,
mAtlasManager.StitchMesh( first, second );
}
-void AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::Cached( Text::FontId fontId,
uint32_t index,
Dali::Toolkit::AtlasManager::AtlasSlot& slot )
{
- for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i )
+ for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+ fontGlyphRecordIt != mFontGlyphRecords.end();
+ ++fontGlyphRecordIt )
{
- if ( fontId == mGlyphRecords[ i ].mFontId && index == mGlyphRecords[ i ].mIndex )
+ if ( fontGlyphRecordIt->mFontId == fontId )
{
- slot.mImageId = mGlyphRecords[ i ].mImageId;
- slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
- return;
+ for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+ glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+ ++glyphRecordIt )
+ {
+ if ( glyphRecordIt->mIndex == index )
+ {
+ slot.mImageId = glyphRecordIt->mImageId;
+ slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
+ return true;
+ }
+ }
}
}
slot.mImageId = 0;
+ return false;
}
Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
mAtlasManager.SetNewAtlasSize( size );
}
-void AtlasGlyphManager::Remove( uint32_t imageId )
-{
- if ( mAtlasManager.Remove( imageId ) )
- {
- for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i )
- {
- if ( mGlyphRecords[ i ].mImageId == imageId )
- {
- mGlyphRecords.Remove( mGlyphRecords.Begin() + i );
- return;
- }
- }
- }
-}
-
Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
{
return mAtlasManager.GetPixelFormat( atlasId );
const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
{
- mMetrics.mGlyphCount = mGlyphRecords.Size();
+ mMetrics.mGlyphCount = mFontGlyphRecords.size();
mAtlasManager.GetMetrics( mMetrics.mAtlasMetrics );
return mMetrics;
}
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+{
+ for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+ fontGlyphRecordIt != mFontGlyphRecords.end();
+ ++fontGlyphRecordIt )
+ {
+ if ( fontGlyphRecordIt->mFontId == fontId )
+ {
+ for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+ glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+ ++glyphRecordIt )
+ {
+ if ( glyphRecordIt->mImageId == imageId )
+ {
+ glyphRecordIt->mCount += delta;
+ if ( !glyphRecordIt->mCount )
+ {
+ mAtlasManager.Remove( glyphRecordIt->mImageId );
+ fontGlyphRecordIt->mGlyphRecords.Remove( glyphRecordIt );
+ }
+ return;
+ }
+ }
+ }
+ }
+}
+
} // namespace Internal
} // namespace Toolkit
{
public:
- struct GlyphRecord
+ struct GlyphRecordEntry
{
- Text::FontId mFontId;
Text::GlyphIndex mIndex;
uint32_t mImageId;
+ int32_t mCount;
+ };
+
+ struct FontGlyphRecord
+ {
+ Text::FontId mFontId;
+ Vector< GlyphRecordEntry > mGlyphRecords;
};
AtlasGlyphManager();
/**
* @copydoc Toolkit::AtlasGlyphManager::Add
*/
- void Add( const Text::GlyphInfo& glyph,
+ void Add( Text::FontId fontId,
+ const Text::GlyphInfo& glyph,
const BufferImage& bitmap,
Dali::Toolkit::AtlasManager::AtlasSlot& slot );
/**
* @copydoc Toolkit::AtlasGlyphManager::Cached
*/
- void Cached( Text::FontId fontId,
+ bool Cached( Text::FontId fontId,
Text::GlyphIndex index,
Dali::Toolkit::AtlasManager::AtlasSlot& slot );
void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
/**
- * @copydoc Toolkit::AtlasGlyphManager::Remove
- */
- void Remove( uint32_t imageId );
-
- /**
* @copydoc toolkit::AtlasGlyphManager::GetPixelFormat
*/
Pixel::Format GetPixelFormat( uint32_t atlasId );
*/
const Toolkit::AtlasGlyphManager::Metrics& GetMetrics();
+ /**
+ * @copydoc toolkit::AtlasGlyphManager::AdjustReferenceCount
+ */
+ void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+
private:
Dali::Toolkit::AtlasManager mAtlasManager;
- Vector< GlyphRecord > mGlyphRecords;
+ std::vector< FontGlyphRecord > mFontGlyphRecords;
uint32_t mCount;
Toolkit::AtlasGlyphManager::Metrics mMetrics;
};
{
}
-void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+void AtlasGlyphManager::Add( Text::FontId fontId,
+ const Text::GlyphInfo& glyph,
const BufferImage& bitmap,
AtlasManager::AtlasSlot& slot )
{
- GetImplementation(*this).Add( glyph, bitmap, slot );
+ GetImplementation(*this).Add( fontId, glyph, bitmap, slot );
}
void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
GetImplementation(*this).StitchMesh( first, second );
}
-void AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::Cached( Text::FontId fontId,
Text::GlyphIndex index,
AtlasManager::AtlasSlot& slot )
{
- GetImplementation(*this).Cached( fontId, index, slot );
+ return GetImplementation(*this).Cached( fontId, index, slot );
}
void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
return GetImplementation(*this).GetAtlasSize( atlasId );
}
-void AtlasGlyphManager::Remove( uint32_t imageId )
-{
- GetImplementation(*this).Remove( imageId );
-}
-
Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
{
return GetImplementation(*this).GetPixelFormat( atlasId );
return GetImplementation(*this).GetMetrics();
}
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+{
+ GetImplementation(*this).AdjustReferenceCount( fontId, imageId, delta );
+}
+
} // namespace Toolkit
} // namespace Dali
/**
* @brief Ask Atlas Manager to add a glyph
*
+ * @param[in] fontId fontId glyph comes from
* @param[in] glyph glyph to add to an atlas
* @param[in] bitmap bitmap to use for glyph addition
* @param[out] slot information returned by atlas manager for addition
*/
- void Add( const Text::GlyphInfo& glyph,
+ void Add( Text::FontId fontId,
+ const Text::GlyphInfo& glyph,
const BufferImage& bitmap,
AtlasManager::AtlasSlot& slot );
* @param[in] fontId The font that this glyph comes from
* @param[in] index The GlyphIndex of this glyph
* @param[out] slot container holding information about the glyph( mImage = 0 indicates not being cached )
+ *
+ * @return Whether glyph is cached or not ?
*/
- void Cached( Text::FontId fontId,
+ bool Cached( Text::FontId fontId,
Text::GlyphIndex index,
AtlasManager::AtlasSlot& slot );
void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
/**
- * @brief Unreference an image from the atlas and remove from cache if no longer needed
- *
- * @param[in] imageId ID of the image
- */
- void Remove( uint32_t imageId );
-
- /**
* @brief Get the Pixel Format used by an atlas
*
* @param[in] atlasId Id of atlas to check
*/
const Metrics& GetMetrics();
+ /**
+ * @brief Adjust the reference count for an imageId and remove cache entry if it becomes free
+ *
+ * @param[in] fontId the font this image came from
+ * @param[in] imageId The imageId
+ * @param[in] delta adjustment to make to reference count
+ */
+ void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+
private:
explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl);
uint32_t mMeshRecordIndex;
};
- struct AtlasRecord
+ struct MaxBlockSize
{
- uint32_t mImageId;
+ FontId mFontId;
+ uint32_t mNeededBlockWidth;
+ uint32_t mNeededBlockHeight;
+ };
+
+ struct CheckEntry
+ {
+ FontId mFontId;
Text::GlyphIndex mIndex;
};
- struct MaxBlockSize
+ struct TextCacheEntry
{
FontId mFontId;
- uint32_t mNeededBlockWidth;
- uint32_t mNeededBlockHeight;
+ Text::GlyphIndex mIndex;
+ uint32_t mImageId;
};
Impl()
AtlasManager::AtlasSlot slot;
std::vector< MeshRecord > meshContainer;
Vector< Extent > extents;
+ TextCacheEntry textCacheEntry;
float currentUnderlinePosition = ZERO;
float currentUnderlineThickness = underlineHeight;
style = STYLE_DROP_SHADOW;
}
- if ( mImageIds.Size() )
+ if ( mTextCache.Size() )
{
- // Unreference any currently used glyphs
- RemoveText();
+ // Update the glyph cache with any changes to current text
+ RemoveText( glyphs );
}
CalculateBlocksSize( glyphs );
const Vector2& position = positions[ i ];
MeshData newMeshData;
- mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
- if ( slot.mImageId )
- {
- // This glyph already exists so generate mesh data plugging in our supplied position
- mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
- mImageIds.PushBack( slot.mImageId );
- }
- else
+ if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
{
-
// Select correct size for new atlas if needed....?
if ( lastFontId != glyph.fontId )
{
}
// Locate a new slot for our glyph
- mGlyphManager.Add( glyph, bitmap, slot );
-
- // Generate mesh data for this quad, plugging in our supplied position
- if ( slot.mImageId )
- {
- mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
- mImageIds.PushBack( slot.mImageId );
- }
+ mGlyphManager.Add( glyph.fontId, glyph, bitmap, slot );
}
}
+
+ // Generate mesh data for this quad, plugging in our supplied position
+ mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
+ textCacheEntry.mFontId = glyph.fontId;
+ textCacheEntry.mImageId = slot.mImageId;
+ textCacheEntry.mIndex = glyph.index;
+ mTextCache.PushBack( textCacheEntry );
+
// Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
StitchTextMesh( meshContainer,
newMeshData,
mActor = actor;
}
}
- mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
}
#if defined(DEBUG_ENABLED)
Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
}
}
- // Unreference any glyphs that were used with this actor
- void OffStageDisconnect( Dali::Actor actor )
+ void RemoveText( const Vector<GlyphInfo>& glyphs )
{
- RemoveText();
- }
+ Vector< CheckEntry > checked;
+ CheckEntry checkEntry;
- void RemoveText()
- {
- for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
+ for ( Vector< TextCacheEntry >::Iterator tCit = mTextCache.Begin(); tCit != mTextCache.End(); ++tCit )
{
- mGlyphManager.Remove( mImageIds[ i ] );
+ uint32_t index = tCit->mIndex;
+ uint32_t fontId = tCit->mFontId;
+
+ // Check that this character has not already been checked...
+ bool wasChecked = false;
+ for ( Vector< CheckEntry >::Iterator cEit = checked.Begin(); cEit != checked.End(); ++cEit )
+ {
+ if ( fontId == cEit->mFontId && index == cEit->mIndex )
+ {
+ wasChecked = true;
+ }
+ }
+
+ if ( !wasChecked )
+ {
+
+ int32_t newCount = 0;
+ int32_t oldCount = 0;
+
+ // How many times does this character occur in the old text ?
+ for ( Vector< TextCacheEntry >::Iterator oTcit = mTextCache.Begin(); oTcit != mTextCache.End(); ++oTcit )
+ {
+ if ( fontId == oTcit->mFontId && index == oTcit->mIndex )
+ {
+ oldCount++;
+ }
+ }
+
+ // And how many times in the new ?
+ for ( Vector< GlyphInfo >::Iterator cGit = glyphs.Begin(); cGit != glyphs.End(); ++cGit )
+ {
+ if ( fontId == cGit->fontId && index == cGit->index )
+ {
+ newCount++;
+ }
+ }
+ mGlyphManager.AdjustReferenceCount( fontId, tCit->mImageId, newCount - oldCount );
+ checkEntry.mIndex = index;
+ checkEntry.mFontId = fontId;
+ checked.PushBack( checkEntry );
+ }
}
- mImageIds.Resize( 0 );
+ mTextCache.Resize( 0 );
}
void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
RenderableActor mActor; ///< The actor parent which renders the text
AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching
- Vector< uint32_t > mImageIds; ///< A list of imageIDs used by the renderer
TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
ShaderEffect mBasicShader; ///> Shader used to render L8 glyphs
ShaderEffect mBgraShader; ///> Shader used to render BGRA glyphs
ShaderEffect mBasicShadowShader; ///> Shader used to render drop shadow into buffer
std::vector< MaxBlockSize > mBlockSizes; ///> Maximum size needed to contain a glyph in a block within a new atlas
std::vector< MeshData::FaceIndex > mFace; ///> Face indices for a quad
+ Vector< TextCacheEntry > mTextCache;
};
Text::RendererPtr AtlasRenderer::New()
AtlasRenderer::~AtlasRenderer()
{
+ Vector< GlyphInfo > emptyGlyphs;
+ mImpl->RemoveText( emptyGlyphs );
delete mImpl;
}