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=62865d6ee031c0dfffc8f589c9914062401086e9;hp=2332c7a500cdf774a34902ea988c1d53ef020651;hb=6bc33c55ece7fc30d8229f35e6e9f8b807a9a437;hpb=c57e053b5795783ad92b0fd7f8fbaba6b6d9322a 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 2332c7a..62865d6 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include // INTERNAL INCLUDES #include @@ -42,11 +43,58 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_RENDERING"); #endif +#define MAKE_SHADER(A)#A + +const char* VERTEX_SHADER = MAKE_SHADER( +attribute mediump vec2 aPosition; +attribute mediump vec2 aTexCoord; +attribute mediump vec4 aColor; +uniform mediump vec2 uOffset; +uniform mediump mat4 uMvpMatrix; +varying mediump vec2 vTexCoord; +varying mediump vec4 vColor; + +void main() +{ + mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 ); + gl_Position = uMvpMatrix * position; + vTexCoord = aTexCoord; + vColor = aColor; +} +); + +const char* FRAGMENT_SHADER_L8 = MAKE_SHADER( +uniform lowp vec4 uColor; +uniform lowp vec4 textColorAnimatable; +uniform sampler2D sTexture; +varying mediump vec2 vTexCoord; +varying mediump vec4 vColor; + +void main() +{ + mediump vec4 color = texture2D( sTexture, vTexCoord ); + gl_FragColor = vec4( vColor.rgb * uColor.rgb * textColorAnimatable.rgb, uColor.a * vColor.a * textColorAnimatable.a * color.r ); +} +); + +const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER( +uniform lowp vec4 uColor; +uniform lowp vec4 textColorAnimatable; +uniform sampler2D sTexture; +varying mediump vec2 vTexCoord; + +void main() +{ + gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * textColorAnimatable; +} +); + const float ZERO( 0.0f ); const float HALF( 0.5f ); const float ONE( 1.0f ); const uint32_t DEFAULT_ATLAS_WIDTH = 512u; const uint32_t DEFAULT_ATLAS_HEIGHT = 512u; +const int NO_OUTLINE( 0 ); } struct AtlasRenderer::Impl @@ -164,6 +212,8 @@ struct AtlasRenderer::Impl } void AddGlyphs( Text::ViewInterface& view, + Actor textControl, + Property::Index animatablePropertyIndex, const Vector& positions, const Vector& glyphs, const Vector4& defaultColor, @@ -266,58 +316,79 @@ struct AtlasRenderer::Impl lastUnderlinedFontId = glyph.fontId; } // underline - if( !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ) ) + bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ); // Check FontGlyphRecord vector for entry with glyph index and fontId + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached)?"not cached":"cached" ); + + if( glyphNotCached ) { - // Select correct size for new atlas if needed....? - if( lastFontId != glyph.fontId ) + MaxBlockSize& blockSize = mBlockSizes[currentBlockSize]; + + if ( lastFontId != glyph.fontId ) { uint32_t index = 0u; + // Looks through all stored block sizes until finds the one which mataches required glyph font it. Ensures new atlas block size will match existing for same font id. + // CalculateBlocksSize() above ensures a block size entry exists. for( std::vector::const_iterator it = mBlockSizes.begin(), endIt = mBlockSizes.end(); it != endIt; ++it, ++index ) { - const MaxBlockSize& blockSize = *it; - if( blockSize.mFontId == glyph.fontId ) + const MaxBlockSize& blockSizeEntry = *it; + if( blockSizeEntry.mFontId == glyph.fontId ) { - currentBlockSize = index; - mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH, - DEFAULT_ATLAS_HEIGHT, - blockSize.mNeededBlockWidth, - blockSize.mNeededBlockHeight ); + blockSize = mBlockSizes[index]; } } } // Create a new image for the glyph - PixelData bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index ); + PixelData bitmap; + + // Whether the current glyph is a color one. + const bool isColorGlyph = mFontClient.IsColorGlyph( glyph.fontId, glyph.index ); + + // Retrieve the emoji's bitmap. + TextAbstraction::FontClient::GlyphBufferData glyphBufferData; + glyphBufferData.width = isColorGlyph ? glyph.width : 0; // Desired width and height. + glyphBufferData.height = isColorGlyph ? glyph.height : 0; + + mFontClient.CreateBitmap( glyph.fontId, + glyph.index, + glyphBufferData, + NO_OUTLINE ); + + // Create the pixel data. + bitmap = PixelData::New( glyphBufferData.buffer, + glyph.width * glyph.height * GetBytesPerPixel( glyphBufferData.format ), + glyph.width, + glyph.height, + glyphBufferData.format, + PixelData::DELETE_ARRAY ); + if( bitmap ) { - MaxBlockSize& blockSize = mBlockSizes[currentBlockSize]; - // Ensure that the next image will fit into the current block size - bool setSize = false; if( bitmap.GetWidth() > blockSize.mNeededBlockWidth ) { - setSize = true; blockSize.mNeededBlockWidth = bitmap.GetWidth(); } + if( bitmap.GetHeight() > blockSize.mNeededBlockHeight ) { - setSize = true; blockSize.mNeededBlockHeight = bitmap.GetHeight(); } - if( setSize ) - { - mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH, - DEFAULT_ATLAS_HEIGHT, - blockSize.mNeededBlockWidth, - blockSize.mNeededBlockHeight ); - } + // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas + + // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice. + mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH, + DEFAULT_ATLAS_HEIGHT, + blockSize.mNeededBlockWidth, + blockSize.mNeededBlockHeight ); // Locate a new slot for our glyph - mGlyphManager.Add( glyph, bitmap, slot ); + mGlyphManager.Add( glyph, bitmap, slot ); // slot will be 0 is glyph not added } } else @@ -329,55 +400,44 @@ struct AtlasRenderer::Impl // Move the origin (0,0) of the mesh to the center of the actor const Vector2 position = *( positionsBuffer + i ) - halfTextSize - lineOffsetPosition; - // 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 ); + if ( 0u != slot.mImageId ) // invalid slot id, glyph has failed to be added to atlas + { + // 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 ); - AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin(); + AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin(); + + // Get the color of the character. + const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i ); + const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u ); - // Adjust the vertices if the fixed-size font should be down-scaled - if( glyph.scaleFactor > 0 ) - { for( unsigned int index = 0u, size = newMesh.mVertices.Count(); index < size; ++index ) { AtlasManager::Vertex2D& vertex = *( verticesBuffer + index ); - // Set the position of the vertex. - vertex.mPosition.x = position.x + ( ( vertex.mPosition.x - position.x ) * glyph.scaleFactor ); - vertex.mPosition.y = position.y + ( ( vertex.mPosition.y - position.y ) * glyph.scaleFactor ); + // Set the color of the vertex. + vertex.mColor = color; } - } - // Get the color of the character. - const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i ); - const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u ); - - for( unsigned int index = 0u, size = newMesh.mVertices.Count(); - index < size; - ++index ) - { - AtlasManager::Vertex2D& vertex = *( verticesBuffer + index ); - - // Set the color of the vertex. - vertex.mColor = color; + // 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, + newMesh, + extents, + position.y + glyph.yBearing, + underlineGlyph, + currentUnderlinePosition, + currentUnderlineThickness, + slot ); + + lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId. } - - // 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, - newMesh, - extents, - position.y + glyph.yBearing, - underlineGlyph, - currentUnderlinePosition, - currentUnderlineThickness, - slot ); - lastFontId = glyph.fontId; } } // glyphs @@ -401,6 +461,7 @@ struct AtlasRenderer::Impl mActor.SetParentOrigin( ParentOrigin::TOP_LEFT ); mActor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); mActor.SetSize( textSize ); + mActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); } for( std::vector< MeshRecord >::iterator it = meshContainer.begin(), @@ -409,7 +470,7 @@ struct AtlasRenderer::Impl { MeshRecord& meshRecord = *it; - Actor actor = CreateMeshActor( meshRecord, textSize ); + Actor actor = CreateMeshActor( textControl, animatablePropertyIndex, defaultColor, meshRecord, textSize, STYLE_NORMAL ); // Whether the actor has renderers. const bool hasRenderer = actor.GetRendererCount() > 0u; @@ -429,7 +490,7 @@ struct AtlasRenderer::Impl vertex.mColor = shadowColor; } - Actor shadowActor = CreateMeshActor( meshRecord, textSize ); + Actor shadowActor = CreateMeshActor(textControl, animatablePropertyIndex, defaultColor, meshRecord, textSize, STYLE_DROP_SHADOW ); #if defined(DEBUG_ENABLED) shadowActor.SetName( "Text Shadow renderable actor" ); #endif @@ -480,7 +541,8 @@ struct AtlasRenderer::Impl mTextCache.Resize( 0 ); } - Actor CreateMeshActor( const MeshRecord& meshRecord, const Vector2& actorSize ) + Actor CreateMeshActor( Actor textControl, Property::Index animatablePropertyIndex, const Vector4& defaultColor, const MeshRecord& meshRecord, + const Vector2& actorSize, Style style ) { PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat ); quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ), meshRecord.mMesh.mVertices.Size() ); @@ -490,22 +552,65 @@ struct AtlasRenderer::Impl quadGeometry.SetIndexBuffer( &meshRecord.mMesh.mIndices[0], meshRecord.mMesh.mIndices.Size() ); TextureSet textureSet( mGlyphManager.GetTextures( meshRecord.mAtlasId ) ); - Shader shader( mGlyphManager.GetShader( meshRecord.mAtlasId ) ); + + // Choose the shader to use. + const bool isColorShader = ( STYLE_DROP_SHADOW != style ) && ( Pixel::BGRA8888 == mGlyphManager.GetPixelFormat( meshRecord.mAtlasId ) ); + Shader shader; + if( isColorShader ) + { + // The glyph is an emoji and is not a shadow. + if( !mShaderRgba ) + { + mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA ); + } + shader = mShaderRgba; + } + else + { + // The glyph is text or a shadow. + if( !mShaderL8 ) + { + mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 ); + } + shader = mShaderL8; + } + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "defaultColor[%f, %f, %f, %f ]\n", defaultColor.r, defaultColor.g, defaultColor.b, defaultColor.a ); + + Dali::Property::Index shaderTextColorIndex = shader.RegisterProperty( "textColorAnimatable", defaultColor ); + + if ( animatablePropertyIndex != Property::INVALID_INDEX ) + { + // create constraint for the animatable text's color Property with textColorAnimatable in the shader. + if( shaderTextColorIndex ) + { + Constraint constraint = Constraint::New( shader, shaderTextColorIndex, EqualToConstraint() ); + constraint.AddSource( Source( textControl, animatablePropertyIndex ) ); + constraint.Apply(); + } + } + else + { + // If not animating the text colour then set to 1's so shader uses the current vertex color + shader.RegisterProperty( "textColorAnimatable", Vector4(1.0, 1.0, 1.0, 1.0 ) ); + } + Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, shader ); renderer.SetTextures( textureSet ); renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON ); renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + mDepth ); + Actor actor = Actor::New(); #if defined(DEBUG_ENABLED) actor.SetName( "Text renderable actor" ); #endif actor.AddRenderer( renderer ); - // Keep all of the origins aligned actor.SetParentOrigin( ParentOrigin::TOP_LEFT ); actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); actor.SetSize( actorSize ); actor.RegisterProperty("uOffset", Vector2::ZERO ); + actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); return actor; } @@ -637,8 +742,9 @@ struct AtlasRenderer::Impl blockIt != blockEndIt; ++blockIt ) { - if( (*blockIt).mFontId == fontId ) + if( (*blockIt).mFontId == fontId ) // Different size fonts will have a different fontId { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize match found fontID(%u) glyphIndex(%u)\n", fontId, (*glyphIt).index ); foundFont = true; break; } @@ -653,7 +759,7 @@ struct AtlasRenderer::Impl maxBlockSize.mNeededBlockWidth = static_cast< uint32_t >( fontMetrics.height ); maxBlockSize.mNeededBlockHeight = maxBlockSize.mNeededBlockWidth; maxBlockSize.mFontId = fontId; - + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize New font with no matched blocksize, setting blocksize[%u]\n", maxBlockSize.mNeededBlockWidth ); mBlockSizes.push_back( maxBlockSize ); } } @@ -723,11 +829,13 @@ struct AtlasRenderer::Impl 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 - Vector< TextCacheEntry > mTextCache; ///> Caches data from previous render - Property::Map mQuadVertexFormat; ///> Describes the vertex format for text - int mDepth; ///> DepthIndex passed by control when connect to stage + TextAbstraction::FontClient mFontClient; ///< The font client used to supply glyph information + Shader mShaderL8; ///< The shader for glyphs and emoji's shadows. + Shader mShaderRgba; ///< The shader for emojis. + std::vector< MaxBlockSize > mBlockSizes; ///< Maximum size needed to contain a glyph in a block within a new atlas + Vector< TextCacheEntry > mTextCache; ///< Caches data from previous render + Property::Map mQuadVertexFormat; ///< Describes the vertex format for text + int mDepth; ///< DepthIndex passed by control when connect to stage }; Text::RendererPtr AtlasRenderer::New() @@ -738,6 +846,8 @@ Text::RendererPtr AtlasRenderer::New() } Actor AtlasRenderer::Render( Text::ViewInterface& view, + Actor textControl, + Property::Index animatablePropertyIndex, float& alignmentOffset, int depth ) { @@ -769,6 +879,8 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view, const Vector4& defaultColor = view.GetTextColor(); mImpl->AddGlyphs( view, + textControl, + animatablePropertyIndex, positions, glyphs, defaultColor,