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