Merge "Update contents of programming guide" into tizen
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / atlas-manager / atlas-manager-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // CLASS HEADER
18 #include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
19
20 // EXTERNAL INCLUDE
21 #include <iostream>
22 #include <string.h>
23 #include <dali/integration-api/debug.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 namespace Internal
32 {
33
34 namespace
35 {
36   const uint32_t DEFAULT_ATLAS_WIDTH( 512u );
37   const uint32_t DEFAULT_ATLAS_HEIGHT( 512u );
38   const uint32_t DEFAULT_BLOCK_WIDTH( 16u );
39   const uint32_t DEFAULT_BLOCK_HEIGHT( 16u );
40   const uint32_t SINGLE_PIXEL_PADDING( 1u );
41   const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
42   const uint32_t FILLED_PIXEL( -1 );
43   Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
44 }
45
46 AtlasManager::AtlasManager()
47 : mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
48   mFilledPixel( FILLED_PIXEL )
49 {
50   mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
51   mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
52   mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
53   mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
54 }
55
56 AtlasManagerPtr AtlasManager::New()
57 {
58   AtlasManagerPtr internal = new AtlasManager();
59   return internal;
60 }
61
62 AtlasManager::~AtlasManager()
63 {
64   for ( uint32_t i = 0; i < mAtlasList.size(); ++i )
65   {
66     delete[] mAtlasList[ i ].mStripBuffer;
67   }
68 }
69
70 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
71 {
72   SizeType width = size.mWidth;
73   SizeType height = size.mHeight;
74   SizeType blockWidth = size.mBlockWidth;
75   SizeType blockHeight = size.mBlockHeight;
76
77   // Check to see if the atlas is large enough to hold a single block even ?
78   if ( blockWidth > width || blockHeight > height )
79   {
80     DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
81                     width, height, blockWidth, blockHeight );
82     return 0;
83   }
84
85   Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
86   AtlasDescriptor atlasDescriptor;
87   atlasDescriptor.mAtlas = atlas;
88   atlasDescriptor.mSize = size;
89   atlasDescriptor.mPixelFormat = pixelformat;
90   std::stringstream materialLabel;
91   materialLabel << "Atlas Material - ";
92   materialLabel << mAtlasList.size();
93   atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
94   atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
95   atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
96
97   // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
98   uint32_t neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
99   atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
100   memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
101
102   atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
103                                                        blockWidth,
104                                                        SINGLE_PIXEL_PADDING,
105                                                        pixelformat );
106
107   atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
108                                                      SINGLE_PIXEL_PADDING,
109                                                      blockHeight - DOUBLE_PIXEL_PADDING,
110                                                      pixelformat );
111   atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
112   atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
113   mAtlasList.push_back( atlasDescriptor );
114   return mAtlasList.size();
115 }
116
117 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
118 {
119   mAddFailPolicy = policy;
120 }
121
122 void AtlasManager::Add( const BufferImage& image,
123                         Toolkit::AtlasManager::AtlasSlot& slot,
124                         Toolkit::AtlasManager::AtlasId atlas )
125 {
126   // See if there's a slot in an atlas that matches the requirements of this image
127   // A bitmap must be sliceable into a single atlas
128   Pixel::Format pixelFormat = image.GetPixelFormat();
129   SizeType width = image.GetWidth();
130   SizeType height = image.GetHeight();
131   SizeType blockArea = 0;
132   SizeType totalBlocks = 0;
133   SizeType foundAtlas = 0;
134   SizeType index = 0;
135   slot.mImageId = 0;
136
137   AtlasSlotDescriptor desc;
138
139   // If there is a preferred atlas then check for room in that first
140   if ( atlas-- )
141   {
142     foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
143   }
144
145   // Search current atlases to see if there is a good match
146
147   while( !foundAtlas && index < mAtlasList.size() )
148   {
149     foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
150     ++index;
151   }
152
153   // If we can't find a suitable atlas then check the policy to determine action
154   if ( !foundAtlas-- )
155   {
156     if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
157     {
158       SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
159       if ( !newAtlas-- )
160       {
161         return;
162       }
163       else
164       {
165         foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
166       }
167     }
168
169     if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
170     {
171       // Haven't found an atlas for this image!!!!!!
172           return;
173     }
174   }
175
176   // Work out where the blocks are we're going to use
177   for ( SizeType i = 0; i < blockArea; ++i )
178   {
179     // Is there currently a next free block available ?
180     if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
181     {
182       // Yes, so use this for our next block
183       SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
184       desc.mBlocksList.PushBack( selectedBlock );
185
186       // Any blocks going to be available after this one (adjust to store +1 )?
187       selectedBlock++;
188       selectedBlock++;
189       if ( selectedBlock > totalBlocks )
190       {
191         // No so start trying to use free blocks list
192         selectedBlock = 0;
193       }
194       mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
195     }
196     else
197     {
198       // Our next block must be from the free list, fetch from the start of the list
199       desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
200       mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
201     }
202   }
203
204   desc.mImageWidth = width;
205   desc.mImageHeight = height;
206   desc.mAtlasId = foundAtlas + 1u;
207   desc.mCount = 1u;
208
209   // See if there's a previously freed image ID that we can assign to this new image
210   uint32_t imageId = 0;
211   for ( uint32_t i = 0; i < mImageList.size(); ++i )
212   {
213     if ( !mImageList[ i ].mCount )
214     {
215       imageId = i + 1u;
216       break;
217     }
218   }
219   if ( !imageId )
220   {
221     mImageList.push_back( desc );
222     slot.mImageId = mImageList.size();
223   }
224   else
225   {
226     mImageList[ imageId - 1u ] = desc;
227     slot.mImageId = imageId;
228   }
229   slot.mAtlasId = foundAtlas + 1u;
230   UploadImage( image, desc );
231 }
232
233 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
234                                                  SizeType width,
235                                                  SizeType height,
236                                                  Pixel::Format pixelFormat,
237                                                  SizeType& blockArea,
238                                                  SizeType& totalBlocks )
239 {
240   if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
241   {
242     // Check to see if there are any unused blocks in this atlas to accomodate our image
243     SizeType blocksInX = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
244     SizeType blocksInY = mAtlasList[ atlas ].mSize.mHeight / mAtlasList[ atlas ].mSize.mBlockHeight;
245     totalBlocks = blocksInX * blocksInY;
246     SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ?
247                           totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u :
248                           mAtlasList[ atlas ].mFreeBlocksList.Size();
249
250     // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
251     if ( blocksFree
252          && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
253          && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
254     {
255       blockArea = 1u;
256       return ( atlas + 1u );
257     }
258   }
259   return 0;
260 }
261
262 void AtlasManager::CreateMesh( SizeType atlas,
263                                SizeType imageWidth,
264                                SizeType imageHeight,
265                                const Vector2& position,
266                                SizeType widthInBlocks,
267                                SizeType heightInBlocks,
268                                Dali::MeshData& meshData,
269                                AtlasSlotDescriptor& desc )
270 {
271   Dali::MeshData::Vertex vertex;
272   Dali::MeshData::VertexContainer vertices;
273   Dali::MeshData::FaceIndices faces;
274   Dali::MeshData::FaceIndex faceIndex = 0;
275   meshData.SetHasNormals( false );
276   meshData.SetHasColor( true );
277   meshData.SetHasTextureCoords( true );
278
279   SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
280   SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
281
282   float vertexBlockWidth = static_cast< float >( blockWidth );
283   float vertexBlockHeight = static_cast< float >( blockHeight );
284
285   SizeType width = mAtlasList[ atlas ].mSize.mWidth;
286   SizeType height = mAtlasList[ atlas ].mSize.mHeight;
287
288   SizeType atlasWidthInBlocks = width / blockWidth;
289
290   // Get the normalized size of a texel in both directions
291   // TODO when texture resizing and passing texture size via uniforms is available,
292   //      we will encode pixel positions into the vertex data rather than normalized
293   //      meaning that geometry needn't be changed on an atlas resize
294   float texelX = 1.0f / static_cast< float >( width );
295   float texelY = 1.0f / static_cast< float >( height );
296
297   // Get the normalized size of a block in texels
298   float texelBlockWidth = texelX * vertexBlockWidth;
299   float texelBlockHeight = texelY * vertexBlockHeight;
300
301   // Get partial block space
302   float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
303   float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
304
305   // And in texels
306   float texelEdgeWidth = vertexEdgeWidth * texelX;
307   float texelEdgeHeight = vertexEdgeHeight * texelY;
308
309    // Block by block create the two triangles for the quad
310   SizeType blockIndex = 0;
311   float ndcWidth;
312   float ndcHeight;
313   float ndcVWidth;
314   float ndcVHeight;
315
316   Vector2 topLeft = position;
317
318   for ( SizeType y = 0; y < heightInBlocks; ++y )
319   {
320
321     float currentX = position.x;
322
323     if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
324     {
325       ndcHeight = texelEdgeHeight;
326       ndcVHeight = vertexEdgeHeight;
327     }
328     else
329     {
330       ndcHeight = texelBlockHeight;
331       ndcVHeight = vertexBlockHeight;
332     }
333
334     for ( SizeType x = 0; x < widthInBlocks; ++x )
335     {
336       SizeType block = desc.mBlocksList[ blockIndex++ ];
337
338       float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
339       float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
340
341       // Add on texture filtering compensation
342       fBlockX += texelX;
343       fBlockY += texelY;
344
345       if (  ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
346       {
347         ndcWidth = texelEdgeWidth;
348         ndcVWidth = vertexEdgeWidth;
349       }
350       else
351       {
352         ndcWidth = texelBlockWidth;
353         ndcVWidth = vertexBlockWidth;
354       }
355
356       // Top left
357       vertex.x = topLeft.x;
358       vertex.y = topLeft.y;
359       vertex.z = 0.0f;
360       vertex.u = fBlockX;
361       vertex.v = fBlockY;
362
363       vertices.push_back( vertex );
364
365       // Top Right
366       vertex.x = topLeft.x + ndcVWidth;
367       vertex.y = topLeft.y;
368       vertex.z = 0.0f;
369       vertex.u = fBlockX + ndcWidth;
370       vertex.v = fBlockY;
371
372       vertices.push_back( vertex );
373
374       // Bottom Left
375       vertex.x = topLeft.x;
376       vertex.y = topLeft.y + ndcVHeight;
377       vertex.z = 0.0f;
378       vertex.u = fBlockX;
379       vertex.v = fBlockY + ndcHeight;
380
381       vertices.push_back( vertex );
382
383       // Bottom Right
384       topLeft.x += ndcVWidth;
385       vertex.x = topLeft.x;
386       vertex.y = topLeft.y + ndcVHeight;
387       vertex.z = 0.0f;
388       vertex.u = fBlockX + ndcWidth;
389       vertex.v = fBlockY + ndcHeight;
390
391       vertices.push_back( vertex );
392
393       // Six indices in counter clockwise winding
394       faces.push_back( faceIndex + 1u );
395       faces.push_back( faceIndex );
396       faces.push_back( faceIndex + 2u );
397       faces.push_back( faceIndex + 2u );
398       faces.push_back( faceIndex + 3u );
399       faces.push_back( faceIndex + 1u );
400       faceIndex += 4;
401     }
402
403     // Move down a row
404     topLeft.x = currentX;
405     topLeft.y += vertexBlockHeight;
406   }
407
408   // If there's only one block then skip this next vertex optimisation
409   if ( widthInBlocks * heightInBlocks > 1 )
410   {
411     Dali::MeshData::VertexContainer optimizedVertices;
412     OptimizeVertices( vertices, faces, optimizedVertices );
413     meshData.SetVertices( optimizedVertices );
414   }
415   else
416   {
417     meshData.SetVertices( vertices );
418   }
419
420   meshData.SetFaceIndices( faces );
421   meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
422 }
423
424 void AtlasManager::PrintMeshData( const MeshData& meshData )
425 {
426   std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
427   std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
428
429   Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
430   Dali::MeshData::FaceIndices faces = meshData.GetFaces();
431
432   for ( SizeType v = 0; v < vertices.size(); ++v )
433   {
434     std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
435     std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
436     std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
437   }
438
439   std::cout << "\n Indices: ";
440   for ( SizeType i = 0; i < faces.size(); ++i )
441   {
442     std::cout << " " << faces[ i ];
443   }
444   std::cout << std::endl;
445 }
446
447 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
448                                      MeshData::FaceIndices& faces,
449                                      MeshData::VertexContainer& out )
450 {
451   unsigned short vertexIndex = 0;
452
453   // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
454   for ( SizeType i = 0; i < faces.size(); ++i )
455   {
456     // Fetch a vertex, has it already been assigned?
457     bool foundVertex = false;
458     Dali::MeshData::Vertex v = in[ faces [ i ] ];
459     for ( SizeType j = 0; j < vertexIndex; ++j )
460     {
461       if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
462            v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
463            v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
464       {
465         // Yes, so store this down as the vertex to use
466         faces[ i ] = j;
467         foundVertex = true;
468         break;
469       }
470     }
471
472     // Did we find a vertex ?
473     if ( !foundVertex )
474     {
475       // Add a new vertex
476       faces[ i ] = vertexIndex++;
477       out.push_back( v );
478     }
479   }
480 }
481
482 void AtlasManager::StitchMesh( MeshData& first,
483                                const MeshData& second,
484                                bool optimize )
485 {
486
487   // Would be much quicker to be able to get a non-const reference to these containers and update in situ
488   MeshData::VertexContainer v1 = first.GetVertices();
489   MeshData::VertexContainer v2 = second.GetVertices();
490   MeshData::FaceIndices f1 = first.GetFaces();
491   MeshData::FaceIndices f2 = second.GetFaces();
492
493   uint32_t vc1 = first.GetVertexCount();
494   uint32_t vc2 = second.GetVertexCount();
495
496   for ( uint32_t v = 0; v < vc2; ++v )
497   {
498     v1.push_back( v2[ v ] );
499   }
500
501   for ( uint32_t f = 0; f < f2.size(); ++f )
502   {
503     f1.push_back( f2[ f ] + vc1 );
504   }
505
506   if ( optimize )
507   {
508     MeshData::VertexContainer optimizedVertices;
509     OptimizeVertices( v1, f1, optimizedVertices );
510     first.SetVertices( optimizedVertices );
511   }
512   else
513   {
514     first.SetVertices( v1 );
515   }
516
517   first.SetFaceIndices( f1 );
518 }
519
520 void AtlasManager::StitchMesh( const MeshData& first,
521                                const MeshData& second,
522                                MeshData& out,
523                                bool optimize )
524 {
525   MeshData::VertexContainer v1 = first.GetVertices();
526   MeshData::VertexContainer v2 = second.GetVertices();
527   MeshData::FaceIndices f1 = first.GetFaces();
528   MeshData::FaceIndices f2 = second.GetFaces();
529
530   uint32_t vc1 = first.GetVertexCount();
531   uint32_t vc2 = second.GetVertexCount();
532
533   MeshData::VertexContainer vertices;
534
535   MeshData::FaceIndices faces;
536
537   MeshData::Vertex vertex;
538
539   for ( uint32_t v = 0; v < vc1; ++v )
540   {
541     vertices.push_back( v1[ v ] );
542   }
543
544   for ( uint32_t v = 0; v < vc2; ++v )
545   {
546     vertices.push_back( v2[ v  ] );
547   }
548
549   for ( uint32_t f = 0; f < f1.size(); ++f )
550   {
551     faces.push_back( f1[ f ] );
552   }
553
554   for ( uint32_t f = 0; f < f2.size(); ++f )
555   {
556     faces.push_back( f2[ f ] + vc1 );
557   }
558
559   if ( optimize )
560   {
561     MeshData::VertexContainer optimizedVertices;
562     OptimizeVertices( vertices, faces, optimizedVertices );
563     out.SetVertices( optimizedVertices );
564   }
565   else
566   {
567     out.SetVertices( vertices );
568   }
569
570   out.SetMaterial( first.GetMaterial() );
571   out.SetFaceIndices( faces );
572 }
573
574 void AtlasManager::UploadImage( const BufferImage& image,
575                                 const AtlasSlotDescriptor& desc )
576 {
577   // Get the atlas to upload the image to
578   SizeType atlas = desc.mAtlasId - 1u;
579
580   // Check to see that the pixel formats are compatible
581   if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
582   {
583     DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
584     return;
585   }
586
587   SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
588   SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
589   SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
590
591   SizeType block = desc.mBlocksList[ 0 ];
592   SizeType blockX = block % atlasWidthInBlocks;
593   SizeType blockY = block / atlasWidthInBlocks;
594   SizeType blockOffsetX = blockX * atlasBlockWidth;
595   SizeType blockOffsetY = blockY * atlasBlockHeight;
596
597   SizeType width = image.GetWidth();
598   SizeType height = image.GetHeight();
599
600   // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
601   if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
602                                            blockOffsetX + SINGLE_PIXEL_PADDING,
603                                            blockOffsetY + SINGLE_PIXEL_PADDING ) )
604   {
605     DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
606   }
607
608   // If this is the first block then we need to keep the first pixel free for underline texture
609   if ( block )
610   {
611
612     // Blit top strip
613     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
614                                              blockOffsetX,
615                                              blockOffsetY ) )
616     {
617       DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
618     }
619
620     // Blit left strip
621     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
622                                              blockOffsetX,
623                                              blockOffsetY + SINGLE_PIXEL_PADDING ) )
624     {
625       DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
626     }
627   }
628
629   // Blit bottom strip
630   if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
631   {
632     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
633                                              blockOffsetX,
634                                              blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
635     {
636       DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
637     }
638   }
639
640   // Blit right strip
641   if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
642   {
643     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
644                                              blockOffsetX + width + SINGLE_PIXEL_PADDING,
645                                              blockOffsetY + SINGLE_PIXEL_PADDING ) )
646     {
647       DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
648     }
649   }
650 }
651
652 void AtlasManager::GenerateMeshData( ImageId id,
653                                      const Vector2& position,
654                                      MeshData& meshData )
655 {
656   // Read the atlas Id to use for this image
657   SizeType imageId = id - 1u;
658   SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
659   SizeType width = mImageList[ imageId ].mImageWidth;
660   SizeType height = mImageList[ imageId ].mImageHeight;
661
662   SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
663   if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
664   {
665     widthInBlocks++;
666   }
667   SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
668   if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
669   {
670     heightInBlocks++;
671   }
672
673   CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
674
675   // Mesh created so increase the reference count
676   mImageList[ imageId ].mCount++;
677 }
678
679 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
680 {
681   Dali::Atlas null;
682   if ( !atlas || atlas > mAtlasList.size( ) )
683   {
684
685     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
686     return null;
687   }
688   return mAtlasList[ atlas -1u ].mAtlas;
689 }
690
691 bool AtlasManager::Remove( ImageId id )
692 {
693   // Decrements the reference count of this image, and removes the blocks if zero.
694   SizeType imageId = id - 1u;
695   bool removed = false;
696
697   if ( id > mImageList.size() )
698      {
699     DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
700     return false;
701   }
702
703   // If we attempt to free an image that is already freed then do nothing, other than log
704   if ( !mImageList[ imageId ].mCount )
705   {
706     DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
707     return false;
708   }
709
710   if ( 2u > --mImageList[ imageId ].mCount )
711   {
712     // 'Remove the blocks' from this image and add to the atlas' freelist
713     removed = true;
714     mImageList[ imageId ].mCount = 0;
715     SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
716     for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
717     {
718       mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
719     }
720   }
721   return removed;
722 }
723
724 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
725 {
726   if ( id && id <= mImageList.size() )
727   {
728     return mImageList[ id - 1u ].mAtlasId;
729   }
730   else
731   {
732     return 0;
733   }
734 }
735
736 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
737 {
738   mNewAtlasSize = size;
739   mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
740   mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
741 }
742
743 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
744 {
745   if ( atlas && atlas-- <= mAtlasList.size() )
746   {
747     return mAtlasList[ atlas ].mSize;
748   }
749   return EMPTY_SIZE;
750 }
751
752 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
753 {
754   if ( atlas && atlas <= mAtlasList.size() )
755   {
756     uint32_t index = atlas - 1u;
757     uint32_t width = mAtlasList[ index ].mSize.mWidth;
758     uint32_t height = mAtlasList[ index ].mSize.mHeight;
759     uint32_t blockWidth = mAtlasList[ index ].mSize.mBlockWidth;
760     uint32_t blockHeight = mAtlasList[ index ].mSize.mBlockHeight;
761
762     SizeType widthInBlocks = width / blockWidth;
763     SizeType heightInBlocks = height / blockHeight;
764     uint32_t blockCount = widthInBlocks * heightInBlocks;
765
766     // Check free previously unallocated blocks and any free blocks
767     if ( mAtlasList[ index ].mNextFreeBlock )
768     {
769       blockCount -= mAtlasList[ index ].mNextFreeBlock -1u - mAtlasList[ index ].mFreeBlocksList.Size();
770     }
771     else
772     {
773       blockCount = mAtlasList[ index ].mFreeBlocksList.Size();
774     }
775     return blockCount;
776   }
777   else
778   {
779     return 0;
780   }
781 }
782
783 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
784 {
785   return mAtlasList.size();
786 }
787
788 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
789 {
790   if ( !atlas || atlas > mAtlasList.size( ) )
791   {
792
793     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
794     return Pixel::L8;
795   }
796   return mAtlasList[ atlas -1u ].mPixelFormat;
797 }
798
799 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
800 {
801   Toolkit::AtlasManager::AtlasMetricsEntry entry;
802   uint32_t textureMemoryUsed = 0;
803   uint32_t atlasCount = mAtlasList.size();
804   metrics.mAtlasCount = atlasCount;
805   metrics.mAtlasMetrics.Resize(0);
806
807   for ( uint32_t i = 0; i < atlasCount; ++i )
808   {
809     entry.mSize = mAtlasList[ i ].mSize;
810     entry.mTotalBlocks = ( entry.mSize.mWidth / entry.mSize.mBlockWidth ) * ( entry.mSize.mHeight / entry.mSize.mBlockHeight );
811     uint32_t reuseBlocks = mAtlasList[ i ].mFreeBlocksList.Size();
812     entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock - reuseBlocks - 1u: entry.mTotalBlocks - reuseBlocks;
813     entry.mPixelFormat = GetPixelFormat( i + 1 );
814
815       metrics.mAtlasMetrics.PushBack( entry );
816
817     uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
818     if ( entry.mPixelFormat == Pixel::BGRA8888 )
819     {
820       size <<= 2;
821     }
822
823     textureMemoryUsed += size;
824
825   }
826   metrics.mTextureMemoryUsed = textureMemoryUsed;
827 }
828
829
830 } // namespace Internal
831
832 } // namespace Toolkit
833
834 } // namespace Dali
835
836