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)
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)
#include <dali-toolkit/public-api/scripting/script.h>
#include <dali-toolkit/public-api/scripting/script-plugin.h>
+#include <dali-toolkit/public-api/text/rendering-backend.h>
+
#include <dali-toolkit/public-api/shader-effects/alpha-discard-effect.h>
#include <dali-toolkit/public-api/shader-effects/bendy-effect.h>
#include <dali-toolkit/public-api/shader-effects/blind-effect.h>
--- /dev/null
+/*
+ * 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 <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <dali/integration-api/debug.h>
+
+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
+
+
--- /dev/null
+#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 <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class AtlasManager;
+
+} // namespace Toolkit
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+typedef Dali::Vector< Toolkit::AtlasManager::AtlasSlot > slotContainer;
+
+class AtlasManager;
+typedef IntrusivePtr<AtlasManager> 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<const Internal::AtlasManager&>(handle);
+}
+
+inline Internal::AtlasManager& GetImplementation(Toolkit::AtlasManager& manager)
+{
+ DALI_ASSERT_ALWAYS( manager && "AtlasManager handle is empty" );
+
+ BaseObject& handle = manager.GetBaseObject();
+
+ return static_cast<Internal::AtlasManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+ #endif // __DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H__
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+
+ // INTERNAL INCLUDES
+#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+
+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
--- /dev/null
+#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 <stdint.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/geometry/mesh-data.h>
+#include <dali/public-api/images/atlas.h>
+#include <dali/public-api/images/buffer-image.h>
+
+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
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/layouts/layout-engine.h>
#include <dali-toolkit/internal/text/rendering/text-backend.h>
+#include <dali-toolkit/public-api/text/rendering-backend.h>
using namespace Dali::Toolkit::Text;
-namespace
-{
-
-const unsigned int DEFAULT_RENDERING_BACKEND = 0;
-
-} // namespace
-
-
namespace Dali
{
namespace
{
+ const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+}
+
+namespace
+{
// Type registration
BaseHandle Create()
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/layouts/layout-engine.h>
#include <dali-toolkit/internal/text/rendering/text-backend.h>
+#include <dali-toolkit/public-api/text/rendering-backend.h>
using Dali::Toolkit::Text::LayoutEngine;
using Dali::Toolkit::Text::Backend;
-namespace
-{
-
-const unsigned int DEFAULT_RENDERING_BACKEND = 0;
-
-} // namespace
-
namespace Dali
{
namespace
{
+ const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+}
+
+namespace
+{
// Type registration
BaseHandle Create()
# 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 \
$(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 \
--- /dev/null
+ /*
+ * 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 <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/image-actor.h>
+#include <dali/public-api/common/stage.h>
+
+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
--- /dev/null
+
+#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 <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class AtlasGlyphManager;
+
+} // namespace Toolkit
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class AtlasGlyphManager;
+typedef IntrusivePtr<AtlasGlyphManager> 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<const Internal::AtlasGlyphManager&>(handle);
+}
+
+inline Internal::AtlasGlyphManager& GetImplementation(Toolkit::AtlasGlyphManager& manager)
+{
+ DALI_ASSERT_ALWAYS( manager && "AtlasGlyphManager handle is empty" );
+
+ BaseObject& handle = manager.GetBaseObject();
+
+ return static_cast<Internal::AtlasGlyphManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+ #endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
\ No newline at end of file
--- /dev/null
+ /*
+ * 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 <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h>
+
+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<Internal::AtlasGlyphManager*>(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
--- /dev/null
+#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 <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+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__
--- /dev/null
+/*
+ * 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 <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/dali.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+#include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
+#include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
+
+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<Vector2>& positions, const Vector<GlyphInfo>& 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<GlyphInfo>& 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<GlyphInfo> glyphs;
+ glyphs.Resize( numberOfGlyphs );
+
+ view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
+
+ std::vector<Vector2> 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
--- /dev/null
+#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 <dali-toolkit/internal/text/rendering/text-renderer.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+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__
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 );
}
namespace Text
{
-namespace BGRAShader
+namespace BgraShader
{
Dali::ShaderEffect New()
/**
* @brief A BGRA shader for rendering glyphs.
*/
-namespace BGRAShader
+namespace BgraShader
{
/**
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/rendering-backend.h>
+#include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
#include <dali-toolkit/internal/text/rendering/basic/text-basic-renderer.h>
namespace Dali
case Dali::Toolkit::Text::RENDERING_SHARED_ATLAS:
{
- // TODO
+ renderer = Dali::Toolkit::Text::AtlasRenderer::New();
}
break;
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.
*/
$(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
--- /dev/null
+#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__