From 225ea9dd33c2d8669d8dac1f2b116eeb2ea00c0d Mon Sep 17 00:00:00 2001 From: Richard Underhill Date: Thu, 15 Oct 2015 14:25:00 +0100 Subject: [PATCH] Text Shadow Implementation via copied renderer. Change-Id: I1549e0b0c788b252ad176210f503c76397112e51 Signed-off-by: Richard Underhill --- dali-toolkit/internal/file.list | 5 +- .../rendering/atlas/atlas-glyph-manager-impl.cpp | 60 ++- .../rendering/atlas/atlas-glyph-manager-impl.h | 40 +- .../text/rendering/atlas/atlas-glyph-manager.cpp | 29 +- .../text/rendering/atlas/atlas-glyph-manager.h | 40 +- .../rendering/atlas}/atlas-manager-impl.cpp | 446 ++++----------------- .../rendering/atlas}/atlas-manager-impl.h | 42 +- .../rendering/atlas}/atlas-manager.cpp | 21 +- .../rendering/atlas}/atlas-manager.h | 152 +------ .../text/rendering/atlas/atlas-mesh-factory.cpp | 166 ++++++++ .../text/rendering/atlas/atlas-mesh-factory.h | 70 ++++ .../text/rendering/atlas/text-atlas-renderer.cpp | 218 ++-------- 12 files changed, 416 insertions(+), 873 deletions(-) rename dali-toolkit/internal/{atlas-manager => text/rendering/atlas}/atlas-manager-impl.cpp (50%) rename dali-toolkit/internal/{atlas-manager => text/rendering/atlas}/atlas-manager-impl.h (82%) rename dali-toolkit/internal/{atlas-manager => text/rendering/atlas}/atlas-manager.cpp (84%) rename dali-toolkit/internal/{atlas-manager => text/rendering/atlas}/atlas-manager.h (62%) create mode 100644 dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp create mode 100644 dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 9ecd378..34d10cc 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -1,8 +1,6 @@ # Add local source files here toolkit_src_files = \ - $(toolkit_src_dir)/atlas-manager/atlas-manager.cpp \ - $(toolkit_src_dir)/atlas-manager/atlas-manager-impl.cpp \ $(toolkit_src_dir)/builder/builder-actor.cpp \ $(toolkit_src_dir)/builder/builder-animations.cpp \ $(toolkit_src_dir)/builder/builder-impl.cpp \ @@ -99,6 +97,9 @@ toolkit_src_files = \ $(toolkit_src_dir)/text/rendering/atlas/text-atlas-renderer.cpp \ $(toolkit_src_dir)/text/rendering/atlas/atlas-glyph-manager.cpp \ $(toolkit_src_dir)/text/rendering/atlas/atlas-glyph-manager-impl.cpp \ + $(toolkit_src_dir)/text/rendering/atlas/atlas-manager.cpp \ + $(toolkit_src_dir)/text/rendering/atlas/atlas-manager-impl.cpp \ + $(toolkit_src_dir)/text/rendering/atlas/atlas-mesh-factory.cpp \ $(toolkit_src_dir)/text/rendering/text-backend-impl.cpp \ $(toolkit_src_dir)/transition-effects/cube-transition-effect-impl.cpp \ $(toolkit_src_dir)/transition-effects/cube-transition-cross-effect-impl.cpp \ diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp index 92c5b42..f2c328e 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp @@ -20,8 +20,6 @@ // EXTERNAL INCLUDES #include -#define MAKE_SHADER(A)#A - namespace { @@ -29,52 +27,42 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING"); #endif +#define MAKE_SHADER(A)#A + const char* VERTEX_SHADER = MAKE_SHADER( attribute mediump vec2 aPosition; attribute mediump vec2 aTexCoord; +uniform mediump vec2 uOffset; uniform mediump mat4 uMvpMatrix; varying mediump vec2 vTexCoord; void main() { - mediump vec4 position = vec4( aPosition, 0.0, 1.0 ); + mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 ); gl_Position = uMvpMatrix * position; vTexCoord = aTexCoord; } ); -const char* FRAGMENT_SHADER = MAKE_SHADER( +const char* FRAGMENT_SHADER_L8 = MAKE_SHADER( +uniform lowp vec4 uColor; uniform sampler2D sTexture; varying mediump vec2 vTexCoord; void main() { - gl_FragColor = texture2D( sTexture, vTexCoord ); -} -); - -const char* VERTEX_SHADER_SHADOW = MAKE_SHADER( -attribute mediump vec2 aPosition; -attribute mediump vec2 aTexCoord; -varying mediump vec2 vTexCoord; - -void main() -{ - mediump vec4 position = vec4( aPosition, 0.0, 1.0 ); - gl_Position = position; - vTexCoord = aTexCoord; + mediump vec4 color = texture2D( sTexture, vTexCoord ); + gl_FragColor = vec4( uColor.rgb, uColor.a * color.r ); } ); -const char* FRAGMENT_SHADER_SHADOW = MAKE_SHADER( +const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER( uniform sampler2D sTexture; -uniform lowp vec4 uColor; varying mediump vec2 vTexCoord; void main() { - mediump vec4 color = texture2D( sTexture, vTexCoord ); - gl_FragColor = vec4(uColor.rgb, uColor.a*color.r); + gl_FragColor = texture2D( sTexture, vTexCoord ); } ); @@ -91,9 +79,9 @@ namespace Internal AtlasGlyphManager::AtlasGlyphManager() { + mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 ); + mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA ); mAtlasManager = Dali::Toolkit::AtlasManager::New(); - mEffectBufferShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ); - mShadowShader = Shader::New( VERTEX_SHADER_SHADOW, FRAGMENT_SHADER_SHADOW, Dali::Shader::HINT_MODIFIES_GEOMETRY ); } void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, @@ -102,7 +90,16 @@ void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, { DALI_LOG_INFO( gLogFilter, Debug::General, "Added glyph, font: %d index: %d\n", glyph.fontId, glyph.index ); - mAtlasManager.Add( bitmap, slot ); + if ( mAtlasManager.Add( bitmap, slot ) ) + { + // A new atlas was created so set the material details for the atlas + Dali::Atlas atlas = mAtlasManager.GetAtlasContainer( slot.mAtlasId ); + Pixel::Format pixelFormat = mAtlasManager.GetPixelFormat( slot.mAtlasId ); + Material material = Material::New( pixelFormat == Pixel::L8 ? mShaderL8 : mShaderRgba ); + material.AddTexture( atlas, "sTexture" ); + material.SetBlendMode( BlendingMode::ON ); + mAtlasManager.SetMaterial( slot.mAtlasId, material ); + } GlyphRecordEntry record; record.mIndex = glyph.index; @@ -140,13 +137,7 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, mAtlasManager.GenerateMeshData( imageId, position, mesh, false ); } -void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first, - const Toolkit::AtlasManager::Mesh2D& second ) -{ - mAtlasManager.StitchMesh( first, second ); -} - -bool AtlasGlyphManager::Cached( Text::FontId fontId, +bool AtlasGlyphManager::IsCached( Text::FontId fontId, Text::GlyphIndex index, Dali::Toolkit::AtlasManager::AtlasSlot& slot ) { @@ -263,11 +254,6 @@ Material AtlasGlyphManager::GetMaterial( uint32_t atlasId ) const return mAtlasManager.GetMaterial( atlasId ); } -Image AtlasGlyphManager::GetImage( uint32_t atlasId ) const -{ - return mAtlasManager.GetImage( atlasId ); -} - AtlasGlyphManager::~AtlasGlyphManager() { // mAtlasManager handle is automatically released here diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h index da659bc..0c67501 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h @@ -81,17 +81,11 @@ public: Toolkit::AtlasManager::Mesh2D& mesh ); /** - * @copydoc Toolkit::AtlasGlyphManager::StitchMesh + * @copydoc Toolkit::AtlasGlyphManager::IsCached */ - void StitchMesh( Toolkit::AtlasManager::Mesh2D& first, - const Toolkit::AtlasManager::Mesh2D& second ); - - /** - * @copydoc Toolkit::AtlasGlyphManager::Cached - */ - bool Cached( Text::FontId fontId, - Text::GlyphIndex index, - Dali::Toolkit::AtlasManager::AtlasSlot& slot ); + bool IsCached( Text::FontId fontId, + Text::GlyphIndex index, + Dali::Toolkit::AtlasManager::AtlasSlot& slot ); /** * @copydoc Toolkit::AtlasGlyphManager::GetAtlasSize @@ -119,31 +113,10 @@ public: Material GetMaterial( uint32_t atlasId ) const; /** - * @copydoc Toolkit::AtlasGlyphManager::GetMaterial - */ - Image GetImage( uint32_t atlasId ) const; - - /** * @copydoc Toolkit::AtlasGlyphManager::GetMetrics */ const Toolkit::AtlasGlyphManager::Metrics& GetMetrics(); - /** - * @copydoc Toolkit::AtlasGlyphManager::GetEffectBufferShader - */ - Shader GetEffectBufferShader() const - { - return mEffectBufferShader; - } - - /** - * @copydoc Toolkit::AtlasGlyphManager::GetGlyphShadowShader - */ - Shader GetGlyphShadowShader() const - { - return mShadowShader; - } - protected: /** @@ -156,8 +129,9 @@ private: Dali::Toolkit::AtlasManager mAtlasManager; ///> Atlas Manager created by GlyphManager std::vector< FontGlyphRecord > mFontGlyphRecords; Toolkit::AtlasGlyphManager::Metrics mMetrics; ///> Metrics to pass back on GlyphManager status - Shader mEffectBufferShader; ///> Shader used to render drop shadow buffer textures - Shader mShadowShader; ///> Shader used to render drop shadow into buffer + + Shader mShaderL8; + Shader mShaderRgba; }; } // namespace Internal diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp index 39ce202..5a46ef5 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp @@ -84,17 +84,11 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, mesh ); } -void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first, - const Toolkit::AtlasManager::Mesh2D& second ) +bool AtlasGlyphManager::IsCached( Text::FontId fontId, + Text::GlyphIndex index, + AtlasManager::AtlasSlot& slot ) { - GetImplementation(*this).StitchMesh( first, second ); -} - -bool AtlasGlyphManager::Cached( Text::FontId fontId, - Text::GlyphIndex index, - AtlasManager::AtlasSlot& slot ) -{ - return GetImplementation(*this).Cached( fontId, index, slot ); + return GetImplementation(*this).IsCached( fontId, index, slot ); } void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight ) @@ -117,11 +111,6 @@ Material AtlasGlyphManager::GetMaterial( uint32_t atlasId ) const return GetImplementation(*this).GetMaterial( atlasId ); } -Image AtlasGlyphManager::GetImage( uint32_t atlasId ) const -{ - return GetImplementation(*this).GetImage( atlasId ); -} - const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics() { return GetImplementation(*this).GetMetrics(); @@ -132,16 +121,6 @@ void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIn GetImplementation(*this).AdjustReferenceCount( fontId, index, delta ); } -Shader AtlasGlyphManager::GetEffectBufferShader() const -{ - return GetImplementation(*this).GetEffectBufferShader(); -} - -Shader AtlasGlyphManager::GetGlyphShadowShader() const -{ - return GetImplementation(*this).GetGlyphShadowShader(); -} - } // namespace Toolkit } // namespace Dali diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h index 2deba24..1870bd5 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h @@ -19,7 +19,7 @@ */ // INTERNAL INCLUDES -#include +#include #include namespace Dali @@ -99,15 +99,6 @@ public: Toolkit::AtlasManager::Mesh2D& mesh ); /** - * @brief Stitch Two Meshes together - * - * @param[in] first first mesh - * @param[in] second second mesh - */ - void StitchMesh( Toolkit::AtlasManager::Mesh2D& first, - const Toolkit::AtlasManager::Mesh2D& second ); - - /** * @brief Check to see if a glyph is being cached * * @param[in] fontId The font that this glyph comes from @@ -116,9 +107,9 @@ public: * * @return Whether glyph is cached or not ? */ - bool Cached( Text::FontId fontId, - Text::GlyphIndex index, - AtlasManager::AtlasSlot& slot ); + bool IsCached( Text::FontId fontId, + Text::GlyphIndex index, + AtlasManager::AtlasSlot& slot ); /** * @brief Retrieve the size of an atlas @@ -158,15 +149,6 @@ public: Material GetMaterial( uint32_t atlasId ) const; /** - * @brief Get the sampler used by an atlas - * - * @param[in] atlasId Id of an atlas - * - * @return The sampler used by the atlas - */ - Image GetImage( uint32_t atlasId ) const; - - /** * @brief Get Glyph Manager metrics * * @return const reference to glyph manager metrics @@ -182,20 +164,6 @@ public: */ void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta ); - /** - * @brief Get Shader used for rendering glyph effect buffers - * - * @return Handle of shader needed - */ - Shader GetEffectBufferShader() const; - - /** - * @brief Get Shader used rendering Glyph Shadows - * - * @return Handle of shader needed - */ - Shader GetGlyphShadowShader() const; - private: explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl); diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp similarity index 50% rename from dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp rename to dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp index 5a524d2..dacb141 100644 --- a/dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp @@ -15,15 +15,15 @@ */ // CLASS HEADER -#include +#include -// EXTERNAL INCLUDE -#include +// EXTERNAL INCLUDES #include -#include -#include #include +// INTERNAL INCLUDES +#include + namespace Dali { @@ -43,45 +43,6 @@ namespace const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 ); const uint32_t FILLED_PIXEL( -1 ); Toolkit::AtlasManager::AtlasSize EMPTY_SIZE; - - #define MAKE_SHADER(A)#A - - const char* VERTEX_SHADER = MAKE_SHADER( - attribute mediump vec2 aPosition; - attribute mediump vec2 aTexCoord; - uniform mediump mat4 uMvpMatrix; - varying mediump vec2 vTexCoord; - - void main() - { - mediump vec4 position = vec4( aPosition, 0.0, 1.0 ); - gl_Position = uMvpMatrix * position; - vTexCoord = aTexCoord; - } - ); - - const char* FRAGMENT_SHADER_L8 = MAKE_SHADER( - uniform lowp vec4 uColor; - uniform sampler2D sTexture; - varying mediump vec2 vTexCoord; - - void main() - { - mediump vec4 color = texture2D( sTexture, vTexCoord ); - gl_FragColor = vec4( uColor.rgb, uColor.a * color.r ); - } - ); - - const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER( - uniform sampler2D sTexture; - varying mediump vec2 vTexCoord; - - void main() - { - gl_FragColor = texture2D( sTexture, vTexCoord ); - } - ); - } AtlasManager::AtlasManager() @@ -91,8 +52,6 @@ AtlasManager::AtlasManager() mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT; mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH; mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT; - mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 ); - mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA ); } AtlasManagerPtr AtlasManager::New() @@ -158,11 +117,6 @@ Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasMa memset( buffer, 0xFF, filledPixelImage.GetBufferSize() ); atlas.Upload( filledPixelImage, 0, 0 ); - - atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba ); - atlasDescriptor.mMaterial.AddTexture(atlas, "sTexture" ); - atlasDescriptor.mImage = atlas; - atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON ); mAtlasList.push_back( atlasDescriptor ); return mAtlasList.size(); } @@ -172,16 +126,14 @@ void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy ) mAddFailPolicy = policy; } -void AtlasManager::Add( const BufferImage& image, +bool AtlasManager::Add( const BufferImage& image, Toolkit::AtlasManager::AtlasSlot& slot, Toolkit::AtlasManager::AtlasId atlas ) { - // See if there's a slot in an atlas that matches the requirements of this image - // A bitmap must be sliceable into a single atlas + bool created = false; Pixel::Format pixelFormat = image.GetPixelFormat(); SizeType width = image.GetWidth(); SizeType height = image.GetHeight(); - SizeType blockArea = 0; SizeType foundAtlas = 0; SizeType index = 0; slot.mImageId = 0; @@ -191,13 +143,13 @@ void AtlasManager::Add( const BufferImage& image, // If there is a preferred atlas then check for room in that first if ( atlas-- ) { - foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea ); + foundAtlas = CheckAtlas( atlas, width, height, pixelFormat ); } // Search current atlases to see if there is a good match while( !foundAtlas && index < mAtlasList.size() ) { - foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea ); + foundAtlas = CheckAtlas( index, width, height, pixelFormat ); ++index; } @@ -214,35 +166,32 @@ void AtlasManager::Add( const BufferImage& image, mNewAtlasSize.mHeight, mNewAtlasSize.mBlockWidth, mNewAtlasSize.mBlockHeight ); - return; + return created; } - - foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea ); + created = true; + foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat ); } if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy ) { // Haven't found an atlas for this image!!!!!! DALI_LOG_ERROR("Failed to create an atlas under current policy.\n"); - return; + return created; } } - // Work out where the blocks are we're going to use - for ( SizeType i = 0; i < blockArea; ++i ) + // Work out which the block we're going to use + // Is there currently a next free block available ? + if ( mAtlasList[ foundAtlas ].mAvailableBlocks ) { - // Is there currently a next free block available ? - if ( mAtlasList[ foundAtlas ].mAvailableBlocks ) - { - // Yes, so select our next block - desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- ); - } - else - { - // Our next block must be from the free list, fetch from the start of the list - desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] ); - mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() ); - } + // Yes, so select our next block + desc.mBlock = mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks--; + } + else + { + // Our next block must be from the free list, fetch from the start of the list + desc.mBlock = mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ]; + mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() ); } desc.mImageWidth = width; @@ -252,7 +201,7 @@ void AtlasManager::Add( const BufferImage& image, // See if there's a previously freed image ID that we can assign to this new image uint32_t imageId = 0u; - for ( uint32_t i = 0u; i < mImageList.size(); ++i ) + for ( uint32_t i = 0u; i < mImageList.Size(); ++i ) { if ( !mImageList[ i ].mCount ) { @@ -262,8 +211,8 @@ void AtlasManager::Add( const BufferImage& image, } if ( !imageId ) { - mImageList.push_back( desc ); - slot.mImageId = mImageList.size(); + mImageList.PushBack( desc ); + slot.mImageId = mImageList.Size(); } else { @@ -271,15 +220,18 @@ void AtlasManager::Add( const BufferImage& image, slot.mImageId = imageId; } slot.mAtlasId = foundAtlas + 1u; + + // Upload the buffer image into the atlas UploadImage( image, desc ); + return created; } AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas, SizeType width, SizeType height, - Pixel::Format pixelFormat, - SizeType& blockArea ) + Pixel::Format pixelFormat ) { + AtlasManager::SizeType result = 0u; if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat ) { // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas @@ -287,254 +239,10 @@ AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas, && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight ) { - blockArea = 1u; - return ( atlas + 1u ); + result = atlas + 1u; } } - return 0u; -} - -void AtlasManager::CreateMesh( SizeType atlas, - SizeType imageWidth, - SizeType imageHeight, - const Vector2& position, - SizeType widthInBlocks, - SizeType heightInBlocks, - Toolkit::AtlasManager::Mesh2D& mesh, - AtlasSlotDescriptor& desc ) -{ - Toolkit::AtlasManager::Vertex2D vertex; - uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available - - SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth; - SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight; - - float vertexBlockWidth = static_cast< float >( blockWidth ); - float vertexBlockHeight = static_cast< float >( blockHeight ); - - SizeType width = mAtlasList[ atlas ].mSize.mWidth; - SizeType height = mAtlasList[ atlas ].mSize.mHeight; - - SizeType atlasWidthInBlocks = ( width - 1u ) / blockWidth; - - // Get the normalized size of a texel in both directions - // TODO when texture resizing and passing texture size via uniforms is available, - // we will encode pixel positions into the vertex data rather than normalized - // meaning that geometry needn't be changed on an atlas resize - float texelX = 1.0f / static_cast< float >( width ); - float texelY = 1.0f / static_cast< float >( height ); - - float oneAndAHalfTexelX = texelX + ( texelX * 0.5f ); - float oneAndAHalfTexelY = texelY + ( texelY * 0.5f ); - - // Get the normalized size of a block in texels - float texelBlockWidth = texelX * vertexBlockWidth; - float texelBlockHeight = texelY * vertexBlockHeight; - - // Get partial block space - float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth ); - float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight ); - - // And in texels - float texelEdgeWidth = texelX * vertexEdgeWidth; - float texelEdgeHeight = texelY * vertexEdgeHeight; - - // We're going to 'blit' half a pixel more on each edge - vertexBlockWidth++; - vertexEdgeWidth++; - vertexBlockHeight++; - vertexEdgeHeight++; - - // Block by block create the two triangles for the quad - SizeType blockIndex = 0; - float ndcWidth; - float ndcHeight; - float ndcVWidth; - float ndcVHeight; - - // Move back half a pixel - Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f ); - - for ( SizeType y = 0; y < heightInBlocks; ++y ) - { - - float currentX = position.x; - - if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f ) - { - ndcHeight = texelEdgeHeight + texelY; - ndcVHeight = vertexEdgeHeight; - } - else - { - ndcHeight = texelBlockHeight + texelY; - ndcVHeight = vertexBlockHeight; - } - - for ( SizeType x = 0; x < widthInBlocks; ++x ) - { - SizeType block = desc.mBlocksList[ blockIndex++ ]; - - float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks ); - float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks ); - - // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner ) - fBlockX += oneAndAHalfTexelX; - fBlockY += oneAndAHalfTexelY; - - if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f ) - { - ndcWidth = texelEdgeWidth + texelX; - ndcVWidth = vertexEdgeWidth; - } - else - { - ndcWidth = texelBlockWidth + texelX; - ndcVWidth = vertexBlockWidth; - } - - // Top left - vertex.mPosition.x = topLeft.x; - vertex.mPosition.y = topLeft.y; - vertex.mTexCoords.x = fBlockX; - vertex.mTexCoords.y = fBlockY; - - mesh.mVertices.PushBack( vertex ); - - // Top Right - vertex.mPosition.x = topLeft.x + ndcVWidth; - vertex.mPosition.y = topLeft.y; - vertex.mTexCoords.x = fBlockX + ndcWidth; - vertex.mTexCoords.y = fBlockY; - - mesh.mVertices.PushBack( vertex ); - - // Bottom Left - vertex.mPosition.x = topLeft.x; - vertex.mPosition.y = topLeft.y + ndcVHeight; - vertex.mTexCoords.x = fBlockX; - vertex.mTexCoords.y = fBlockY + ndcHeight; - - mesh.mVertices.PushBack( vertex ); - - // Bottom Right - topLeft.x += ndcVWidth; - vertex.mPosition.x = topLeft.x; - vertex.mPosition.y = topLeft.y + ndcVHeight; - vertex.mTexCoords.x = fBlockX + ndcWidth; - vertex.mTexCoords.y = fBlockY + ndcHeight; - - mesh.mVertices.PushBack( vertex ); - - // Six indices in counter clockwise winding - mesh.mIndices.PushBack( faceIndex + 1u ); - mesh.mIndices.PushBack( faceIndex ); - mesh.mIndices.PushBack( faceIndex + 2u ); - mesh.mIndices.PushBack( faceIndex + 2u ); - mesh.mIndices.PushBack( faceIndex + 3u ); - mesh.mIndices.PushBack( faceIndex + 1u ); - faceIndex += 4; - } - - // Move down a row - topLeft.x = currentX; - topLeft.y += vertexBlockHeight; - } - - // If there's only one block then skip this next vertex optimisation - if ( widthInBlocks * heightInBlocks > 1 ) - { - Toolkit::AtlasManager::Mesh2D optimizedMesh; - OptimizeMesh( mesh, optimizedMesh ); - } -} - -void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh ) -{ - uint32_t vertexCount = mesh.mVertices.Size(); - uint32_t indexCount = mesh.mIndices.Size(); - std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount; - std::cout << ", Triangles = " << indexCount / 3 << std::endl; - - for ( SizeType v = 0; v < vertexCount; ++v ) - { - std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", "; - std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", "; - std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", "; - std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl; - } - - std::cout << "\n Indices: "; - for ( SizeType i = 0; i < indexCount; ++i ) - { - std::cout << " " << mesh.mIndices[ i ]; - } - std::cout << std::endl; -} - -void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in, - Toolkit::AtlasManager::Mesh2D& out ) -{ - unsigned short vertexIndex = 0; - - // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts - for ( SizeType i = 0; i < in.mIndices.Size(); ++i ) - { - // Fetch a vertex, has it already been assigned? - bool foundVertex = false; - Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ]; - for ( SizeType j = 0; j < out.mVertices.Size(); ++j ) - { - if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) && - ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) && - ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) && - ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) ) - { - // Yes, so store this down as the vertex to use - out.mIndices.PushBack( j ); - foundVertex = true; - break; - } - } - - // Did we find a vertex ? - if ( !foundVertex ) - { - // No so add a new one - out.mVertices.PushBack( v ); - vertexIndex++; - } - } -} - -void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first, - const Toolkit::AtlasManager::Mesh2D& second, - bool optimize ) -{ - const uint32_t verticesCount = first.mVertices.Size(); - first.mVertices.Insert( first.mVertices.End(), - second.mVertices.Begin(), - second.mVertices.End() ); - - const uint32_t indicesCount = first.mIndices.Size(); - first.mIndices.Insert( first.mIndices.End(), - second.mIndices.Begin(), - second.mIndices.End() ); - - for( Vector::Iterator it = first.mIndices.Begin() + indicesCount, - endIt = first.mIndices.End(); - it != endIt; - ++it ) - { - *it += verticesCount; - } - - if ( optimize ) - { - Toolkit::AtlasManager::Mesh2D optimizedMesh; - OptimizeMesh( first, optimizedMesh ); - first = optimizedMesh; - } + return result; } void AtlasManager::UploadImage( const BufferImage& image, @@ -554,9 +262,8 @@ void AtlasManager::UploadImage( const BufferImage& image, SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight; SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth; - SizeType block = desc.mBlocksList[ 0 ]; - SizeType blockX = block % atlasWidthInBlocks; - SizeType blockY = block / atlasWidthInBlocks; + SizeType blockX = desc.mBlock % atlasWidthInBlocks; + SizeType blockY = desc.mBlock / atlasWidthInBlocks; SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u; SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u; @@ -623,18 +330,12 @@ void AtlasManager::GenerateMeshData( ImageId id, SizeType width = mImageList[ imageId ].mImageWidth; SizeType height = mImageList[ imageId ].mImageHeight; - SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth; - if ( width % mAtlasList[ atlas ].mSize.mBlockWidth ) - { - widthInBlocks++; - } - SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight; - if ( height % mAtlasList[ atlas ].mSize.mBlockHeight ) - { - heightInBlocks++; - } - - CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] ); + AtlasMeshFactory::CreateQuad( width, + height, + mImageList[ imageId ].mBlock, + mAtlasList[ atlas ].mSize, + position, + meshData ); // Mesh created so increase the reference count, if we're asked to if ( addReference ) @@ -650,14 +351,13 @@ void AtlasManager::GenerateMeshData( ImageId id, Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const { - Dali::Atlas null; - if ( !atlas || atlas > mAtlasList.size( ) ) + DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() ); + Dali::Atlas atlasContainer; + if ( atlas && atlas-- <= mAtlasList.size() ) { - - DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n"); - return null; + atlasContainer = mAtlasList[ atlas ].mAtlas; } - return mAtlasList[ atlas -1u ].mAtlas; + return atlasContainer; } bool AtlasManager::Remove( ImageId id ) @@ -666,7 +366,7 @@ bool AtlasManager::Remove( ImageId id ) SizeType imageId = id - 1u; bool removed = false; - if ( id > mImageList.size() ) + if ( id > mImageList.Size() ) { DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id ); return false; @@ -685,24 +385,20 @@ bool AtlasManager::Remove( ImageId id ) removed = true; mImageList[ imageId ].mCount = 0; SizeType atlas = mImageList[ imageId ].mAtlasId - 1u; - for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i ) - { - mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] ); - } + mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlock ); } return removed; } AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const { - if ( id && id <= mImageList.size() ) - { - return mImageList[ id - 1u ].mAtlasId; - } - else + DALI_ASSERT_DEBUG( id && id <= mImageList.Size() ); + AtlasManager::AtlasId atlasId = 0u; + if ( id && id-- <= mImageList.Size() ) { - return 0; + atlasId = mImageList[ id ].mAtlasId; } + return atlasId; } void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size ) @@ -716,6 +412,7 @@ void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas ) { + DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() ); if ( atlas && atlas-- <= mAtlasList.size() ) { return mAtlasList[ atlas ].mSize; @@ -725,14 +422,13 @@ const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atla AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const { + DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() ); + AtlasManager::SizeType freeBlocks = 0u; if ( atlas && atlas-- <= mAtlasList.size() ) { - return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() ); - } - else - { - return 0; + freeBlocks = mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size(); } + return freeBlocks; } AtlasManager::SizeType AtlasManager::GetAtlasCount() const @@ -742,13 +438,13 @@ AtlasManager::SizeType AtlasManager::GetAtlasCount() const Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas ) { - if ( !atlas || atlas > mAtlasList.size( ) ) + DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() ); + Pixel::Format pixelFormat = Pixel::RGBA8888; + if ( atlas && atlas-- <= mAtlasList.size() ) { - - DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n"); - return Pixel::L8; + pixelFormat = mAtlasList[ atlas ].mPixelFormat; } - return mAtlasList[ --atlas].mPixelFormat; + return pixelFormat; } void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics ) @@ -782,22 +478,22 @@ void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics ) Material AtlasManager::GetMaterial( AtlasId atlas ) const { + DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() ); + Material material; if ( atlas && atlas-- <= mAtlasList.size() ) { - return mAtlasList[ atlas ].mMaterial; + material = mAtlasList[ atlas ].mMaterial; } - Material null; - return null; + return material; } -Image AtlasManager::GetImage( AtlasId atlas ) const +void AtlasManager::SetMaterial( AtlasId atlas, Material& material ) { + DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() ); if ( atlas && atlas-- <= mAtlasList.size() ) { - return mAtlasList[ atlas ].mImage; + mAtlasList[ atlas ].mMaterial = material; } - Image null; - return null; } } // namespace Internal diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager-impl.h b/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h similarity index 82% rename from dali-toolkit/internal/atlas-manager/atlas-manager-impl.h rename to dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h index 5f940a6..b4828a0 100644 --- a/dali-toolkit/internal/atlas-manager/atlas-manager-impl.h +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h @@ -23,7 +23,7 @@ #include // INTERNAL INCLUDES -#include +#include namespace Dali { @@ -65,7 +65,6 @@ public: BufferImage mHorizontalStrip; // Image used to pad upload BufferImage mVerticalStrip; // Image used to pad upload Material mMaterial; // material used for atlas texture - Image mImage; SizeType mTotalBlocks; // total number of blocks in atlas SizeType mAvailableBlocks; // number of blocks available in atlas Dali::Vector< SizeType > mFreeBlocksList; // unless there are any previously freed blocks @@ -77,7 +76,7 @@ public: SizeType mImageWidth; // Width of image stored SizeType mImageHeight; // Height of image stored AtlasId mAtlasId; // Image is stored in this Atlas - Dali::Vector< SizeType > mBlocksList; // List of blocks within atlas used for image + SizeType mBlock; // Block within atlas used for image }; AtlasManager(); @@ -102,7 +101,7 @@ public: /** * @copydoc Toolkit::AtlasManager::Add */ - void Add( const BufferImage& image, + bool Add( const BufferImage& image, Toolkit::AtlasManager::AtlasSlot& slot, Toolkit::AtlasManager::AtlasId atlas ); @@ -115,13 +114,6 @@ public: bool addReference ); /** - * @copydoc Toolkit::AtlasManager::StitchMesh - */ - void StitchMesh( Toolkit::AtlasManager::Mesh2D& first, - const Toolkit::AtlasManager::Mesh2D& second, - bool optimize ); - - /** * @copydoc Toolkit::AtlasManager::Remove */ bool Remove( ImageId id ); @@ -176,44 +168,26 @@ public: */ Material GetMaterial( AtlasId atlas ) const; -/** - * @copydoc Toolkit::AtlasManager::GetImage + /** + * @copydoc Toolkit::AtlasManager::SetMaterial */ - Image GetImage( AtlasId atlas ) const; + void SetMaterial( AtlasId atlas, Material& material ); private: std::vector< AtlasDescriptor > mAtlasList; // List of atlases created - std::vector< AtlasSlotDescriptor > mImageList; // List of bitmaps store in atlases + Vector< AtlasSlotDescriptor > mImageList; // List of bitmaps stored in atlases Toolkit::AtlasManager::AtlasSize mNewAtlasSize; // Atlas size to use in next creation Toolkit::AtlasManager::AddFailPolicy mAddFailPolicy; // Policy for faling to add an Image SizeType CheckAtlas( SizeType atlas, SizeType width, SizeType height, - Pixel::Format pixelFormat, - SizeType& blockArea ); - - void CreateMesh( SizeType atlas, - SizeType imageWidth, - SizeType imageHeight, - const Vector2& position, - SizeType widthInBlocks, - SizeType heightInBlocks, - Toolkit::AtlasManager::Mesh2D& mesh, - AtlasSlotDescriptor& desc ); - - void OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in, - Toolkit::AtlasManager::Mesh2D& out ); + Pixel::Format pixelFormat ); void UploadImage( const BufferImage& image, const AtlasSlotDescriptor& desc ); - void PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh ); - - Shader mShaderL8; - Shader mShaderRgba; - }; } // namespace Internal diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp similarity index 84% rename from dali-toolkit/internal/atlas-manager/atlas-manager.cpp rename to dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp index 987f1f1..2aa1bce 100644 --- a/dali-toolkit/internal/atlas-manager/atlas-manager.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp @@ -15,10 +15,10 @@ */ // CLASS HEADER -#include +#include - // INTERNAL INCLUDES -#include +// INTERNAL INCLUDES +#include namespace Dali { @@ -55,11 +55,11 @@ void AtlasManager::SetAddPolicy( AddFailPolicy policy ) GetImplementation(*this).SetAddPolicy( policy ); } -void AtlasManager::Add( const BufferImage& image, +bool AtlasManager::Add( const BufferImage& image, AtlasManager::AtlasSlot& slot, AtlasManager::AtlasId atlas ) { - GetImplementation(*this).Add( image, slot, atlas ); + return GetImplementation(*this).Add( image, slot, atlas ); } bool AtlasManager::Remove( ImageId id ) @@ -78,13 +78,6 @@ void AtlasManager::GenerateMeshData( ImageId id, addReference ); } -void AtlasManager::StitchMesh( Mesh2D& first, - const Mesh2D& second, - bool optimize ) -{ - GetImplementation(*this).StitchMesh( first, second, optimize ); -} - Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const { return GetImplementation(*this).GetAtlasContainer( atlas ); @@ -130,9 +123,9 @@ Material AtlasManager::GetMaterial( AtlasId atlas ) const return GetImplementation(*this).GetMaterial( atlas ); } -Image AtlasManager::GetImage( AtlasId atlas ) const +void AtlasManager::SetMaterial( AtlasId atlas, Material& material ) { - return GetImplementation(*this).GetImage( atlas ); + GetImplementation(*this).SetMaterial( atlas, material ); } } // namespace Toolkit diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager.h b/dali-toolkit/internal/text/rendering/atlas/atlas-manager.h similarity index 62% rename from dali-toolkit/internal/atlas-manager/atlas-manager.h rename to dali-toolkit/internal/text/rendering/atlas/atlas-manager.h index 6d41419..cf774b3 100644 --- a/dali-toolkit/internal/atlas-manager/atlas-manager.h +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-manager.h @@ -37,120 +37,6 @@ class AtlasManager; } // namespace Internal -/** - * AtlasManager - * ------------ - * - * Creates and manages additions and removals of images from Texture Atlases - * - * The AtlasManager will match pixeltype and optimal block use to determine - * the appropriate atlas to upload an image to. - * - * A policy can be specified to determine the action the AtlasManager will carry - * out, should it not be able to add an image. This can return an error, or create - * a new atlas of pre-determined dimensions to accomodate the new image. - * - * Images are referenced by an ImageId once they have been successfully uploaded. - * - * Once an image has been successfully uploaded, Geometry can be generated by passing - * the ImageId to the GenerateMeshData method and geometry can be consolidated via - * the StitchMesh method. - * - * Images are reference counted once mesh data has been generated. An image is removed - * from the Atlas via the Remove( ImageId ) method. This unreferences the image and only - * physically removes it from the atlas once all references have been freed. - * - * If the AddPolicy is set to generate and error if an image can't be uploaded, then it - * is the applications responsibility to deal with the situation. An error will be indicated - * with an ImageId of 0. - * - * Examples using the AtlasManager - * - * Create or obtain the AtlasManager - * @code - * - * AtlasManager manager = AtlasManager::Get(); - * - * @endcode - * - * Set the AtlasManager AddPolicy - * - * @code - * - * // Tell the atlas manager to create a new atlas, if it needs to - * manager.SetAddPolicy( FAIL_ON_ADD_CREATES ); - * - * // Tell the atlas manager to return an error, if it can't add an image - * manager.SetAddPolicy( FAIL_ON_ADD_FAILS ); - * - * @endcode - * - * Simple add and removal of BufferImage to and from an atlas - * - * @code - * - * // Structure returned by AtlasManager operations - * AtlasSlot slot; - * - * // Add image to an atlas ( will be created if none suitable exists ) - * manager.Add( bitmapImage, slot ); - * - * // slot.mImage returns the imageId for the bitmap, slot.mAtlas indicates the atlasId - * // that the image was added to. The imageId is used to communicate with the AtlasManager - * uint32_t imageId = slot.mImage; - * if ( !imageId ) - * { - * // Addition has failed..... - * } - * ... - * ... - * // Done with image, so remove from atlas, if not being used elsewhere - * manager.Remove( imageId ); - * - * @endcode - * - * Create a Specific Atlas for adding BufferImages to - * - * @code - * - * // Create an RGB888 atlas of 2048x2848, with a blocksize of 128x128 - * uint32_t atlas = manager.CreateAtlas( 2048u, 2048u, 128u, 128u, Pixel::RGB888 ); - * - * // Add an image to a preferred atlas ( note not specifying atlas may still result - * // in the bitmap being added to the atlas above ) - * manager.Add( bitmapImage, slot, atlas ); - * - * @endcode - * - * Create Geometry for a previously added image - * - * @code - * - * // Top left corner of geometry to be generated - * Vector2 position( 1.0f, 1.0f ); - * - * // Geometry will end up here! - * MeshData meshData; - * manager.GenerateMeshData( imageId, position, meshData ); - * - * @endcode - * - * Generating Geometry from multiple images in the same atlas - * - * @code - * - * MeshData firstMesh; - * MeshData secondMesh; - * manager.GenerateMeshData( imageid_1, position_1, firstMesh ); - * manager.GenerateMeshData( imageid_2, position_2, secondMesh ); - * - * // Combine the two meshes. Passing MESH_OPTIMIZE as an optional third parameter will remove duplicate vertices - * manager.StitchMesh( first, second ); - * - * @endcode - * - */ - class AtlasManager : public BaseHandle { public: @@ -158,7 +44,6 @@ public: typedef uint32_t SizeType; typedef SizeType AtlasId; typedef SizeType ImageId; - static const bool MESH_OPTIMIZE = true; struct AtlasSize { @@ -197,14 +82,14 @@ public: struct Vertex2D { - Vector2 mPosition; - Vector2 mTexCoords; + Vector2 mPosition; ///< Vertex posiiton + Vector2 mTexCoords; ///< Vertex texture co-ordinates }; struct Mesh2D { - Vector< Vertex2D > mVertices; - Vector< unsigned int> mIndices; + Vector< Vertex2D > mVertices; ///< container of vertices + Vector< SizeType > mIndices; ///< container of indices }; /** @@ -274,8 +159,10 @@ public: * @param[in] image reference to a bitmapimage * @param[out] slot result of add operation * @param[in] atlas optional preferred atlas + * + * @return true if a new atlas was created */ - void Add( const BufferImage& image, + bool Add( const BufferImage& image, AtlasSlot& slot, AtlasId atlas = 0 ); @@ -302,17 +189,6 @@ public: bool addReference = true ); /** - * @brief Append second mesh to the first mesh - * - * @param[in] first First mesh - * @param[in] second Second mesh - * @param[in] optimize should we optimize vertex data - */ - void StitchMesh( Mesh2D& first, - const Mesh2D& second, - bool optimize = false ); - - /** * @brief Get the BufferImage containing an atlas * * @param[in] atlas AtlasId returned when atlas was created @@ -382,20 +258,20 @@ public: /** * @brief Get Material used by atlas * - * @param atlas[in] atlas AtlasId + * @param[in] atlas AtlasId * * @return Material used by atlas */ Material GetMaterial( AtlasId atlas ) const; - /** - * @brief Get Image used by atlas - * - * @param atlas[in] atlas AtlasId + /** + * @brief Set the material used by an atlas * - * @return Sampler used by atlas + * @param[in] atlas AtlasId + * @param[in] material The Material to assign */ - Image GetImage( AtlasId atlas ) const; + void SetMaterial( AtlasId atlas, Material& material ); + private: explicit DALI_INTERNAL AtlasManager(Internal::AtlasManager *impl); diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp new file mode 100644 index 0000000..3a64c96 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp @@ -0,0 +1,166 @@ + /* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// CLASS HEADER +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace AtlasMeshFactory +{ + +void CreateQuad( SizeType imageWidth, + SizeType imageHeight, + SizeType block, + const Toolkit::AtlasManager::AtlasSize& atlasSize, + const Vector2& position, + Toolkit::AtlasManager::Mesh2D& mesh ) +{ + Toolkit::AtlasManager::Vertex2D vertex; + + SizeType blockWidth = atlasSize.mBlockWidth; + SizeType blockHeight = atlasSize.mBlockHeight; + + float vertexBlockWidth = static_cast< float >( blockWidth ); + float vertexBlockHeight = static_cast< float >( blockHeight ); + + SizeType atlasWidth = atlasSize.mWidth; + SizeType atlasHeight = atlasSize.mHeight; + + SizeType atlasWidthInBlocks = ( atlasWidth - 1u ) / blockWidth; + + // Get the normalized size of a texel in both directions + float texelX = 1.0f / static_cast< float >( atlasWidth ); + float texelY = 1.0f / static_cast< float >( atlasHeight ); + + float oneAndAHalfTexelX = texelX + ( texelX * 0.5f ); + float oneAndAHalfTexelY = texelY + ( texelY * 0.5f ); + + float texelBlockWidth = texelX * vertexBlockWidth; + float texelBlockHeight = texelY * vertexBlockHeight; + + uint32_t pixelsX = imageWidth % blockWidth; + uint32_t pixelsY = imageHeight % blockHeight; + + if ( !pixelsX ) + { + pixelsX = blockWidth; + } + if ( !pixelsY ) + { + pixelsY = blockHeight; + } + float vertexWidth = static_cast< float >( pixelsX ); + float vertexHeight = static_cast< float >( pixelsY ); + float texelWidth = texelX * vertexWidth; + float texelHeight = texelY * vertexHeight; + + // We're going to 'blit' half a pixel more on each edge + vertexWidth++; + vertexHeight++; + + // Move back half a pixel + Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f ); + + float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks ); + float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks ); + + // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner ) + fBlockX += oneAndAHalfTexelX; + fBlockY += oneAndAHalfTexelY; + + float texelWidthOffset = texelWidth + texelX; + float texelHeightOffset = texelHeight + texelY; + + // Top left + vertex.mPosition.x = topLeft.x; + vertex.mPosition.y = topLeft.y; + vertex.mTexCoords.x = fBlockX; + vertex.mTexCoords.y = fBlockY; + + mesh.mVertices.Reserve( 4u ); + mesh.mVertices.PushBack( vertex ); + + // Top Right + vertex.mPosition.x = topLeft.x + vertexWidth; + vertex.mPosition.y = topLeft.y; + vertex.mTexCoords.x = fBlockX + texelWidthOffset; + vertex.mTexCoords.y = fBlockY; + + mesh.mVertices.PushBack( vertex ); + + // Bottom Left + vertex.mPosition.x = topLeft.x; + vertex.mPosition.y = topLeft.y + vertexHeight; + vertex.mTexCoords.x = fBlockX; + vertex.mTexCoords.y = fBlockY + texelHeightOffset; + + mesh.mVertices.PushBack( vertex ); + + // Bottom Right + vertex.mPosition.x = topLeft.x + vertexWidth; + vertex.mPosition.y = topLeft.y + vertexHeight; + vertex.mTexCoords.x = fBlockX + texelWidthOffset; + vertex.mTexCoords.y = fBlockY + texelHeightOffset; + + mesh.mVertices.PushBack( vertex ); + + // Six indices in counter clockwise winding + mesh.mIndices.Reserve( 6u ); + mesh.mIndices.PushBack( 1u ); + mesh.mIndices.PushBack( 0u ); + mesh.mIndices.PushBack( 2u ); + mesh.mIndices.PushBack( 2u ); + mesh.mIndices.PushBack( 3u ); + mesh.mIndices.PushBack( 1u ); +} + +void AppendMesh( Toolkit::AtlasManager::Mesh2D& first, + const Toolkit::AtlasManager::Mesh2D& second ) +{ + const uint32_t verticesCount = first.mVertices.Size(); + first.mVertices.Insert( first.mVertices.End(), + second.mVertices.Begin(), + second.mVertices.End() ); + + const uint32_t indicesCount = first.mIndices.Size(); + first.mIndices.Insert( first.mIndices.End(), + second.mIndices.Begin(), + second.mIndices.End() ); + + for( Vector::Iterator it = first.mIndices.Begin() + indicesCount, + endIt = first.mIndices.End(); + it != endIt; + ++it ) + { + *it += verticesCount; + } +} + +} // namespace AtlasMeshFactory + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h new file mode 100644 index 0000000..f3a953c --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h @@ -0,0 +1,70 @@ +#ifndef __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__ +#define __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace AtlasMeshFactory +{ + typedef uint32_t SizeType; + + /** + * @brief Create a Quad that describes an area in an atlas and a position. + * + * @param[in] width Width of area in pixels. + * @param[in] height Height of area in pixels. + * @param[in] block Block position in atlas. + * @param[in] atlasSize Atlas and block dimensions. + * @param[in] position Position to place area in space. + * @param[out] mesh Mesh object to hold created quad. + */ + void CreateQuad( SizeType width, + SizeType height, + SizeType block, + const Toolkit::AtlasManager::AtlasSize& atlasSize, + const Vector2& position, + Toolkit::AtlasManager::Mesh2D& mesh ); + + /** + * @brief Append one mesh to another. + * + * @param[in,out] first Mesh to append to. + * @param[in] second Mesh to append. + */ + void AppendMesh( Toolkit::AtlasManager::Mesh2D& first, + const Toolkit::AtlasManager::Mesh2D& second ); + +} // namespace AtlasMeshFactory + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__ 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 80459a8..8653b43 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -20,10 +20,6 @@ // EXTERNAL INCLUDES #include -#include -#include -#include -#include #include #include #include @@ -32,6 +28,7 @@ #include #include #include +#include #include using namespace Dali; @@ -47,11 +44,11 @@ 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 { @@ -151,9 +148,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker bool IsGlyphUnderlined( GlyphIndex index, const Vector& underlineRuns ) { - // TODO: At the moment it works because we always traverse the glyphs starting from the beginning - // and there is only one glyph run! If there are more they should be ordered. - for( Vector::ConstIterator it = underlineRuns.Begin(), endIt = underlineRuns.End(); it != endIt; @@ -267,7 +261,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker 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 ) @@ -358,7 +352,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Now remove references for the old text RemoveText(); mTextCache.Swap( newTextCache ); - RemoveAllShadowRenderTasks(); if( thereAreUnderlinedGlyphs ) { @@ -376,9 +369,33 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Create an effect if necessary if ( style == STYLE_DROP_SHADOW ) { - Actor shadowActor = GenerateShadow( *mIt, actorSize, shadowOffset, shadowColor ); - shadowActor.Add( actor ); - actor = shadowActor; + // 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 ) @@ -446,6 +463,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned actor.SetSize( actorSize ); actor.SetColor( meshRecord.mColor ); + actor.RegisterProperty("uOffset", Vector2::ZERO ); return actor; } @@ -473,8 +491,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker { if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor ) { - // Stitch the mesh to the existing mesh and adjust any extents - mGlyphManager.StitchMesh( mIt->mMesh, newMesh ); + // Append the mesh to the existing mesh and adjust any extents + Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh ); if( underlineGlyph ) { @@ -647,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 { @@ -660,170 +678,14 @@ struct AtlasRenderer::Impl : public ConnectionTracker } } - Actor GenerateShadow( MeshRecord& meshRecord, - const Vector2& actorSize, - 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 ); - - Material material = Material::New( mGlyphManager.GetEffectBufferShader() ); - material.AddTexture(meshRecord.mBuffer, "sTexture"); - - Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material ); - - // Set depth index to -1.0 to make sure shadow is rendered first in 3D layers - renderer.SetDepthIndex( -1.0f ); - Actor actor = Actor::New(); - actor.AddRenderer( renderer ); - actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned - actor.SetSize( actorSize ); - - // 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() ); - Image normImage = mGlyphManager.GetImage( meshRecord.mAtlasId ); - normMaterial.AddTexture( normImage, "sTexture" ); - Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial ); - Actor subActor = Actor::New(); - subActor.AddRenderer( normRenderer ); - subActor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned - subActor.SetSize( actorSize ); - subActor.SetColor( shadowColor ); - - // Create a render task to render the effect - RenderTask shadowTask = Stage::GetCurrent().GetRenderTaskList().CreateTask(); - shadowTask.SetTargetFrameBuffer( meshRecord.mBuffer ); - shadowTask.SetSourceActor( subActor ); - shadowTask.SetClearEnabled( true ); - shadowTask.SetClearColor( Vector4::ZERO ); - shadowTask.SetExclusive( true ); - shadowTask.SetRefreshRate( RenderTask::REFRESH_ONCE ); - shadowTask.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete ); - mShadowTasks.push_back( shadowTask ); - actor.Add( subActor ); - - return actor; - } - - void RemoveShadowRenderTask( RenderTask renderTask ) - { - if( renderTask ) - { - renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete ); - - // Guard to prevent accessing Stage after dali-core destruction - if( Stage::IsInstalled() ) - { - Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask ); - } - renderTask.Reset(); - } - } - - void RenderComplete( RenderTask& 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 ); - } - } - - RemoveShadowRenderTask( renderTask ); - } - - void RemoveAllShadowRenderTasks() - { - for ( std::vector< RenderTask >::iterator shadowIterator = mShadowTasks.begin(); - shadowIterator != mShadowTasks.end(); ++shadowIterator ) - { - RemoveShadowRenderTask( *shadowIterator ); - } - } - Actor mActor; ///< The actor parent which renders the text AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching - std::vector< RenderTask > mShadowTasks; ///< Used to render shadows 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() @@ -871,8 +733,6 @@ AtlasRenderer::AtlasRenderer() AtlasRenderer::~AtlasRenderer() { - mImpl->RemoveAllShadowRenderTasks(); - mImpl->RemoveText(); delete mImpl; } -- 2.7.4