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