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