Text Rendering via Atlas Renderer 87/36387/6
authorRichard Underhill <r.underhill@partner.samsung.com>
Thu, 12 Mar 2015 13:39:33 +0000 (13:39 +0000)
committerRichard Underhill <r.underhill@partner.samsung.com>
Thu, 12 Mar 2015 16:25:16 +0000 (16:25 +0000)
Change-Id: I7fe87403467f2f9e979935d217a34569d2ebe36b
Signed-off-by: Richard Underhill <r.underhill@partner.samsung.com>
22 files changed:
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/dali-toolkit.h
dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/atlas-manager/atlas-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/atlas-manager/atlas-manager.cpp [new file with mode: 0644]
dali-toolkit/internal/atlas-manager/atlas-manager.h [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/basic/text-basic-renderer.cpp
dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.cpp
dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h
dali-toolkit/internal/text/rendering/text-backend-impl.cpp
dali-toolkit/internal/text/rendering/text-backend.h
dali-toolkit/public-api/file.list
dali-toolkit/public-api/text/rendering-backend.h [new file with mode: 0644]

index d5567eb..ff48b23 100644 (file)
@@ -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)
 
index 11ab4e0..8949d3f 100644 (file)
@@ -87,6 +87,8 @@
 #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>
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 (file)
index 0000000..da6ae94
--- /dev/null
@@ -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 <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
+
+
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 (file)
index 0000000..14f6c72
--- /dev/null
@@ -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 <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
diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager.cpp b/dali-toolkit/internal/atlas-manager/atlas-manager.cpp
new file mode 100644 (file)
index 0000000..85d6cba
--- /dev/null
@@ -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 <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
diff --git a/dali-toolkit/internal/atlas-manager/atlas-manager.h b/dali-toolkit/internal/atlas-manager/atlas-manager.h
new file mode 100644 (file)
index 0000000..55612ff
--- /dev/null
@@ -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 <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
index bfa89f6..5c5591a 100644 (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
 {
 
@@ -52,6 +45,11 @@ namespace Internal
 
 namespace
 {
+  const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+}
+
+namespace
+{
 
 // Type registration
 BaseHandle Create()
index 43a600d..fdce0ed 100644 (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 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()
index e3f1495..9391d2f 100644 (file)
@@ -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 (file)
index 0000000..001281e
--- /dev/null
@@ -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 <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
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 (file)
index 0000000..c4da1ba
--- /dev/null
@@ -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 <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
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 (file)
index 0000000..9ca3773
--- /dev/null
@@ -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 <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
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 (file)
index 0000000..a90efdb
--- /dev/null
@@ -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 <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__
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 (file)
index 0000000..0ed74bd
--- /dev/null
@@ -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 <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
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 (file)
index 0000000..e259621
--- /dev/null
@@ -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 <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__
index 31ab53f..dc6ec3e 100644 (file)
@@ -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 );
     }
 
index 70e3c67..16293c6 100644 (file)
@@ -34,7 +34,7 @@ namespace Text
 /**
  * @brief A BGRA shader for rendering glyphs.
  */
-namespace BGRAShader
+namespace BgraShader
 {
 
 /**
index 74b80f1..5653ebf 100644 (file)
@@ -23,6 +23,8 @@
 #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
@@ -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;
 
index 62b9f86..df7bfa2 100644 (file)
@@ -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.
  */
index 34774ac..8e1ccdf 100755 (executable)
@@ -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 (file)
index 0000000..522a307
--- /dev/null
@@ -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__