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