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