Text Atlas Rendering Artefact fix
[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 ? totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u : 0;
241
242     // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
243     if ( blocksFree
244          && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
245          && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
246     {
247       blockArea = 1u;
248       return ( atlas + 1u );
249     }
250   }
251   return 0;
252 }
253
254 void AtlasManager::CreateMesh( SizeType atlas,
255                                SizeType imageWidth,
256                                SizeType imageHeight,
257                                const Vector2& position,
258                                SizeType widthInBlocks,
259                                SizeType heightInBlocks,
260                                Dali::MeshData& meshData,
261                                AtlasSlotDescriptor& desc )
262 {
263   Dali::MeshData::Vertex vertex;
264   Dali::MeshData::VertexContainer vertices;
265   Dali::MeshData::FaceIndices faces;
266   Dali::MeshData::FaceIndex faceIndex = 0;
267   meshData.SetHasNormals( false );
268   meshData.SetHasColor( true );
269   meshData.SetHasTextureCoords( true );
270
271   SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth;
272   SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight;
273
274   float vertexBlockWidth = static_cast< float >( blockWidth );
275   float vertexBlockHeight = static_cast< float >( blockHeight );
276
277   SizeType width = mAtlasList[ atlas ].mWidth;
278   SizeType height = mAtlasList[ atlas ].mHeight;
279
280   SizeType atlasWidthInBlocks = width / blockWidth;
281
282   // Get the normalized size of a texel in both directions
283   // TODO when texture resizing and passing texture size via uniforms is available,
284   //      we will encode pixel positions into the vertex data rather than normalized
285   //      meaning that geometry needn't be changed on an atlas resize
286   float texelX = 1.0f / static_cast< float >( width );
287   float texelY = 1.0f / static_cast< float >( height );
288
289   // Get the normalized size of a block in texels
290   float texelBlockWidth = texelX * vertexBlockWidth;
291   float texelBlockHeight = texelY * vertexBlockHeight;
292
293   // Get partial block space
294   float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
295   float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
296
297   // And in texels
298   float texelEdgeWidth = vertexEdgeWidth * texelX;
299   float texelEdgeHeight = vertexEdgeHeight * texelY;
300
301    // Block by block create the two triangles for the quad
302   SizeType blockIndex = 0;
303   float ndcWidth;
304   float ndcHeight;
305   float ndcVWidth;
306   float ndcVHeight;
307
308   Vector2 topLeft = position;
309
310   for ( SizeType y = 0; y < heightInBlocks; ++y )
311   {
312
313     float currentX = position.x;
314
315     if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
316     {
317       ndcHeight = texelEdgeHeight;
318       ndcVHeight = vertexEdgeHeight;
319     }
320     else
321     {
322       ndcHeight = texelBlockHeight;
323       ndcVHeight = vertexBlockHeight;
324     }
325
326     for ( SizeType x = 0; x < widthInBlocks; ++x )
327     {
328       SizeType block = desc.mBlocksList[ blockIndex++ ];
329
330       float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
331       float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
332
333       // Add on texture filtering compensation
334       fBlockX += texelX;
335       fBlockY += texelY;
336
337       if (  ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
338       {
339         ndcWidth = texelEdgeWidth;
340         ndcVWidth = vertexEdgeWidth;
341       }
342       else
343       {
344         ndcWidth = texelBlockWidth;
345         ndcVWidth = vertexBlockWidth;
346       }
347
348       // Top left
349       vertex.x = topLeft.x;
350       vertex.y = topLeft.y;
351       vertex.z = 0.0f;
352       vertex.u = fBlockX;
353       vertex.v = fBlockY;
354
355       vertices.push_back( vertex );
356
357       // Top Right
358       vertex.x = topLeft.x + ndcVWidth;
359       vertex.y = topLeft.y;
360       vertex.z = 0.0f;
361       vertex.u = fBlockX + ndcWidth;
362       vertex.v = fBlockY;
363
364       vertices.push_back( vertex );
365
366       // Bottom Left
367       vertex.x = topLeft.x;
368       vertex.y = topLeft.y + ndcVHeight;
369       vertex.z = 0.0f;
370       vertex.u = fBlockX;
371       vertex.v = fBlockY + ndcHeight;
372
373       vertices.push_back( vertex );
374
375       // Bottom Right
376       topLeft.x += ndcVWidth;
377       vertex.x = topLeft.x;
378       vertex.y = topLeft.y + ndcVHeight;
379       vertex.z = 0.0f;
380       vertex.u = fBlockX + ndcWidth;
381       vertex.v = fBlockY + ndcHeight;
382
383       vertices.push_back( vertex );
384
385       // Six indices in counter clockwise winding
386       faces.push_back( faceIndex + 1u );
387       faces.push_back( faceIndex );
388       faces.push_back( faceIndex + 2u );
389       faces.push_back( faceIndex + 2u );
390       faces.push_back( faceIndex + 3u );
391       faces.push_back( faceIndex + 1u );
392       faceIndex += 4;
393     }
394
395     // Move down a row
396     topLeft.x = currentX;
397     topLeft.y += vertexBlockHeight;
398   }
399
400   // If there's only one block then skip this next vertex optimisation
401   if ( widthInBlocks * heightInBlocks > 1 )
402   {
403     Dali::MeshData::VertexContainer optimizedVertices;
404     OptimizeVertices( vertices, faces, optimizedVertices );
405     meshData.SetVertices( optimizedVertices );
406   }
407   else
408   {
409     meshData.SetVertices( vertices );
410   }
411
412   meshData.SetFaceIndices( faces );
413   meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
414   //PrintMeshData( meshData );
415 }
416
417 void AtlasManager::PrintMeshData( const MeshData& meshData )
418 {
419   std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
420   std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
421
422   Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
423   Dali::MeshData::FaceIndices faces = meshData.GetFaces();
424
425   for ( SizeType v = 0; v < vertices.size(); ++v )
426   {
427     std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
428     std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
429     std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
430   }
431
432   std::cout << "\n Indices: ";
433   for ( SizeType i = 0; i < faces.size(); ++i )
434   {
435     std::cout << " " << faces[ i ];
436   }
437   std::cout << std::endl;
438 }
439
440 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
441                                      MeshData::FaceIndices& faces,
442                                      MeshData::VertexContainer& out )
443 {
444   unsigned short vertexIndex = 0;
445
446   // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
447   for ( SizeType i = 0; i < faces.size(); ++i )
448   {
449     // Fetch a vertex, has it already been assigned?
450     bool foundVertex = false;
451     Dali::MeshData::Vertex v = in[ faces [ i ] ];
452     for ( SizeType j = 0; j < vertexIndex; ++j )
453     {
454       if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
455            v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
456            v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
457       {
458         // Yes, so store this down as the vertex to use
459         faces[ i ] = j;
460         foundVertex = true;
461         break;
462       }
463     }
464
465     // Did we find a vertex ?
466     if ( !foundVertex )
467     {
468       // Add a new vertex
469       faces[ i ] = vertexIndex++;
470       out.push_back( v );
471     }
472   }
473 }
474
475 void AtlasManager::StitchMesh( MeshData& first,
476                                const MeshData& second,
477                                bool optimize )
478 {
479
480   // Would be much quicker to be able to get a non-const reference to these containers and update in situ
481   MeshData::VertexContainer v1 = first.GetVertices();
482   MeshData::VertexContainer v2 = second.GetVertices();
483   MeshData::FaceIndices f1 = first.GetFaces();
484   MeshData::FaceIndices f2 = second.GetFaces();
485
486   uint32_t vc1 = first.GetVertexCount();
487   uint32_t vc2 = second.GetVertexCount();
488
489   for ( uint32_t v = 0; v < vc2; ++v )
490   {
491     v1.push_back( v2[ v ] );
492   }
493
494   for ( uint32_t f = 0; f < f2.size(); ++f )
495   {
496     f1.push_back( f2[ f ] + vc1 );
497   }
498
499   if ( optimize )
500   {
501     MeshData::VertexContainer optimizedVertices;
502     OptimizeVertices( v1, f1, optimizedVertices );
503     first.SetVertices( optimizedVertices );
504   }
505   else
506   {
507     first.SetVertices( v1 );
508   }
509
510   first.SetFaceIndices( f1 );
511
512   // TODO rather than set the material to the second, check to see if there's a match and return if not
513   first.SetMaterial( second.GetMaterial() );
514 }
515
516 void AtlasManager::StitchMesh( const MeshData& first,
517                                const MeshData& second,
518                                MeshData& out,
519                                bool optimize )
520 {
521   MeshData::VertexContainer v1 = first.GetVertices();
522   MeshData::VertexContainer v2 = second.GetVertices();
523   MeshData::FaceIndices f1 = first.GetFaces();
524   MeshData::FaceIndices f2 = second.GetFaces();
525
526   uint32_t vc1 = first.GetVertexCount();
527   uint32_t vc2 = second.GetVertexCount();
528
529   MeshData::VertexContainer vertices;
530
531   MeshData::FaceIndices faces;
532
533   MeshData::Vertex vertex;
534
535   for ( uint32_t v = 0; v < vc1; ++v )
536   {
537     vertices.push_back( v1[ v ] );
538   }
539
540   for ( uint32_t v = 0; v < vc2; ++v )
541   {
542     vertices.push_back( v2[ v  ] );
543   }
544
545   for ( uint32_t f = 0; f < f1.size(); ++f )
546   {
547     faces.push_back( f1[ f ] );
548   }
549
550   for ( uint32_t f = 0; f < f2.size(); ++f )
551   {
552     faces.push_back( f2[ f ] + vc1 );
553   }
554
555   if ( optimize )
556   {
557     MeshData::VertexContainer optimizedVertices;
558     OptimizeVertices( vertices, faces, optimizedVertices );
559     out.SetVertices( optimizedVertices );
560   }
561   else
562   {
563     out.SetVertices( vertices );
564   }
565
566   // TODO rather than set the material to the second, check to see if there's a match and return if not
567   out.SetMaterial( second.GetMaterial() );
568   out.SetFaceIndices( faces );
569 }
570
571 void AtlasManager::UploadImage( const BufferImage& image,
572                                 const AtlasSlotDescriptor& desc )
573 {
574   // Get the atlas to upload the image to
575   SizeType atlas = desc.mAtlasId - 1u;
576
577   // Check to see that the pixel formats are compatible
578   if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
579   {
580     DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
581     return;
582   }
583
584   SizeType atlasBlockWidth = mAtlasList[ atlas ].mBlockWidth;
585   SizeType atlasBlockHeight = mAtlasList[ atlas ].mBlockHeight;
586   SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
587
588   SizeType block = desc.mBlocksList[ 0 ];
589   SizeType blockX = block % atlasWidthInBlocks;
590   SizeType blockY = block / atlasWidthInBlocks;
591   SizeType blockOffsetX = blockX * atlasBlockWidth;
592   SizeType blockOffsetY = blockY * atlasBlockHeight;
593
594   SizeType width = image.GetWidth();
595   SizeType height = image.GetHeight();
596
597   // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
598   if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
599                                            blockOffsetX + SINGLE_PIXEL_PADDING,
600                                            blockOffsetY + SINGLE_PIXEL_PADDING ) )
601   {
602     DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
603   }
604
605   // Blit top strip
606   if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
607                                            blockOffsetX,
608                                            blockOffsetY ) )
609   {
610     DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
611   }
612
613   // Blit left strip
614   if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
615                                            blockOffsetX,
616                                            blockOffsetY + SINGLE_PIXEL_PADDING ) )
617   {
618     DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
619   }
620
621   // Blit bottom strip
622   if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
623   {
624     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
625                                              blockOffsetX,
626                                              blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
627     {
628       DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
629     }
630   }
631
632   // Blit right strip
633   if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
634   {
635     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
636                                              blockOffsetX + width + SINGLE_PIXEL_PADDING,
637                                              blockOffsetY + SINGLE_PIXEL_PADDING ) )
638     {
639       DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
640     }
641   }
642 }
643
644 void AtlasManager::GenerateMeshData( ImageId id,
645                                      const Vector2& position,
646                                      MeshData& meshData )
647 {
648   // Read the atlas Id to use for this image
649   SizeType imageId = id - 1u;
650   SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
651   SizeType width = mImageList[ imageId ].mImageWidth;
652   SizeType height = mImageList[ imageId ].mImageHeight;
653
654   SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
655   if ( width % mAtlasList[ atlas ].mBlockWidth )
656   {
657     widthInBlocks++;
658   }
659   SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
660   if ( height % mAtlasList[ atlas ].mBlockHeight )
661   {
662     heightInBlocks++;
663   }
664
665   CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
666
667   // Mesh created so increase the reference count
668   mImageList[ imageId ].mCount++;
669 }
670
671 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
672 {
673   Dali::Atlas null;
674   if ( !atlas || atlas > mAtlasList.size( ) )
675   {
676
677     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
678     return null;
679   }
680   return mAtlasList[ atlas -1u ].mAtlas;
681 }
682
683 bool AtlasManager::Remove( ImageId id )
684 {
685   // Decrements the reference count of this image, and removes the blocks if zero.
686   SizeType imageId = id - 1u;
687   bool removed = false;
688
689   if ( id > mImageList.size() )
690      {
691     DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
692     return false;
693   }
694
695   // If we attempt to free an image that is already freed then do nothing, other than log
696   if ( !mImageList[ imageId ].mCount )
697   {
698     DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
699     return false;
700   }
701
702   if ( 1u == --mImageList[ imageId ].mCount )
703   {
704     // 'Remove the blocks' from this image and add to the atlas' freelist
705     removed = true;
706     mImageList[ imageId ].mCount = 0;
707     SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
708     for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
709     {
710       mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
711     }
712   }
713   return removed;
714 }
715
716 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
717 {
718   if ( id && id <= mImageList.size() )
719   {
720     return mImageList[ id - 1u ].mAtlasId;
721   }
722   else
723   {
724     return 0;
725   }
726 }
727
728 void AtlasManager::SetNewAtlasSize( const Vector2& size,
729                                     const Vector2& blockSize )
730 {
731   mNewAtlasSize = size;
732   mNewBlockSize = blockSize;
733 }
734
735 Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
736 {
737   if ( atlas && atlas <= mAtlasList.size() )
738   {
739   return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ),
740                   static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) );
741   }
742   else
743   {
744     return Vector2( 0.0f, 0.0f );
745   }
746 }
747
748 Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
749 {
750   if ( atlas && atlas <= mAtlasList.size() )
751   {
752     return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mWidth ),
753                     static_cast< float >( mAtlasList[ atlas - 1u ].mHeight ) );
754   }
755   else
756   {
757     return Vector2( 0.0f, 0.0f );
758   }
759 }
760
761 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
762 {
763   if ( atlas && atlas <= mAtlasList.size() )
764   {
765     uint32_t index = atlas - 1u;
766     uint32_t width = mAtlasList[ index ].mWidth;
767     uint32_t height = mAtlasList[ index ].mHeight;
768     uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
769     uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
770
771     SizeType widthInBlocks = width / blockWidth;
772     SizeType heightInBlocks = height / blockHeight;
773     uint32_t blockCount = widthInBlocks * heightInBlocks;
774
775     // Check free previously unallocated blocks and any free blocks
776     blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size();
777     return blockCount;
778   }
779   else
780   {
781     return 0;
782   }
783 }
784
785 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
786 {
787   return mAtlasList.size();
788 }
789
790 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
791 {
792   if ( !atlas || atlas > mAtlasList.size( ) )
793   {
794
795     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
796     return Pixel::L8;
797   }
798   return mAtlasList[ atlas -1u ].mPixelFormat;
799 }
800
801 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
802 {
803   Toolkit::AtlasManager::AtlasMetricsEntry entry;
804   uint32_t textureMemoryUsed = 0;
805   uint32_t atlasCount = mAtlasList.size();
806   metrics.mAtlasCount = atlasCount;
807   metrics.mAtlasMetrics.Resize(0);
808
809   for ( uint32_t i = 0; i < atlasCount; ++i )
810   {
811     SizeType width = mAtlasList[ i ].mWidth;
812     SizeType height = mAtlasList[ i ].mHeight;
813     SizeType blockWidth = mAtlasList[ i ].mBlockWidth;
814     SizeType blockHeight = mAtlasList[ i ].mBlockHeight;
815
816     entry.mWidth = width;
817     entry.mHeight = height;
818     entry.mBlockWidth = blockWidth;
819     entry.mBlockHeight = blockHeight;
820     entry.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
821     entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock : entry.mTotalBlocks - mAtlasList[ i ].mFreeBlocksList.Size();
822     entry.mPixelFormat = GetPixelFormat( i + 1 );
823
824       metrics.mAtlasMetrics.PushBack( entry );
825
826     uint32_t size = width * height;
827     if ( entry.mPixelFormat == Pixel::BGRA8888 )
828     {
829       size <<= 2;
830     }
831
832     textureMemoryUsed += size;
833
834   }
835   metrics.mTextureMemoryUsed = textureMemoryUsed;
836 }
837
838
839 } // namespace Internal
840
841 } // namespace Toolkit
842
843 } // namespace Dali
844
845