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