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