X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Frendering%2Fatlas%2Ftext-atlas-renderer.cpp;h=8653b435ed274327adde6e596d2dff8eab9b90e1;hp=d0cedf42a5dae24f43d8f33dbb4ccbc44b6be83a;hb=225ea9dd33c2d8669d8dac1f2b116eeb2ea00c0d;hpb=d41c68d7d25046369262fd8a238a80d3eea21034 diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp index d0cedf4..8653b43 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -19,17 +19,17 @@ #include // EXTERNAL INCLUDES -#include -#include -#include +#include #include -#include -#include +#include #include -#include + // INTERNAL INCLUDES #include +#include #include +#include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -44,13 +44,12 @@ namespace const float ZERO( 0.0f ); const float HALF( 0.5f ); const float ONE( 1.0f ); -const float TWO( 2.0f ); const uint32_t DEFAULT_ATLAS_WIDTH = 512u; const uint32_t DEFAULT_ATLAS_HEIGHT = 512u; } -struct AtlasRenderer::Impl : public ConnectionTracker -{ +struct AtlasRenderer::Impl +{ enum Style { STYLE_NORMAL, @@ -59,15 +58,34 @@ struct AtlasRenderer::Impl : public ConnectionTracker struct MeshRecord { + MeshRecord() + : mColor( Color::BLACK ), + mAtlasId( 0 ) + { + } + Vector4 mColor; uint32_t mAtlasId; AtlasManager::Mesh2D mMesh; FrameBufferImage mBuffer; - bool mIsUnderline; }; + /** + * brief Struct used to generate the underline mesh. + * There is one Extent per line of text. + */ struct Extent { + Extent() + : mBaseLine( 0.0f ), + mLeft( 0.0f ), + mRight( 0.0f ), + mUnderlinePosition( 0.0f ), + mUnderlineThickness( 0.0f ), + mMeshRecordIndex( 0 ) + { + } + float mBaseLine; float mLeft; float mRight; @@ -78,6 +96,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker struct MaxBlockSize { + MaxBlockSize() + : mFontId( 0 ), + mNeededBlockWidth( 0 ), + mNeededBlockHeight( 0 ) + { + } + FontId mFontId; uint32_t mNeededBlockWidth; uint32_t mNeededBlockHeight; @@ -85,12 +110,25 @@ struct AtlasRenderer::Impl : public ConnectionTracker struct CheckEntry { + CheckEntry() + : mFontId( 0 ), + mIndex( 0 ) + { + } + FontId mFontId; Text::GlyphIndex mIndex; }; struct TextCacheEntry { + TextCacheEntry() + : mFontId( 0 ), + mIndex( 0 ), + mImageId( 0 ) + { + } + FontId mFontId; Text::GlyphIndex mIndex; uint32_t mImageId; @@ -107,14 +145,28 @@ struct AtlasRenderer::Impl : public ConnectionTracker mQuadIndexFormat[ "indices" ] = Property::INTEGER; } - void AddGlyphs( const std::vector& positions, + bool IsGlyphUnderlined( GlyphIndex index, + const Vector& underlineRuns ) + { + for( Vector::ConstIterator it = underlineRuns.Begin(), + endIt = underlineRuns.End(); + it != endIt; + ++it ) + { + const GlyphRun& run = *it; + + if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) ) + { + return true; + } + } + + return false; + } + + void AddGlyphs( Text::ViewInterface& view, + const Vector& positions, const Vector& glyphs, - const Vector4& textColor, - const Vector2& shadowOffset, - const Vector4& shadowColor, - bool underlineEnabled, - const Vector4& underlineColor, - float underlineHeight, int depth ) { AtlasManager::AtlasSlot slot; @@ -123,10 +175,30 @@ struct AtlasRenderer::Impl : public ConnectionTracker TextCacheEntry textCacheEntry; mDepth = depth; + const Vector2& actorSize( view.GetControlSize() ); + const Vector2 halfActorSize( actorSize * 0.5f ); + const Vector4& textColor( view.GetTextColor() ); + const Vector2& shadowOffset( view.GetShadowOffset() ); + const Vector4& shadowColor( view.GetShadowColor() ); + const bool underlineEnabled( view.IsUnderlineEnabled() ); + const Vector4& underlineColor( view.GetUnderlineColor() ); + const float underlineHeight( view.GetUnderlineHeight() ); + + // Get the underline runs. + const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns(); + Vector underlineRuns; + underlineRuns.Resize( numberOfUnderlineRuns ); + view.GetUnderlineRuns( underlineRuns.Begin(), + 0u, + numberOfUnderlineRuns ); + + bool thereAreUnderlinedGlyphs = false; + float currentUnderlinePosition = ZERO; float currentUnderlineThickness = underlineHeight; uint32_t currentBlockSize = 0; FontId lastFontId = 0; + FontId lastUnderlinedFontId = 0; Style style = STYLE_NORMAL; if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 ) @@ -138,22 +210,27 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Avoid emptying mTextCache (& removing references) until after incremented references for the new text Vector< TextCacheEntry > newTextCache; + const GlyphInfo* const glyphsBuffer = glyphs.Begin(); + const Vector2* const positionsBuffer = positions.Begin(); for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i ) { - const GlyphInfo& glyph = glyphs[ i ]; + const GlyphInfo& glyph = *( glyphsBuffer + i ); + + const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( i, underlineRuns ); + thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph; // No operation for white space if ( glyph.width && glyph.height ) { // Are we still using the same fontId as previous - if ( glyph.fontId != lastFontId ) + if ( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) ) { // We need to fetch fresh font underline metrics FontMetrics fontMetrics; mFontClient.GetFontMetrics( glyph.fontId, fontMetrics ); currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) ); - float descender = ceil( fabsf( fontMetrics.descender ) ); + const float descender = ceil( fabsf( fontMetrics.descender ) ); if ( underlineHeight == ZERO ) { @@ -180,12 +257,11 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Move offset down by one ( EFL behavior ) currentUnderlinePosition = ONE; } - } - const Vector2& position = positions[ i ]; - AtlasManager::Mesh2D newMesh; + lastUnderlinedFontId = glyph.fontId; + } // underline - if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) ) + if ( !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ) ) { // Select correct size for new atlas if needed....? if ( lastFontId != glyph.fontId ) @@ -238,31 +314,46 @@ struct AtlasRenderer::Impl : public ConnectionTracker mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, 1/*increment*/ ); } + // Move the origin (0,0) of the mesh to the center of the actor + Vector2 position = *( positionsBuffer + i ) - halfActorSize; + // Generate mesh data for this quad, plugging in our supplied position + AtlasManager::Mesh2D newMesh; mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh ); textCacheEntry.mFontId = glyph.fontId; textCacheEntry.mImageId = slot.mImageId; textCacheEntry.mIndex = glyph.index; newTextCache.PushBack( textCacheEntry ); + // Adjust the vertices if the fixed-size font should be down-scaled + if( glyph.scaleFactor > 0 ) + { + for( unsigned int i=0; i::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt ) { - Actor actor = CreateMeshActor( *mIt ); + Actor actor = CreateMeshActor( *mIt, actorSize ); // Create an effect if necessary if ( style == STYLE_DROP_SHADOW ) { - actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) ); + // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues. + Actor containerActor = Actor::New(); + containerActor.SetParentOrigin( ParentOrigin::CENTER ); + containerActor.SetSize( actorSize ); + + Actor shadowActor = Actor::New(); +#if defined(DEBUG_ENABLED) + shadowActor.SetName( "Text Shadow renderable actor" ); +#endif + // Offset shadow in x and y + shadowActor.RegisterProperty("uOffset", shadowOffset ); + if ( actor.GetRendererCount() ) + { + Dali::Renderer renderer( actor.GetRendererAt( 0 ) ); + Geometry geometry = renderer.GetGeometry(); + Material material = renderer.GetMaterial(); + + Dali::Renderer shadowRenderer = Dali::Renderer::New( geometry, material ); + shadowRenderer.SetDepthIndex( renderer.GetDepthIndex() - 1 ); + shadowActor.AddRenderer( shadowRenderer ); + shadowActor.SetParentOrigin( ParentOrigin::CENTER ); + shadowActor.SetSize( actorSize ); + shadowActor.SetColor( shadowColor ); + containerActor.Add( shadowActor ); + containerActor.Add( actor ); + actor = containerActor; + } } if( mActor ) { - actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned mActor.Add( actor ); } else @@ -325,7 +441,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker mTextCache.Resize( 0 ); } - Actor CreateMeshActor( const MeshRecord& meshRecord ) + Actor CreateMeshActor( const MeshRecord& meshRecord, const Vector2& actorSize ) { PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() ); PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() ); @@ -344,17 +460,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker actor.SetName( "Text renderable actor" ); #endif actor.AddRenderer( renderer ); - actor.SetSize( 1.0f, 1.0f ); + actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned + actor.SetSize( actorSize ); actor.SetColor( meshRecord.mColor ); - - if ( meshRecord.mIsUnderline ) - { - actor.SetColorMode( USE_OWN_COLOR ); - } - else - { - actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); - } + actor.RegisterProperty("uOffset", Vector2::ZERO ); return actor; } @@ -363,6 +472,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker Vector< Extent >& extents, const Vector4& color, float baseLine, + bool underlineGlyph, float underlinePosition, float underlineThickness, AtlasManager::AtlasSlot& slot ) @@ -374,20 +484,28 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Check to see if there's a mesh data object that references the same atlas ? uint32_t index = 0; - for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index ) + for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(), + mEndIt = meshContainer.end(); + mIt != mEndIt; + ++mIt, ++index ) { if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor ) { - // Stitch the mesh to the existing mesh and adjust any extents - mGlyphManager.StitchMesh( mIt->mMesh, newMesh ); - AdjustExtents( extents, - meshContainer, - index, - left, - right, - baseLine, - underlinePosition, - underlineThickness ); + // Append the mesh to the existing mesh and adjust any extents + Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh ); + + if( underlineGlyph ) + { + AdjustExtents( extents, + meshContainer, + index, + left, + right, + baseLine, + underlinePosition, + underlineThickness ); + } + return; } } @@ -397,19 +515,20 @@ struct AtlasRenderer::Impl : public ConnectionTracker meshRecord.mAtlasId = slot.mAtlasId; meshRecord.mMesh = newMesh; meshRecord.mColor = color; - meshRecord.mIsUnderline = false; meshContainer.push_back( meshRecord ); - // Adjust extents for this new meshrecord - AdjustExtents( extents, - meshContainer, - meshContainer.size() - 1u, - left, - right, - baseLine, - underlinePosition, - underlineThickness ); - + if( underlineGlyph ) + { + // Adjust extents for this new meshrecord + AdjustExtents( extents, + meshContainer, + meshContainer.size() - 1u, + left, + right, + baseLine, + underlinePosition, + underlineThickness ); + } } } @@ -423,7 +542,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker float underlineThickness ) { bool foundExtent = false; - for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt ) + for ( Vector< Extent >::Iterator eIt = extents.Begin(), + eEndIt = extents.End(); + eIt != eEndIt; + ++eIt ) { if ( Equals( baseLine, eIt->mBaseLine ) ) { @@ -486,14 +608,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker } } - void GenerateUnderlines( std::vector< MeshRecord>& meshRecords, + void GenerateUnderlines( std::vector< MeshRecord >& meshRecords, Vector< Extent >& extents, const Vector4& underlineColor, const Vector4& textColor ) { AtlasManager::Mesh2D newMesh; unsigned short faceIndex = 0; - for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt ) + for ( Vector< Extent >::ConstIterator eIt = extents.Begin(), + eEndIt = extents.End(); + eIt != eEndIt; + ++eIt ) { AtlasManager::Vertex2D vert; uint32_t index = eIt->mMeshRecordIndex; @@ -540,7 +665,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker if ( underlineColor == textColor ) { - mGlyphManager.StitchMesh( meshRecords[ index ].mMesh, newMesh ); + Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh ); } else { @@ -548,151 +673,19 @@ struct AtlasRenderer::Impl : public ConnectionTracker record.mMesh = newMesh; record.mAtlasId = meshRecords[ index ].mAtlasId; record.mColor = underlineColor; - record.mIsUnderline = true; meshRecords.push_back( record ); } } } - Actor GenerateShadow( MeshRecord& meshRecord, - const Vector2& shadowOffset, - const Vector4& shadowColor ) - { - // Scan vertex buffer to determine width and height of effect buffer needed - const Vector< AtlasManager::Vertex2D >& verts = meshRecord.mMesh.mVertices; - float tlx = verts[ 0 ].mPosition.x; - float tly = verts[ 0 ].mPosition.y; - float brx = ZERO; - float bry = ZERO; - - for ( uint32_t i = 0; i < verts.Size(); ++i ) - { - if ( verts[ i ].mPosition.x < tlx ) - { - tlx = verts[ i ].mPosition.x; - } - if ( verts[ i ].mPosition.y < tly ) - { - tly = verts[ i ].mPosition.y; - } - if ( verts[ i ].mPosition.x > brx ) - { - brx = verts[ i ].mPosition.x; - } - if ( verts[ i ].mPosition.y > bry ) - { - bry = verts[ i ].mPosition.y; - } - } - - float width = brx - tlx; - float height = bry - tly; - float divWidth = TWO / width; - float divHeight = TWO / height; - - // Create a buffer to render to - meshRecord.mBuffer = FrameBufferImage::New( width, height ); - - // We will render a quad into this buffer - unsigned int indices[ 6 ] = { 1, 0, 2, 2, 3, 1 }; - PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, 4u ); - PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, sizeof(indices)/sizeof(indices[0]) ); - - AtlasManager::Vertex2D vertices[ 4 ] = { - { Vector2( tlx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ZERO, ZERO ) }, - { Vector2( brx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ONE, ZERO ) }, - { Vector2( tlx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ZERO, ONE ) }, - { Vector2( brx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ONE, ONE ) } }; - - quadVertices.SetData( vertices ); - quadIndices.SetData( indices ); - - Geometry quadGeometry = Geometry::New(); - quadGeometry.AddVertexBuffer( quadVertices ); - quadGeometry.SetIndexBuffer( quadIndices ); - - Sampler sampler = Sampler::New( meshRecord.mBuffer, "sTexture" ); - Material material = Material::New( mGlyphManager.GetEffectBufferShader() ); - material.AddSampler( sampler ); - - Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material ); - - // Ensure shadow is behind the text... - renderer.SetDepthIndex( CONTENT_DEPTH_INDEX + mDepth - 1 ); - Actor actor = Actor::New(); - actor.AddRenderer( renderer ); - actor.SetSize( 1.0f, 1.0f ); - - // Create a sub actor to render the source with normalized vertex positions - Vector< AtlasManager::Vertex2D > normVertexList; - for ( uint32_t i = 0; i < verts.Size(); ++i ) - { - AtlasManager::Vertex2D vertex = verts[ i ]; - vertex.mPosition.x = ( ( vertex.mPosition.x - tlx ) * divWidth ) - ONE; - vertex.mPosition.y = ( ( vertex.mPosition.y - tly ) * divHeight ) - ONE; - normVertexList.PushBack( vertex ); - } - - PropertyBuffer normVertices = PropertyBuffer::New( mQuadVertexFormat, normVertexList.Size() ); - PropertyBuffer normIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() ); - normVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &normVertexList[ 0 ] ) ); - normIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) ); - - Geometry normGeometry = Geometry::New(); - normGeometry.AddVertexBuffer( normVertices ); - normGeometry.SetIndexBuffer( normIndices ); - - Material normMaterial = Material::New( mGlyphManager.GetGlyphShadowShader() ); - Sampler normSampler = mGlyphManager.GetSampler( meshRecord.mAtlasId ); - normMaterial.AddSampler( normSampler ); - Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial ); - Actor subActor = Actor::New(); - subActor.AddRenderer( normRenderer ); - subActor.SetSize( 1.0f, 1.0f ); - subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); - subActor.SetColor( shadowColor ); - - // Create a render task to render the effect - RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask(); - task.SetTargetFrameBuffer( meshRecord.mBuffer ); - task.SetSourceActor( subActor ); - task.SetClearEnabled( true ); - task.SetClearColor( Vector4::ZERO ); - task.SetExclusive( true ); - task.SetRefreshRate( RenderTask::REFRESH_ONCE ); - task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete ); - actor.Add( subActor ); - - return actor; - } - - void RenderComplete( RenderTask& renderTask ) - { - // Disconnect and remove this single shot render task - renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete ); - Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask ); - - // Get the actor used for render to buffer and remove it from the parent - Actor renderActor = renderTask.GetSourceActor(); - if ( renderActor ) - { - Actor parent = renderActor.GetParent(); - if ( parent ) - { - parent.Remove( renderActor ); - } - } - } - Actor mActor; ///< The actor parent which renders the text AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information std::vector< MaxBlockSize > mBlockSizes; ///> Maximum size needed to contain a glyph in a block within a new atlas - std::vector< uint32_t > mFace; ///> Face indices for a quad - Vector< TextCacheEntry > mTextCache; - Property::Map mQuadVertexFormat; - Property::Map mQuadIndexFormat; - int mDepth; + Vector< TextCacheEntry > mTextCache; ///> Caches data from previous render + Property::Map mQuadVertexFormat; ///> Describes the vertex format for text + Property::Map mQuadIndexFormat; ///> Describes the index format for text + int mDepth; ///> DepthIndex passed by control when connect to stage }; Text::RendererPtr AtlasRenderer::New() @@ -713,24 +706,19 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth ) Vector glyphs; glyphs.Resize( numberOfGlyphs ); - std::vector positions; - positions.resize( numberOfGlyphs ); + Vector positions; + positions.Resize( numberOfGlyphs ); numberOfGlyphs = view.GetGlyphs( glyphs.Begin(), - &positions[0], + positions.Begin(), 0u, numberOfGlyphs ); glyphs.Resize( numberOfGlyphs ); - positions.resize( numberOfGlyphs ); + positions.Resize( numberOfGlyphs ); - mImpl->AddGlyphs( positions, + mImpl->AddGlyphs( view, + positions, glyphs, - view.GetTextColor(), - view.GetShadowOffset(), - view.GetShadowColor(), - view.IsUnderlineEnabled(), - view.GetUnderlineColor(), - view.GetUnderlineHeight(), depth ); }