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