From 7132bfee764dc2c7c68feb8c9e9c4e81c9a7d883 Mon Sep 17 00:00:00 2001 From: Richard Underhill Date: Thu, 12 Mar 2015 13:39:33 +0000 Subject: [PATCH] Text Rendering via Atlas Renderer Change-Id: I7fe87403467f2f9e979935d217a34569d2ebe36b Signed-off-by: Richard Underhill --- build/tizen/dali-toolkit/Makefile.am | 2 + dali-toolkit/dali-toolkit.h | 2 + .../internal/atlas-manager/atlas-manager-impl.cpp | 746 +++++++++++++++++++++ .../internal/atlas-manager/atlas-manager-impl.h | 234 +++++++ .../internal/atlas-manager/atlas-manager.cpp | 136 ++++ .../internal/atlas-manager/atlas-manager.h | 352 ++++++++++ .../controls/text-controls/text-field-impl.cpp | 14 +- .../controls/text-controls/text-label-impl.cpp | 13 +- dali-toolkit/internal/file.list | 5 + .../rendering/atlas/atlas-glyph-manager-impl.cpp | 141 ++++ .../rendering/atlas/atlas-glyph-manager-impl.h | 143 ++++ .../text/rendering/atlas/atlas-glyph-manager.cpp | 119 ++++ .../text/rendering/atlas/atlas-glyph-manager.h | 138 ++++ .../text/rendering/atlas/text-atlas-renderer.cpp | 254 +++++++ .../text/rendering/atlas/text-atlas-renderer.h | 87 +++ .../text/rendering/basic/text-basic-renderer.cpp | 2 +- .../text/rendering/shaders/text-bgra-shader.cpp | 2 +- .../text/rendering/shaders/text-bgra-shader.h | 2 +- .../internal/text/rendering/text-backend-impl.cpp | 4 +- .../internal/text/rendering/text-backend.h | 7 - dali-toolkit/public-api/file.list | 2 + dali-toolkit/public-api/text/rendering-backend.h | 45 ++ 22 files changed, 2424 insertions(+), 26 deletions(-) create mode 100644 dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp create mode 100644 dali-toolkit/internal/atlas-manager/atlas-manager-impl.h create mode 100644 dali-toolkit/internal/atlas-manager/atlas-manager.cpp create mode 100644 dali-toolkit/internal/atlas-manager/atlas-manager.h create mode 100644 dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp create mode 100644 dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h create mode 100644 dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp create mode 100644 dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h create mode 100644 dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp create mode 100644 dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h create mode 100644 dali-toolkit/public-api/text/rendering-backend.h diff --git a/build/tizen/dali-toolkit/Makefile.am b/build/tizen/dali-toolkit/Makefile.am index d5567eb..ff48b23 100644 --- a/build/tizen/dali-toolkit/Makefile.am +++ b/build/tizen/dali-toolkit/Makefile.am @@ -109,6 +109,7 @@ publicapibubbleeffectdir = $(publicapidir)/shader-effects/bubble-effect publicapistylingdir = $(publicapidir)/styling publicapitransitioneffectsdir = $(publicapidir)/transition-effects publicapiscriptingdir = $(publicapidir)/scripting +publicapirenderingbackenddir = $(publicapidir)/text publicapi_HEADERS = $(public_api_header_files) publicapicontrols_HEADERS = $(public_api_controls_header_files) @@ -146,4 +147,5 @@ publicapibubbleeffect_HEADERS = $(public_api_bubble_effect_header_files) publicapistyling_HEADERS = $(public_api_styling_header_files) publicapitransitioneffects_HEADERS = $(public_api_transition_effects_header_files) publicapiscripting_HEADERS = $(public_api_scripting_header_files) +publicapirenderingbackend_HEADERS = $(public_api_rendering_backend_header_files) diff --git a/dali-toolkit/dali-toolkit.h b/dali-toolkit/dali-toolkit.h index 11ab4e0..8949d3f 100644 --- a/dali-toolkit/dali-toolkit.h +++ b/dali-toolkit/dali-toolkit.h @@ -87,6 +87,8 @@ #include #include +#include + #include #include #include diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp b/dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp new file mode 100644 index 0000000..da6ae94 --- /dev/null +++ b/dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp @@ -0,0 +1,746 @@ +/* + * 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 + +// EXTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace +{ + const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f ); + const Vector2 DEFAULT_BLOCK_SIZE( 32.0f, 32.0f ); +} + +AtlasManager::AtlasManager() +: mNewAtlasSize( DEFAULT_ATLAS_SIZE ), + mNewBlockSize( DEFAULT_BLOCK_SIZE ), + mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ) +{ +} + +AtlasManagerPtr AtlasManager::New() +{ + AtlasManagerPtr internal = new AtlasManager(); + return internal; +} + +AtlasManager::~AtlasManager() +{ +} + +Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width, + SizeType height, + SizeType blockWidth, + SizeType blockHeight, + Pixel::Format pixelformat ) +{ + // Check to see if the atlas is large enough to hold a single block even ? + if ( blockWidth > width || blockHeight > height ) + { + DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %i x %i\n", + width, height, blockWidth, blockHeight ); + return 0; + } + + Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat ); + AtlasDescriptor atlasDescriptor; + atlasDescriptor.mAtlas = atlas; + atlasDescriptor.mWidth = width; + atlasDescriptor.mHeight = height; + atlasDescriptor.mBlockWidth = blockWidth; + atlasDescriptor.mBlockHeight = blockHeight; + atlasDescriptor.mPixelFormat = pixelformat; + std::stringstream materialLabel; + materialLabel << "Atlas Material - "; + materialLabel << mAtlasList.size(); + atlasDescriptor.mMaterial = Material::New( materialLabel.str() ); + atlasDescriptor.mMaterial.SetDiffuseTexture( atlas ); + atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 ) + mAtlasList.push_back( atlasDescriptor ); + return mAtlasList.size(); +} + +void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy ) +{ + mAddFailPolicy = policy; +} + +void 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 + Pixel::Format pixelFormat = image.GetPixelFormat(); + SizeType width = image.GetWidth(); + SizeType height = image.GetHeight(); + SizeType blockArea = 0; + SizeType totalBlocks = 0; + SizeType foundAtlas = 0; + SizeType index = 0; + slot.mImageId = 0; + + AtlasSlotDescriptor desc; + + // If there is a preferred atlas then check for room in that first + if ( atlas-- ) + { + foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks ); + } + + // Search current atlases to see if there is a good match + + while( !foundAtlas && index < mAtlasList.size() ) + { + foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks ); + ++index; + } + + // If we can't find a suitable atlas then check the policy to determine action + if ( !foundAtlas-- ) + { + if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy ) + { + SizeType newAtlas = CreateAtlas( mNewAtlasSize.x, mNewAtlasSize.y, mNewBlockSize.x, mNewBlockSize.y, pixelFormat ); + if ( !newAtlas-- ) + { + return; + } + else + { + foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks ); + } + } + + if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- ) + { + // Haven't found an atlas for this image!!!!!! + return; + } + } + + // Work out where the blocks are we're going to use + for ( SizeType i = 0; i < blockArea; ++i ) + { + // Is there currently a next free block available ? + if ( mAtlasList[ foundAtlas ].mNextFreeBlock ) + { + // Yes, so use this for our next block + SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u; + desc.mBlocksList.PushBack( selectedBlock ); + + // Any blocks going to be available after this one (adjust to store +1 )? + selectedBlock++; + selectedBlock++; + if ( selectedBlock > totalBlocks ) + { + // No so start trying to use free blocks list + selectedBlock = 0; + } + mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock; + } + 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() ); + } + } + + desc.mImageWidth = width; + desc.mImageHeight = height; + desc.mAtlasId = foundAtlas + 1u; + desc.mCount = 1u; + + // See if there's a previously freed image ID that we can assign to this new image + uint32_t imageId = 0; + for ( uint32_t i = 0; i < mImageList.size(); ++i ) + { + if ( !mImageList[ i ].mCount ) + { + imageId = i + 1u; + break; + } + } + if ( !imageId ) + { + mImageList.push_back( desc ); + slot.mImageId = mImageList.size(); + } + else + { + mImageList[ imageId - 1u ] = desc; + slot.mImageId = imageId; + } + slot.mAtlasId = foundAtlas + 1u; + UploadImage( image, desc ); +} + +AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas, + SizeType width, + SizeType height, + Pixel::Format pixelFormat, + SizeType& blockArea, + SizeType& totalBlocks ) +{ + if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat ) + { + // Work out how many blocks wide and high our bitmap is in the atlas' block size + SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth; + if ( width % mAtlasList[ atlas ].mBlockWidth ) + { + widthInBlocks++; + } + SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight; + if ( height % mAtlasList[ atlas ].mBlockHeight ) + { + heightInBlocks++; + } + blockArea = widthInBlocks * heightInBlocks; + + // Check to see if there are any unused blocks in this atlas to accomodate our image + SizeType blocksInX = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth; + SizeType blocksInY = mAtlasList[ atlas ].mHeight / mAtlasList[ atlas ].mBlockHeight; + totalBlocks = blocksInX * blocksInY; + SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ? totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u : 0; + + // Check to see if there are enough blocks to accomodate our sliced image ? + if ( blockArea <= ( mAtlasList[ atlas ].mFreeBlocksList.Size() + blocksFree ) ) + { + // Yes, we've found room + return ( atlas + 1u ); + } + } + return 0; +} + +void AtlasManager::CreateMesh( SizeType atlas, + SizeType imageWidth, + SizeType imageHeight, + const Vector2& position, + SizeType widthInBlocks, + SizeType heightInBlocks, + Dali::MeshData& meshData, + AtlasSlotDescriptor& desc ) +{ + Dali::MeshData::Vertex vertex; + Dali::MeshData::VertexContainer vertices; + Dali::MeshData::FaceIndices faces; + Dali::MeshData::FaceIndex faceIndex = 0; + meshData.SetHasNormals( false ); + meshData.SetHasColor( true ); + meshData.SetHasTextureCoords( true ); + + SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth; + SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight; + + float vertexBlockWidth = static_cast< float >( blockWidth ); + float vertexBlockHeight = static_cast< float >( blockHeight ); + + SizeType width = mAtlasList[ atlas ].mWidth; + SizeType height = mAtlasList[ atlas ].mHeight; + + SizeType atlasWidthInBlocks = width / 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 ); + + // 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 = vertexEdgeWidth * texelX; + float texelEdgeHeight = vertexEdgeHeight * texelY; + + // Block by block create the two triangles for the quad + SizeType blockIndex = 0; + float ndcWidth; + float ndcHeight; + float ndcVWidth; + float ndcVHeight; + + Vector2 topLeft = position; + + for ( SizeType y = 0; y < heightInBlocks; ++y ) + { + + float currentX = position.x; + + if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f ) + { + ndcHeight = texelEdgeHeight; + ndcVHeight = vertexEdgeHeight; + } + else + { + ndcHeight = texelBlockHeight; + 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 ); + + if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f ) + { + ndcWidth = texelEdgeWidth; + ndcVWidth = vertexEdgeWidth; + } + else + { + ndcWidth = texelBlockWidth; + ndcVWidth = vertexBlockWidth; + } + + // Top left + vertex.x = topLeft.x; + vertex.y = topLeft.y; + vertex.z = 0.0f; + vertex.u = fBlockX; + vertex.v = fBlockY; + + vertices.push_back( vertex ); + + // Top Right + vertex.x = topLeft.x + ndcVWidth; + vertex.y = topLeft.y; + vertex.z = 0.0f; + vertex.u = fBlockX + ndcWidth; + vertex.v = fBlockY; + + vertices.push_back( vertex ); + + // Bottom Left + vertex.x = topLeft.x; + vertex.y = topLeft.y + ndcVHeight; + vertex.z = 0.0f; + vertex.u = fBlockX; + vertex.v = fBlockY + ndcHeight; + + vertices.push_back( vertex ); + + // Bottom Right + topLeft.x += ndcVWidth; + vertex.x = topLeft.x; + vertex.y = topLeft.y + ndcVHeight; + vertex.z = 0.0f; + vertex.u = fBlockX + ndcWidth; + vertex.v = fBlockY + ndcHeight; + + vertices.push_back( vertex ); + + // Six indices in counter clockwise winding + faces.push_back( faceIndex + 1u ); + faces.push_back( faceIndex ); + faces.push_back( faceIndex + 2u ); + faces.push_back( faceIndex + 2u ); + faces.push_back( faceIndex + 3u ); + faces.push_back( 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 ) + { + Dali::MeshData::VertexContainer optimizedVertices; + OptimizeVertices( vertices, faces, optimizedVertices ); + meshData.SetVertices( optimizedVertices ); + } + else + { + meshData.SetVertices( vertices ); + } + + meshData.SetFaceIndices( faces ); + meshData.SetMaterial( mAtlasList[ atlas ].mMaterial ); + //PrintMeshData( meshData ); +} + +void AtlasManager::PrintMeshData( const MeshData& meshData ) +{ + std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount(); + std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl; + + Dali::MeshData::VertexContainer vertices = meshData.GetVertices(); + Dali::MeshData::FaceIndices faces = meshData.GetFaces(); + + for ( SizeType v = 0; v < vertices.size(); ++v ) + { + std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", "; + std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", "; + std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl; + } + + std::cout << "\n Indices: "; + for ( SizeType i = 0; i < faces.size(); ++i ) + { + std::cout << " " << faces[ i ]; + } + std::cout << std::endl; +} + +void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in, + MeshData::FaceIndices& faces, + MeshData::VertexContainer& 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 < faces.size(); ++i ) + { + // Fetch a vertex, has it already been assigned? + bool foundVertex = false; + Dali::MeshData::Vertex v = in[ faces [ i ] ]; + for ( SizeType j = 0; j < vertexIndex; ++j ) + { + if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z && + v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX && + v.nY == out[ j ].nY && v.nZ == out[ j ].nZ ) + { + // Yes, so store this down as the vertex to use + faces[ i ] = j; + foundVertex = true; + break; + } + } + + // Did we find a vertex ? + if ( !foundVertex ) + { + // Add a new vertex + faces[ i ] = vertexIndex++; + out.push_back( v ); + } + } +} + +void AtlasManager::StitchMesh( MeshData& first, + const MeshData& second, + bool optimize ) +{ + + // Would be much quicker to be able to get a non-const reference to these containers and update in situ + MeshData::VertexContainer v1 = first.GetVertices(); + MeshData::VertexContainer v2 = second.GetVertices(); + MeshData::FaceIndices f1 = first.GetFaces(); + MeshData::FaceIndices f2 = second.GetFaces(); + + uint32_t vc1 = first.GetVertexCount(); + uint32_t vc2 = second.GetVertexCount(); + + for ( uint32_t v = 0; v < vc2; ++v ) + { + v1.push_back( v2[ v ] ); + } + + for ( uint32_t f = 0; f < f2.size(); ++f ) + { + f1.push_back( f2[ f ] + vc1 ); + } + + if ( optimize ) + { + MeshData::VertexContainer optimizedVertices; + OptimizeVertices( v1, f1, optimizedVertices ); + first.SetVertices( optimizedVertices ); + } + else + { + first.SetVertices( v1 ); + } + + first.SetFaceIndices( f1 ); + + // TODO rather than set the material to the second, check to see if there's a match and return if not + first.SetMaterial( second.GetMaterial() ); +} + +void AtlasManager::StitchMesh( const MeshData& first, + const MeshData& second, + MeshData& out, + bool optimize ) +{ + // TODO Would be much quicker to be able to get a non-const reference to these containers and update in situ + MeshData::VertexContainer v1 = first.GetVertices(); + MeshData::VertexContainer v2 = second.GetVertices(); + MeshData::FaceIndices f1 = first.GetFaces(); + MeshData::FaceIndices f2 = second.GetFaces(); + + uint32_t vc1 = first.GetVertexCount(); + uint32_t vc2 = second.GetVertexCount(); + + MeshData::VertexContainer vertices; + + MeshData::FaceIndices faces; + + MeshData::Vertex vertex; + + for ( uint32_t v = 0; v < vc1; ++v ) + { + vertices.push_back( v1[ v ] ); + } + + for ( uint32_t v = 0; v < vc2; ++v ) + { + vertices.push_back( v2[ v ] ); + } + + for ( uint32_t f = 0; f < f1.size(); ++f ) + { + faces.push_back( f1[ f ] ); + } + + for ( uint32_t f = 0; f < f2.size(); ++f ) + { + faces.push_back( f2[ f ] + vc1 ); + } + + if ( optimize ) + { + MeshData::VertexContainer optimizedVertices; + OptimizeVertices( vertices, faces, optimizedVertices ); + out.SetVertices( optimizedVertices ); + } + else + { + out.SetVertices( vertices ); + } + + // TODO rather than set the material to the second, check to see if there's a match and return if not + out.SetMaterial( second.GetMaterial() ); + out.SetFaceIndices( faces ); +} + +void AtlasManager::UploadImage( const BufferImage& image, + const AtlasSlotDescriptor& desc ) +{ + // Get the atlas to upload the image to + SizeType atlas = desc.mAtlasId - 1u; + + // Check to see that the pixel formats are compatible + if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat ) + { + DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n"); + return; + } + + SizeType atlasBlockWidth = mAtlasList[ atlas ].mBlockWidth; + SizeType atlasBlockHeight = mAtlasList[ atlas ].mBlockHeight; + SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth; + + SizeType block = desc.mBlocksList[ 0 ]; + SizeType blockX = block % atlasWidthInBlocks; + SizeType blockY = block / atlasWidthInBlocks; + SizeType blockOffsetX = blockX * atlasBlockWidth; + SizeType blockOffsetY = blockY * atlasBlockHeight; + + if ( !mAtlasList[ atlas ].mAtlas.Upload( image, blockOffsetX, blockOffsetY ) ) + { + DALI_LOG_ERROR("Uploading block to Atlas Failed!.\n"); + } +} + +void AtlasManager::GenerateMeshData( ImageId id, + const Vector2& position, + MeshData& meshData ) +{ + // Read the atlas Id to use for this image + SizeType imageId = id - 1u; + SizeType atlas = mImageList[ imageId ].mAtlasId - 1u; + SizeType width = mImageList[ imageId ].mImageWidth; + SizeType height = mImageList[ imageId ].mImageHeight; + + SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth; + if ( width % mAtlasList[ atlas ].mBlockWidth ) + { + widthInBlocks++; + } + SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight; + if ( height % mAtlasList[ atlas ].mBlockHeight ) + { + heightInBlocks++; + } + + CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] ); + + // Mesh created so increase the reference count + mImageList[ imageId ].mCount++; +} + +Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const +{ + Dali::Atlas null; + if ( !atlas || atlas > mAtlasList.size( ) ) + { + + DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n"); + return null; + } + return mAtlasList[ atlas -1u ].mAtlas; +} + +bool AtlasManager::Remove( ImageId id ) +{ + // Decrements the reference count of this image, and removes the blocks if zero. + SizeType imageId = id - 1u; + bool removed = false; + + if ( id > mImageList.size() ) + { + DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id ); + return false; + } + + // If we attempt to free an image that is already freed then do nothing, other than log + if ( !mImageList[ imageId ].mCount ) + { + DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id ); + return false; + } + + if ( 1u == --mImageList[ imageId ].mCount ) + { + // 'Remove the blocks' from this image and add to the atlas' freelist + 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 ] ); + } + } + return removed; +} + +AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const +{ + if ( id && id <= mImageList.size() ) + { + return mImageList[ id - 1u ].mAtlasId; + } + else + { + return 0; + } +} + +void AtlasManager::SetAtlasSize( const Vector2& size, + const Vector2& blockSize ) +{ + mNewAtlasSize = size; + mNewBlockSize = blockSize; +} + +Vector2 AtlasManager::GetBlockSize( AtlasId atlas ) +{ + if ( atlas && atlas <= mAtlasList.size() ) + { + return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ), + static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) ); + } + else + { + return Vector2( 0.0f, 0.0f ); + } +} + +AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const +{ + if ( atlas && atlas <= mAtlasList.size() ) + { + uint32_t index = atlas - 1u; + uint32_t width = mAtlasList[ index ].mWidth; + uint32_t height = mAtlasList[ index ].mHeight; + uint32_t blockWidth = mAtlasList[ index ].mBlockWidth; + uint32_t blockHeight = mAtlasList[ index ].mBlockHeight; + + //Work out how many blocks wide and high our bitmap is in the atlas' block size + SizeType widthInBlocks = width / blockWidth; + if ( width % blockWidth ) + { + widthInBlocks++; + } + SizeType heightInBlocks = height / blockHeight; + if ( height % blockHeight ) + { + heightInBlocks++; + } + + uint32_t blockCount = widthInBlocks * heightInBlocks; + + // Check free previously unallocated blocks and any free blocks + blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size(); + return blockCount; + } + else + { + return 0; + } +} + +AtlasManager::SizeType AtlasManager::GetAtlasCount() const +{ + return mAtlasList.size(); +} + +Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas ) +{ + if ( !atlas || atlas > mAtlasList.size( ) ) + { + + DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n"); + return Pixel::L8; + } + return mAtlasList[ atlas -1u ].mPixelFormat; +} + + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + + diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager-impl.h b/dali-toolkit/internal/atlas-manager/atlas-manager-impl.h new file mode 100644 index 0000000..14f6c72 --- /dev/null +++ b/dali-toolkit/internal/atlas-manager/atlas-manager-impl.h @@ -0,0 +1,234 @@ +#ifndef __DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H__ +#define __DALI_TOOLKIT_ATLAS_MANAGER_IMPL_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. + */ + + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +class AtlasManager; + +} // namespace Toolkit + +namespace Toolkit +{ + +namespace Internal +{ + +typedef Dali::Vector< Toolkit::AtlasManager::AtlasSlot > slotContainer; + +class AtlasManager; +typedef IntrusivePtr AtlasManagerPtr; + +class AtlasManager : public Dali::BaseObject +{ +public: + + typedef uint32_t SizeType; + typedef SizeType AtlasId; + typedef SizeType ImageId; + + /** + * @brief Internal storage of atlas attributes and image upload results + */ + struct AtlasDescriptor + { + Dali::Atlas mAtlas; // atlas image + SizeType mWidth; // width of atlas + SizeType mHeight; // height of atlas + SizeType mBlockWidth; // width of a block in atlas + SizeType mBlockHeight; // height of a block in atlas + Pixel::Format mPixelFormat; // pixel format used by atlas + Material mMaterial; // material used for atlas texture + SizeType mNextFreeBlock; // next free block will be placed here ( actually +1 ) + Dali::Vector< SizeType > mFreeBlocksList; // unless there are any previously freed blocks + }; + + struct AtlasSlotDescriptor + { + SizeType mCount; // Reference count for this slot + 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 + }; + + AtlasManager(); + + /** + * Create a new AtlasManager + */ + static AtlasManagerPtr New(); + + virtual ~AtlasManager(); + + /** + * @copydoc: Toolkit::AtlasManager::CreateAtlas + */ + AtlasId CreateAtlas( SizeType width, + SizeType height, + SizeType blockWidth, + SizeType blockHeight, + Pixel::Format pixelformat ); + + /** + * @copydoc Toolkit::AtlasManager::SetAddPolicy + */ + void SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy ); + + /** + * @copydoc Toolkit::AtlasManager::Add + */ + void Add( const BufferImage& image, + Toolkit::AtlasManager::AtlasSlot& slot, + Toolkit::AtlasManager::AtlasId atlas ); + + /** + * @copydoc Toolkit::AtlasManager::GenerateMeshData + */ + void GenerateMeshData( ImageId id, + const Vector2& position, + MeshData& mesh ); + + /** + * @copydoc Toolkit::AtlasManager::StitchMesh + */ + void StitchMesh( MeshData& first, + const MeshData& second, + bool optimize ); + + /** + * @copydoc Toolkit::AtlasManager::StitchMesh + */ + void StitchMesh( const MeshData& first, + const MeshData& second, + MeshData& out, bool optimize ); + + /** + * @copydoc Toolkit::AtlasManager::Remove + */ + bool Remove( ImageId id ); + + /** + * @copydoc Toolkit::AtlasManager::GetAtlasContainer + */ + Dali::Atlas GetAtlasContainer( AtlasId atlas ) const; + + /** + * @copydoc Toolkit::AtlasManager::GetAtlas + */ + AtlasId GetAtlas( ImageId id ) const; + + /** + * @copydoc Toolkit::AtlasManager::SetAtlasSize + */ + void SetAtlasSize( const Vector2& size, + const Vector2& blockSize ); + + /** + * @copydoc Toolkit::AtlasManager::GetBlockSize + */ + Vector2 GetBlockSize( AtlasId atlas ); + + /** + * @copydoc Toolkit::AtlasManager::GetFreeBlocks + */ + SizeType GetFreeBlocks( AtlasId atlas ) const; + + /* + * @copydoc Toolkit::AtlasManager::GetAtlasCount + */ + SizeType GetAtlasCount() const; + + /** + * @copydoc Toolkit::AtlasManager::GetPixelFormat + */ + Pixel::Format GetPixelFormat( AtlasId atlas ); + +private: + + std::vector< AtlasDescriptor > mAtlasList; // List of atlases created + std::vector< AtlasSlotDescriptor > mImageList; // List of bitmaps store in atlases + + SizeType CheckAtlas( SizeType atlas, + SizeType width, + SizeType height, + Pixel::Format pixelFormat, + SizeType& blockArea, + SizeType& totalBlocks ); + + void CreateMesh( SizeType atlas, + SizeType imageWidth, + SizeType imageHeight, + const Vector2& position, + SizeType widthInBlocks, + SizeType heightInBlocks, + Dali::MeshData& meshData, + AtlasSlotDescriptor& desc ); + + void OptimizeVertices( const MeshData::VertexContainer& in, + MeshData::FaceIndices& faces, + MeshData::VertexContainer& out ); + + void UploadImage( const BufferImage& image, + const AtlasSlotDescriptor& desc ); + + void PrintMeshData( const MeshData& meshData ); + + Vector2 mNewAtlasSize; + Vector2 mNewBlockSize; + Toolkit::AtlasManager::AddFailPolicy mAddFailPolicy; +}; + +} // namespace Internal + +inline const Internal::AtlasManager& GetImplementation(const Toolkit::AtlasManager& manager) +{ + DALI_ASSERT_ALWAYS( manager && "AtlasManager handle is empty" ); + + const BaseObject& handle = manager.GetBaseObject(); + + return static_cast(handle); +} + +inline Internal::AtlasManager& GetImplementation(Toolkit::AtlasManager& manager) +{ + DALI_ASSERT_ALWAYS( manager && "AtlasManager handle is empty" ); + + BaseObject& handle = manager.GetBaseObject(); + + return static_cast(handle); +} + +} // namespace Toolkit + +} // namespace Dali + + + #endif // __DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H__ \ No newline at end of file diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager.cpp b/dali-toolkit/internal/atlas-manager/atlas-manager.cpp new file mode 100644 index 0000000..85d6cba --- /dev/null +++ b/dali-toolkit/internal/atlas-manager/atlas-manager.cpp @@ -0,0 +1,136 @@ +/* + * 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 + + // INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +AtlasManager::AtlasManager() +{ +} + +AtlasManager::~AtlasManager() +{ +} + +AtlasManager AtlasManager::New() +{ + Internal::AtlasManagerPtr internal = Internal::AtlasManager::New(); + return AtlasManager(internal.Get()); +} + +AtlasManager::AtlasManager(Internal::AtlasManager *impl) + : BaseHandle(impl) +{ +} + +AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width, + SizeType height, + SizeType blockWidth, + SizeType blockHeight, + Pixel::Format pixelformat ) +{ + return GetImplementation(*this).CreateAtlas( width, height, blockWidth, blockHeight, pixelformat ); +} + +void AtlasManager::SetAddPolicy( AddFailPolicy policy ) +{ + GetImplementation(*this).SetAddPolicy( policy ); +} + +void AtlasManager::Add( const BufferImage& image, + AtlasManager::AtlasSlot& slot, + AtlasManager::AtlasId atlas ) +{ + GetImplementation(*this).Add( image, slot, atlas ); +} + +bool AtlasManager::Remove( ImageId id ) +{ + return GetImplementation(*this).Remove( id ); +} + +void AtlasManager::GenerateMeshData( ImageId id, + const Vector2& position, + MeshData& meshData) +{ + GetImplementation(*this).GenerateMeshData( id, + position, + meshData ); +} + +void AtlasManager::StitchMesh( MeshData& first, + const MeshData& second, + bool optimize ) +{ + GetImplementation(*this).StitchMesh( first, second, optimize ); +} + +void AtlasManager::StitchMesh( const MeshData& first, + const MeshData& second, + MeshData& out, + bool optimize ) +{ + GetImplementation(*this).StitchMesh( first, second, out, optimize ); +} + +Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const +{ + return GetImplementation(*this).GetAtlasContainer( atlas ); +} + +AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) +{ + return GetImplementation(*this).GetAtlas( id ); +} + +Vector2 AtlasManager::GetBlockSize( AtlasId atlas ) +{ + return GetImplementation(*this).GetBlockSize( atlas ); +} + +AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) +{ + return GetImplementation(*this).GetFreeBlocks( atlas ); +} + +void AtlasManager::SetAtlasSize( const Vector2& size, + const Vector2& blockSize ) +{ + GetImplementation(*this).SetAtlasSize( size, blockSize ); +} + +AtlasManager::SizeType AtlasManager::GetAtlasCount() const +{ + return GetImplementation(*this).GetAtlasCount(); +} + +Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas ) +{ + return GetImplementation(*this).GetPixelFormat( atlas ); +} + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager.h b/dali-toolkit/internal/atlas-manager/atlas-manager.h new file mode 100644 index 0000000..55612ff --- /dev/null +++ b/dali-toolkit/internal/atlas-manager/atlas-manager.h @@ -0,0 +1,352 @@ +#ifndef __DALI_TOOLKIT_ATLAS_MANAGER_H__ +#define __DALI_TOOLKIT_ATLAS_MANAGER_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. + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal DALI_INTERNAL +{ + +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: + + typedef uint32_t SizeType; + typedef SizeType AtlasId; + typedef SizeType ImageId; + static const bool MESH_OPTIMIZE = true; + + /** + * Create an AtlasManager handle; this can be initialised with AtlasManager::New() + * Calling member functions with an uninitialised handle is not allowed. + */ + AtlasManager(); + + /** + * @brief Get new instance of AtlasManager object. + * + * @return A handle to the AtlasManager control. + */ + static AtlasManager New(); + + /** + * @brief Destructor + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~AtlasManager(); + + /** + * Policy on failing to add an image + */ + enum AddFailPolicy + { + FAIL_ON_ADD_FAILS, + FAIL_ON_ADD_CREATES + }; + + /** + * @brief Container to hold result of placing texture into atlas + */ + struct AtlasSlot + { + ImageId mImageId; // Id of stored Image + AtlasId mAtlasId; // Id of Atlas containing this slot + }; + + typedef Dali::Vector< AtlasManager::AtlasSlot > slotContainer; + + /** + * @brief Create a blank atlas of specific dimensions and pixel format with a certain block size + * + * @param width desired atlas width in pixels + * @param height desired atlas height in pixels + * @param blockWidth block width to use in atlas in pixels + * @param blockHeight block height to use in atlas in pixels + * @param pixelformat format of a pixel in atlas + * + * @return atlas Id + */ + AtlasId CreateAtlas( SizeType width, + SizeType height, + SizeType blockWidth, + SizeType blockHeight, + Pixel::Format pixelformat = Pixel::RGBA8888 ); + + /** + * @brief Set the policy on failure to add an image to an atlas + * + * @param policy policy to carry out if add fails + */ + void SetAddPolicy( AddFailPolicy policy ); + + /** + * @brief Attempts to add an image to the most suitable atlas + * + * @details Add Policy may dictate that a new atlas is created if it can't presently be placed. + * If an add is made before an atlas is created under this policy, + * then a default size atlas will be created + * + * @param[in] image reference to a bitmapimage + * @param[out] slot result of add operation + * @param[in] atlas optional preferred atlas + */ + void Add( const BufferImage& image, + AtlasSlot& slot, + AtlasId atlas = 0 ); + + /** + * @brief Remove previously added bitmapimage from atlas + * + * @param[in] id ImageId returned in the AtlasSlot from the add operation + * + * @return if true then image has been removed from the atlas + */ + bool Remove( ImageId id ); + + /** + * @brief Generate mesh data for a previously added image + * + * @param[in] id Image Id returned in the AtlasSlot from the add operation + * @param[in] position position of the resulting mesh in model space + * @param[out] mesh Mesh Data Object to populate with mesh data + */ + void GenerateMeshData( ImageId id, + const Vector2& position, + MeshData& mesh ); + + /** + * @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( MeshData& first, + const MeshData& second, + bool optimize = false ); + + /** + * @brief Combine two meshes, outputting the result into a new mesh + * + * @param[in] first First mesh + * @param[in] second Second mesh + * @param[in] optimize should we optimize vertex data + * @param[out] out resulting mesh + */ + void StitchMesh( const MeshData& first, + const MeshData& second, + MeshData& out, + bool optimize = false ); + + /** + * @brief Get the BufferImage containing an atlas + * + * @param atlas AtlasId returned when atlas was created + * @return Atlas Handle + */ + Dali::Atlas GetAtlasContainer( AtlasId atlas ) const; + + /** + * @brief Get the Id of the atlas containing an image + * + * @param id ImageId + * @return Atlas Id + */ + AtlasId GetAtlas( ImageId id ); + + /** + * @brief Get the size of the blocks used in an atlas + * + * @param atlas AtlasId + * @return width and height of the blocks used + */ + Vector2 GetBlockSize( AtlasId atlas ); + + /** + * @brief Get the number of blocks available in an atlas + * + * @param atlas AtlasId + * @return Number of blocks free in this atlas + */ + SizeType GetFreeBlocks( AtlasId atlas ); + + /** + * @brief Sets the pixel area of any new atlas and also the individual block size + * + * @param size pixel area of atlas + * @param blockSize pixel area in atlas for a block + */ + void SetAtlasSize( const Vector2& size, + const Vector2& blockSize ); + + /** + * @brief Get the number of atlases created + * + * @return number of atlases + */ + SizeType GetAtlasCount() const; + + /** + * @brief Get the pixel format used by an atlas + * + * @param atlas AtlasId + * @return Pixel format used by this atlas + */ + Pixel::Format GetPixelFormat( AtlasId atlas ); + +private: + + explicit DALI_INTERNAL AtlasManager(Internal::AtlasManager *impl); + +}; + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_ATLAS_MANAGER_H__ \ No newline at end of file diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp index bfa89f6..5c5591a 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -30,17 +30,10 @@ // INTERNAL INCLUDES #include #include +#include using namespace Dali::Toolkit::Text; -namespace -{ - -const unsigned int DEFAULT_RENDERING_BACKEND = 0; - -} // namespace - - namespace Dali { @@ -52,6 +45,11 @@ namespace Internal namespace { + const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND; +} + +namespace +{ // Type registration BaseHandle Create() diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 43a600d..fdce0ed 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -26,17 +26,11 @@ // INTERNAL INCLUDES #include #include +#include using Dali::Toolkit::Text::LayoutEngine; using Dali::Toolkit::Text::Backend; -namespace -{ - -const unsigned int DEFAULT_RENDERING_BACKEND = 0; - -} // namespace - namespace Dali { @@ -48,6 +42,11 @@ namespace Internal namespace { + const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND; +} + +namespace +{ // Type registration BaseHandle Create() diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index e3f1495..9391d2f 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -1,6 +1,8 @@ # 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 \ @@ -90,6 +92,9 @@ toolkit_src_files = \ $(toolkit_src_dir)/text/multi-language-support-impl.cpp \ $(toolkit_src_dir)/text/rendering/text-backend.cpp \ $(toolkit_src_dir)/text/rendering/text-renderer.cpp \ + $(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/basic/text-basic-renderer.cpp \ $(toolkit_src_dir)/text/rendering/shaders/text-basic-shader.cpp \ $(toolkit_src_dir)/text/rendering/shaders/text-bgra-shader.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 new file mode 100644 index 0000000..001281e --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp @@ -0,0 +1,141 @@ + /* + * 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 + +// EXTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +//#define DISPLAY_ATLAS + +AtlasGlyphManager::AtlasGlyphManager() +: mCount( 0 ) +{ + mAtlasManager = Dali::Toolkit::AtlasManager::New(); +} + +AtlasGlyphManager::~AtlasGlyphManager() +{ +} + +AtlasGlyphManagerPtr AtlasGlyphManager::New() +{ + AtlasGlyphManagerPtr internal = new AtlasGlyphManager(); + return internal; +} + +void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, + const BufferImage& bitmap, + Dali::Toolkit::AtlasManager::AtlasSlot& slot ) +{ + GlyphRecord record; + record.mFontId = glyph.fontId; + record.mIndex = glyph.index; + + mAtlasManager.Add( bitmap, slot ); + record.mImageId = slot.mImageId; + mGlyphRecords.PushBack( record ); + +#ifdef DISPLAY_ATLAS + { + uint32_t atlasCount = mAtlasManager.GetAtlasCount(); + if ( atlasCount > mCount ) + { + for ( uint32_t i = 0; i < atlasCount; ++i ) + { + ImageActor actor = ImageActor::New( mAtlasManager.GetAtlasContainer( i + 1u ) ); + actor.SetParentOrigin( Vector3( 0.5f, 0.25f + ( static_cast< float >( i ) * 0.25f ), 0.5f ) ); + actor.SetAnchorPoint( AnchorPoint::CENTER ); + actor.SetSize( 256.0f, 256.0f ); + Stage::GetCurrent().Add( actor ); + } + } + mCount = atlasCount; + } +#endif +} + +void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, + const Vector2& position, + MeshData& meshData ) +{ + mAtlasManager.GenerateMeshData( imageId, position, meshData ); +} + +void AtlasGlyphManager::StitchMesh( MeshData& first, + const MeshData& second ) +{ + mAtlasManager.StitchMesh( first, second ); +} + +void AtlasGlyphManager::Cached( Text::FontId fontId, + uint32_t index, + Dali::Toolkit::AtlasManager::AtlasSlot& slot ) +{ + for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i ) + { + if ( fontId == mGlyphRecords[ i ].mFontId && index == mGlyphRecords[ i ].mIndex ) + { + slot.mImageId = mGlyphRecords[ i ].mImageId; + slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId ); + return; + } + } + slot.mImageId = 0; +} + +void AtlasGlyphManager::SetAtlasSize( const Vector2& size, + const Vector2& blockSize ) +{ + mAtlasManager.SetAtlasSize( size, blockSize ); +} + +void AtlasGlyphManager::Remove( uint32_t imageId ) +{ + if ( mAtlasManager.Remove( imageId ) ) + { + for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i ) + { + if ( mGlyphRecords[ i ].mImageId == imageId ) + { + mGlyphRecords.Remove( mGlyphRecords.Begin() + i ); + return; + } + } + } +} + +Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId ) +{ + return mAtlasManager.GetPixelFormat( atlasId ); +} + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali 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 new file mode 100644 index 0000000..c4da1ba --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h @@ -0,0 +1,143 @@ + +#ifndef __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__ +#define __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_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. + */ + + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +class AtlasGlyphManager; + +} // namespace Toolkit + +namespace Toolkit +{ + +namespace Internal +{ + +class AtlasGlyphManager; +typedef IntrusivePtr AtlasGlyphManagerPtr; + +class AtlasGlyphManager : public Dali::BaseObject +{ +public: + + struct GlyphRecord + { + Text::FontId mFontId; + Text::GlyphIndex mIndex; + uint32_t mImageId; + }; + + AtlasGlyphManager(); + + virtual ~AtlasGlyphManager(); + +/** + * Create a new AtlasGlyphManager + */ + static AtlasGlyphManagerPtr New(); + + /** + * @copydoc Toolkit::AtlasGlyphManager::Add + */ + void Add( const Text::GlyphInfo& glyph, + const BufferImage& bitmap, + Dali::Toolkit::AtlasManager::AtlasSlot& slot ); + + /** + * @copydoc Toolkit::AtlasGlyphManager::GenerateMeshData + */ + void GenerateMeshData( uint32_t imageId, + const Vector2& position, + MeshData& meshData ); + + /** + * @copydoc Toolkit::AtlasGlyphManager::StitchMesh + */ + void StitchMesh( MeshData& first, + const MeshData& second ); + + /** + * @copydoc Toolkit::AtlasGlyphManager::Cached + */ + void Cached( Text::FontId fontId, + Text::GlyphIndex index, + Dali::Toolkit::AtlasManager::AtlasSlot& slot ); + + /** + * @copydoc Toolkit::AtlasGlyphManager::SetAtlasSize + */ + void SetAtlasSize( const Vector2& size, + const Vector2& blockSize ); + + /** + * @copydoc Toolkit::AtlasGlyphManager::Remove + */ + void Remove( uint32_t imageId ); + + /** + * @copydoc toolkit::AtlasGlyphManager::GetPixelFormat + */ + Pixel::Format GetPixelFormat( uint32_t atlasId ); + +private: + + Dali::Toolkit::AtlasManager mAtlasManager; + Vector< GlyphRecord > mGlyphRecords; + uint32_t mCount; +}; + +} // namespace Internal + +inline const Internal::AtlasGlyphManager& GetImplementation(const Toolkit::AtlasGlyphManager& manager) +{ + DALI_ASSERT_ALWAYS( manager && "AtlasGlyphManager handle is empty" ); + + const BaseObject& handle = manager.GetBaseObject(); + + return static_cast(handle); +} + +inline Internal::AtlasGlyphManager& GetImplementation(Toolkit::AtlasGlyphManager& manager) +{ + DALI_ASSERT_ALWAYS( manager && "AtlasGlyphManager handle is empty" ); + + BaseObject& handle = manager.GetBaseObject(); + + return static_cast(handle); +} + +} // namespace Toolkit + +} // namespace Dali + + + #endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__ \ No newline at end of file diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp new file mode 100644 index 0000000..9ca3773 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp @@ -0,0 +1,119 @@ + /* + * 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +AtlasGlyphManager::AtlasGlyphManager() +{ +} + +AtlasGlyphManager::~AtlasGlyphManager() +{ +} + +AtlasGlyphManager AtlasGlyphManager::Get() +{ + AtlasGlyphManager manager; + + // Check whether the AtlasGlyphManager is already created + SingletonService singletonService( SingletonService::Get() ); + if ( singletonService ) + { + Dali::BaseHandle handle = singletonService.GetSingleton(typeid(AtlasGlyphManager)); + if(handle) + { + // If so, downcast the handle of singleton to AtlasGlyphManager + manager = AtlasGlyphManager(dynamic_cast(handle.GetObjectPtr())); + } + + if(!manager) + { + // If not, create the AtlasGlyphManager and register it as a singleton + manager = AtlasGlyphManager(new Internal::AtlasGlyphManager()); + singletonService.Register(typeid(manager), manager); + } + } + return manager; +} + +AtlasGlyphManager::AtlasGlyphManager(Internal::AtlasGlyphManager *impl) + : BaseHandle(impl) +{ +} + +void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, + const BufferImage& bitmap, + AtlasManager::AtlasSlot& slot ) +{ + GetImplementation(*this).Add( glyph, bitmap, slot ); +} + +void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, + const Vector2& position, + MeshData& meshData ) +{ + GetImplementation(*this).GenerateMeshData( imageId, + position, + meshData ); +} + +void AtlasGlyphManager::StitchMesh( MeshData& first, + const MeshData& second ) +{ + GetImplementation(*this).StitchMesh( first, second ); +} + +void AtlasGlyphManager::Cached( Text::FontId fontId, + Text::GlyphIndex index, + AtlasManager::AtlasSlot& slot ) +{ + GetImplementation(*this).Cached( fontId, index, slot ); +} + +void AtlasGlyphManager::SetAtlasSize( const Vector2& size, + const Vector2& blockSize ) +{ + GetImplementation(*this).SetAtlasSize( size, blockSize ); +} + +void AtlasGlyphManager::Remove( uint32_t imageId ) +{ + GetImplementation(*this).Remove( imageId ); +} + +Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId ) +{ + return GetImplementation(*this).GetPixelFormat( atlasId ); +} + +} // 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 new file mode 100644 index 0000000..a90efdb --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h @@ -0,0 +1,138 @@ +#ifndef __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H__ +#define __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_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 +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal DALI_INTERNAL +{ +class AtlasGlyphManager; +} + + +class DALI_IMPORT_API AtlasGlyphManager : public BaseHandle +{ +public: + + /** + * @brief Create a AtlasGlyphManager handle. + * + * Calling member functions with an uninitialised handle is not allowed. + */ + AtlasGlyphManager(); + + /** + * @brief Destructor + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~AtlasGlyphManager(); + + /** + * @brief Create or retrieve AtlasGlyphManager singleton. + * + * @return A handle to the AtlasGlyphManager control. + */ + static AtlasGlyphManager Get(); + + /** + * @brief Ask Atlas Manager to add a glyph + * + * @param[in] glyph glyph to add to an atlas + * @param[in] bitmap bitmap to use for glyph addition + * @param[out] slot information returned by atlas manager for addition + */ + void Add( const Text::GlyphInfo& glyph, + const BufferImage& bitmap, + AtlasManager::AtlasSlot& slot ); + + /** + * @brief Generate mesh data for an image contained in an atlas + * + * @param[in] imageId ID of image to generate geometry for + * @param[in] position top left of image + * @param[out] meshData generated MeshData + */ + void GenerateMeshData( uint32_t imageId, + const Vector2& position, + MeshData& meshData ); + + /** + * @brief Stitch Two Meshes together + * + * @param[in] first first mesh + * @param[in] second second mesh + */ + void StitchMesh( MeshData& first, + const MeshData& second ); + + /** + * @brief Check to see if a glyph is being cached + * + * @param[in] fontId The font that this glyph comes from + * @param[in] index The GlyphIndex of this glyph + * @param[out] slot container holding information about the glyph( mImage = 0 indicates not being cached ) + */ + void Cached( Text::FontId fontId, + Text::GlyphIndex index, + AtlasManager::AtlasSlot& slot ); + + /** + * @brief Set the Atlas size and block size for subsequent atlas generation + * + * @param[in] size size of the atlas in pixels + * @param[in] blockSize size of a block in this atlas in pixels + */ + void SetAtlasSize( const Vector2& size, + const Vector2& blockSize ); + + /** + * @brief Unreference an image from the atlas and remove from cache if no longer needed + * + * @param[in] imageId ID of the image + */ + void Remove( uint32_t imageId ); + + /** + * @brief Get the Pixel Format used by an atlas + * + * @param atlasId Id of atlas to check + * @return The pixel format of the atlas + */ + Pixel::Format GetPixelFormat( uint32_t atlasId ); + +private: + + explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl); + +}; + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_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 new file mode 100644 index 0000000..0ed74bd --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -0,0 +1,254 @@ +/* + * 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include + +using namespace Dali; +using namespace Dali::Toolkit; +using namespace Dali::Toolkit::Text; + +namespace +{ + const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f ); + const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f ); + const Vector2 PADDING( 2.0f, 2.0f ); +} + +struct AtlasRenderer::Impl +{ + + struct MeshRecord + { + uint32_t mAtlasId; + MeshData mMeshData; + }; + + struct AtlasRecord + { + uint32_t mImageId; + Text::GlyphIndex mIndex; + }; + + Impl() + : mSlotDelegate( this ) + { + mGlyphManager = AtlasGlyphManager::Get(); + mFontClient = TextAbstraction::FontClient::Get(); + mGlyphManager.SetAtlasSize( DEFAULT_ATLAS_SIZE, DEFAULT_BLOCK_SIZE ); + mBasicShader = BasicShader::New(); + mBGRAShader = BgraShader::New(); + } + + void AddGlyphs( const std::vector& positions, const Vector& glyphs ) + { + AtlasManager::AtlasSlot slot; + std::vector< MeshRecord > meshContainer; + + if (mImageIds.Size() ) + { + // Unreference any currently used glyphs + RemoveText(); + } + + // Set the block size to use, if an atlas is created + mGlyphManager.SetAtlasSize( DEFAULT_ATLAS_SIZE, CalculateBlockSize( glyphs ) ); + + for ( uint32_t i = 0; i < glyphs.Size(); ++i ) + { + GlyphInfo glyph = glyphs[ i ]; + + // No operation for white space + if ( glyph.width && glyph.height ) + { + Vector2 position = positions[ i ]; + MeshData newMeshData; + mGlyphManager.Cached( glyph.fontId, glyph.index, slot ); + + if ( slot.mImageId ) + { + // This glyph already exists so generate mesh data plugging in our supplied position + mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData ); + mImageIds.PushBack( slot.mImageId ); + } + else + { + // Glyph doesn't currently exist in atlas so upload + BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index ); + + // Locate a new slot for our glyph + mGlyphManager.Add( glyph, bitmap, slot ); + + // Generate mesh data for this quad, plugging in our supplied position + if ( slot.mImageId ) + { + mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData ); + mImageIds.PushBack( slot.mImageId ); + } + } + // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas) + StitchTextMesh( meshContainer, newMeshData, slot ); + } + } + + // For each MeshData object, create a mesh actor and add to the renderable actor + if ( meshContainer.size() ) + { + for ( uint32_t i = 0; i < meshContainer.size(); ++i ) + { + Mesh mesh = Mesh::New( meshContainer[ i ].mMeshData ); + MeshActor actor = MeshActor::New( mesh ); + actor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );; + + // Check to see what pixel format the shader should be + if ( mGlyphManager.GetPixelFormat( meshContainer[ i ].mAtlasId ) == Pixel::L8 ) + { + actor.SetShaderEffect( mBasicShader ); + } + else + { + actor.SetShaderEffect( mBGRAShader ); + } + + if ( i ) + { + mActor.Add( actor ); + } + else + { + mActor = actor; + } + } + mActor.OffStageSignal().Connect( mSlotDelegate, &AtlasRenderer::Impl::OffStageDisconnect ); + } + } + + void StitchTextMesh( std::vector< MeshRecord >& meshContainer, + MeshData& newMeshData, + AtlasManager::AtlasSlot& slot ) + { + if ( slot.mImageId ) + { + // Check to see if there's a mesh data object that references the same atlas ? + for ( uint32_t i = 0; i < meshContainer.size(); ++i ) + { + if ( slot.mAtlasId == meshContainer[ i ].mAtlasId ) + { + // Stitch the mesh to the existing mesh + mGlyphManager.StitchMesh( meshContainer[ i ].mMeshData, newMeshData ); + return; + } + } + + // No mesh data object currently exists that references this atlas, so create a new one + MeshRecord meshRecord; + meshRecord.mAtlasId = slot.mAtlasId; + meshRecord.mMeshData = newMeshData; + meshContainer.push_back( meshRecord ); + } + } + + // Unreference any glyphs that were used with this actor + void OffStageDisconnect( Dali::Actor actor ) + { + RemoveText(); + } + + void RemoveText() + { + for ( uint32_t i = 0; i < mImageIds.Size(); ++i ) + { + mGlyphManager.Remove( mImageIds[ i ] ); + } + mImageIds.Resize( 0 ); + } + + Vector2 CalculateBlockSize( const Vector& glyphs ) + { + float maxWidth = glyphs[ 0 ].width; + float maxHeight = glyphs[ 0 ].height; + + for ( uint32_t i = 1u; i < glyphs.Size(); ++i ) + { + if ( maxWidth < glyphs[ i ].width ) + { + maxWidth = glyphs[ i ].width; + } + if ( maxHeight < glyphs[ i ].height ) + { + maxHeight = glyphs[ i ].height; + } + } + return Vector2( maxWidth + PADDING.x, maxHeight + PADDING.y ); + } + + RenderableActor mActor; ///< The actor parent which renders the text + AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching + Vector< uint32_t > mImageIds; ///< A list of imageIDs used by the renderer + TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information + SlotDelegate< AtlasRenderer::Impl > mSlotDelegate; ///> Signal generated to unreference glyphs when renderable actor is removed + ShaderEffect mBasicShader; ///> Shader to render L8 glyphs + ShaderEffect mBGRAShader; ///> Shader to render BGRA glyphs +}; + +Text::RendererPtr AtlasRenderer::New() +{ + return Text::RendererPtr( new AtlasRenderer() ); +} + +RenderableActor AtlasRenderer::Render( Text::ViewInterface& view ) +{ + + UnparentAndReset( mImpl->mActor ); + + Text::Length numberOfGlyphs = view.GetNumberOfGlyphs(); + + if( numberOfGlyphs > 0 ) + { + Vector glyphs; + glyphs.Resize( numberOfGlyphs ); + + view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs ); + + std::vector positions; + positions.resize( numberOfGlyphs ); + view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs ); + mImpl->AddGlyphs( positions, glyphs ); + } + return mImpl->mActor; +} + +AtlasRenderer::AtlasRenderer() +{ + mImpl = new Impl(); + +} + +AtlasRenderer::~AtlasRenderer() +{ + delete mImpl; +} \ No newline at end of file diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h new file mode 100644 index 0000000..e259621 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h @@ -0,0 +1,87 @@ +#ifndef __DALI_TOOLKIT_TEXT_ATLAS_RENDERER_H__ +#define __DALI_TOOLKIT_TEXT_ATLAS_RENDERER_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 +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * @brief Implementation of a text renderer based on dynamic atlases. + * + */ +class AtlasRenderer : public Renderer +{ +public: + + /** + * @brief Create the renderer. + */ + static RendererPtr New(); + + /** + * @brief Render the glyphs from a ViewInterface. + * + * @param[in] view The interface to a view. + * @return The Renderable actor used to position the text. + */ + virtual RenderableActor Render( ViewInterface& view ); + +protected: + + /** + * @brief Constructor. + */ + AtlasRenderer(); + + /** + * @brief A reference counted object may only be deleted by calling Unreference(). + */ + virtual ~AtlasRenderer(); + +private: + + // Undefined + AtlasRenderer( const AtlasRenderer& handle ); + + // Undefined + AtlasRenderer& operator=( const AtlasRenderer& handle ); + +private: + + struct Impl; + Impl* mImpl; +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_ATLAS_RENDERER_H__ diff --git a/dali-toolkit/internal/text/rendering/basic/text-basic-renderer.cpp b/dali-toolkit/internal/text/rendering/basic/text-basic-renderer.cpp index 31ab53f..dc6ec3e 100644 --- a/dali-toolkit/internal/text/rendering/basic/text-basic-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/basic/text-basic-renderer.cpp @@ -369,7 +369,7 @@ RenderableActor BasicRenderer::Render( Text::ViewInterface& view ) actorBGRA8888 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::BGRA8888, mImpl->mAtlasBGRA8888 ) ); actorBGRA8888.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); - ShaderEffect shader = BGRAShader::New(); + ShaderEffect shader = BgraShader::New(); actorBGRA8888.SetShaderEffect( shader ); } diff --git a/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.cpp b/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.cpp index 43f61d5..7f2f2a5 100644 --- a/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.cpp +++ b/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.cpp @@ -27,7 +27,7 @@ namespace Toolkit namespace Text { -namespace BGRAShader +namespace BgraShader { Dali::ShaderEffect New() diff --git a/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h b/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h index 70e3c67..16293c6 100644 --- a/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h +++ b/dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h @@ -34,7 +34,7 @@ namespace Text /** * @brief A BGRA shader for rendering glyphs. */ -namespace BGRAShader +namespace BgraShader { /** diff --git a/dali-toolkit/internal/text/rendering/text-backend-impl.cpp b/dali-toolkit/internal/text/rendering/text-backend-impl.cpp index 74b80f1..5653ebf 100644 --- a/dali-toolkit/internal/text/rendering/text-backend-impl.cpp +++ b/dali-toolkit/internal/text/rendering/text-backend-impl.cpp @@ -23,6 +23,8 @@ #include // INTERNAL INCLUDES +#include +#include #include namespace Dali @@ -92,7 +94,7 @@ RendererPtr Backend::NewRenderer( unsigned int renderingType ) case Dali::Toolkit::Text::RENDERING_SHARED_ATLAS: { - // TODO + renderer = Dali::Toolkit::Text::AtlasRenderer::New(); } break; diff --git a/dali-toolkit/internal/text/rendering/text-backend.h b/dali-toolkit/internal/text/rendering/text-backend.h index 62b9f86..df7bfa2 100644 --- a/dali-toolkit/internal/text/rendering/text-backend.h +++ b/dali-toolkit/internal/text/rendering/text-backend.h @@ -38,13 +38,6 @@ namespace Internal DALI_INTERNAL class Backend; } -// The type of text renderer required -enum RenderingType -{ - RENDERING_BASIC, ///< A bitmap-based reference implementation - RENDERING_SHARED_ATLAS ///< A bitmap-based solution where renderers can share a texture atlas -}; - /** * @brief Provides access to different text rendering backends. */ diff --git a/dali-toolkit/public-api/file.list b/dali-toolkit/public-api/file.list index 34774ac..8e1ccdf 100755 --- a/dali-toolkit/public-api/file.list +++ b/dali-toolkit/public-api/file.list @@ -273,3 +273,5 @@ public_api_scripting_header_files = \ $(public_api_src_dir)/scripting/script.h \ $(public_api_src_dir)/scripting/script-plugin.h +public_api_rendering_backend_header_files = \ + $(public_api_src_dir)/text/rendering-backend.h diff --git a/dali-toolkit/public-api/text/rendering-backend.h b/dali-toolkit/public-api/text/rendering-backend.h new file mode 100644 index 0000000..522a307 --- /dev/null +++ b/dali-toolkit/public-api/text/rendering-backend.h @@ -0,0 +1,45 @@ +#ifndef __DALI_TOOLKIT_RENDERING_BACKEND_H__ +#define __DALI_TOOLKIT_RENDERING_BACKEND_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. + * + */ + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +// The type of text renderer required +enum RenderingType +{ + RENDERING_BASIC, ///< A bitmap-based reference implementation + RENDERING_SHARED_ATLAS ///< A bitmap-based solution where renderers can share a texture atlas +}; + +const unsigned int DEFAULT_RENDERING_BACKEND = RENDERING_SHARED_ATLAS; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_RENDERING_BACKEND_H__ -- 2.7.4