2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
23 #include <dali/integration-api/debug.h>
36 const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
37 const Vector2 DEFAULT_BLOCK_SIZE( 32.0f, 32.0f );
38 const uint32_t SINGLE_PIXEL_PADDING( 1u );
39 const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
40 const uint32_t FILLED_PIXEL( -1 );
43 AtlasManager::AtlasManager()
44 : mNewAtlasSize( DEFAULT_ATLAS_SIZE ),
45 mNewBlockSize( DEFAULT_BLOCK_SIZE ),
46 mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
47 mFilledPixel( FILLED_PIXEL )
51 AtlasManagerPtr AtlasManager::New()
53 AtlasManagerPtr internal = new AtlasManager();
57 AtlasManager::~AtlasManager()
59 for ( uint32_t i = 0; i < mAtlasList.size(); ++i )
61 delete[] mAtlasList[ i ].mStripBuffer;
65 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width,
69 Pixel::Format pixelformat )
71 // Check to see if the atlas is large enough to hold a single block even ?
72 if ( blockWidth > width || blockHeight > height )
74 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
75 width, height, blockWidth, blockHeight );
79 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
80 AtlasDescriptor atlasDescriptor;
81 atlasDescriptor.mAtlas = atlas;
82 atlasDescriptor.mWidth = width;
83 atlasDescriptor.mHeight = height;
84 atlasDescriptor.mBlockWidth = blockWidth;
85 atlasDescriptor.mBlockHeight = blockHeight;
86 atlasDescriptor.mPixelFormat = pixelformat;
87 std::stringstream materialLabel;
88 materialLabel << "Atlas Material - ";
89 materialLabel << mAtlasList.size();
90 atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
91 atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
92 atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
94 // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
95 uint32_t neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
96 atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
97 memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
99 atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
101 SINGLE_PIXEL_PADDING,
104 atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
105 SINGLE_PIXEL_PADDING,
106 blockHeight - DOUBLE_PIXEL_PADDING,
108 atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
109 atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
110 mAtlasList.push_back( atlasDescriptor );
111 return mAtlasList.size();
114 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
116 mAddFailPolicy = policy;
119 void AtlasManager::Add( const BufferImage& image,
120 Toolkit::AtlasManager::AtlasSlot& slot,
121 Toolkit::AtlasManager::AtlasId atlas )
123 // See if there's a slot in an atlas that matches the requirements of this image
124 // A bitmap must be sliceable into a single atlas
125 Pixel::Format pixelFormat = image.GetPixelFormat();
126 SizeType width = image.GetWidth();
127 SizeType height = image.GetHeight();
128 SizeType blockArea = 0;
129 SizeType totalBlocks = 0;
130 SizeType foundAtlas = 0;
134 AtlasSlotDescriptor desc;
136 // If there is a preferred atlas then check for room in that first
139 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
142 // Search current atlases to see if there is a good match
144 while( !foundAtlas && index < mAtlasList.size() )
146 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
150 // If we can't find a suitable atlas then check the policy to determine action
153 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
155 SizeType newAtlas = CreateAtlas( mNewAtlasSize.x, mNewAtlasSize.y, mNewBlockSize.x, mNewBlockSize.y, pixelFormat );
162 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
166 if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
168 // Haven't found an atlas for this image!!!!!!
173 // Work out where the blocks are we're going to use
174 for ( SizeType i = 0; i < blockArea; ++i )
176 // Is there currently a next free block available ?
177 if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
179 // Yes, so use this for our next block
180 SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
181 desc.mBlocksList.PushBack( selectedBlock );
183 // Any blocks going to be available after this one (adjust to store +1 )?
186 if ( selectedBlock > totalBlocks )
188 // No so start trying to use free blocks list
191 mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
195 // Our next block must be from the free list, fetch from the start of the list
196 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
197 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
201 desc.mImageWidth = width;
202 desc.mImageHeight = height;
203 desc.mAtlasId = foundAtlas + 1u;
206 // See if there's a previously freed image ID that we can assign to this new image
207 uint32_t imageId = 0;
208 for ( uint32_t i = 0; i < mImageList.size(); ++i )
210 if ( !mImageList[ i ].mCount )
218 mImageList.push_back( desc );
219 slot.mImageId = mImageList.size();
223 mImageList[ imageId - 1u ] = desc;
224 slot.mImageId = imageId;
226 slot.mAtlasId = foundAtlas + 1u;
227 UploadImage( image, desc );
230 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
233 Pixel::Format pixelFormat,
235 SizeType& totalBlocks )
237 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
239 // Check to see if there are any unused blocks in this atlas to accomodate our image
240 SizeType blocksInX = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
241 SizeType blocksInY = mAtlasList[ atlas ].mHeight / mAtlasList[ atlas ].mBlockHeight;
242 totalBlocks = blocksInX * blocksInY;
243 SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ?
244 totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u :
245 mAtlasList[ atlas ].mFreeBlocksList.Size();
247 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
249 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
250 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
253 return ( atlas + 1u );
259 void AtlasManager::CreateMesh( SizeType atlas,
261 SizeType imageHeight,
262 const Vector2& position,
263 SizeType widthInBlocks,
264 SizeType heightInBlocks,
265 Dali::MeshData& meshData,
266 AtlasSlotDescriptor& desc )
268 Dali::MeshData::Vertex vertex;
269 Dali::MeshData::VertexContainer vertices;
270 Dali::MeshData::FaceIndices faces;
271 Dali::MeshData::FaceIndex faceIndex = 0;
272 meshData.SetHasNormals( false );
273 meshData.SetHasColor( true );
274 meshData.SetHasTextureCoords( true );
276 SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth;
277 SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight;
279 float vertexBlockWidth = static_cast< float >( blockWidth );
280 float vertexBlockHeight = static_cast< float >( blockHeight );
282 SizeType width = mAtlasList[ atlas ].mWidth;
283 SizeType height = mAtlasList[ atlas ].mHeight;
285 SizeType atlasWidthInBlocks = width / blockWidth;
287 // Get the normalized size of a texel in both directions
288 // TODO when texture resizing and passing texture size via uniforms is available,
289 // we will encode pixel positions into the vertex data rather than normalized
290 // meaning that geometry needn't be changed on an atlas resize
291 float texelX = 1.0f / static_cast< float >( width );
292 float texelY = 1.0f / static_cast< float >( height );
294 // Get the normalized size of a block in texels
295 float texelBlockWidth = texelX * vertexBlockWidth;
296 float texelBlockHeight = texelY * vertexBlockHeight;
298 // Get partial block space
299 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
300 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
303 float texelEdgeWidth = vertexEdgeWidth * texelX;
304 float texelEdgeHeight = vertexEdgeHeight * texelY;
306 // Block by block create the two triangles for the quad
307 SizeType blockIndex = 0;
313 Vector2 topLeft = position;
315 for ( SizeType y = 0; y < heightInBlocks; ++y )
318 float currentX = position.x;
320 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
322 ndcHeight = texelEdgeHeight;
323 ndcVHeight = vertexEdgeHeight;
327 ndcHeight = texelBlockHeight;
328 ndcVHeight = vertexBlockHeight;
331 for ( SizeType x = 0; x < widthInBlocks; ++x )
333 SizeType block = desc.mBlocksList[ blockIndex++ ];
335 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
336 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
338 // Add on texture filtering compensation
342 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
344 ndcWidth = texelEdgeWidth;
345 ndcVWidth = vertexEdgeWidth;
349 ndcWidth = texelBlockWidth;
350 ndcVWidth = vertexBlockWidth;
354 vertex.x = topLeft.x;
355 vertex.y = topLeft.y;
360 vertices.push_back( vertex );
363 vertex.x = topLeft.x + ndcVWidth;
364 vertex.y = topLeft.y;
366 vertex.u = fBlockX + ndcWidth;
369 vertices.push_back( vertex );
372 vertex.x = topLeft.x;
373 vertex.y = topLeft.y + ndcVHeight;
376 vertex.v = fBlockY + ndcHeight;
378 vertices.push_back( vertex );
381 topLeft.x += ndcVWidth;
382 vertex.x = topLeft.x;
383 vertex.y = topLeft.y + ndcVHeight;
385 vertex.u = fBlockX + ndcWidth;
386 vertex.v = fBlockY + ndcHeight;
388 vertices.push_back( vertex );
390 // Six indices in counter clockwise winding
391 faces.push_back( faceIndex + 1u );
392 faces.push_back( faceIndex );
393 faces.push_back( faceIndex + 2u );
394 faces.push_back( faceIndex + 2u );
395 faces.push_back( faceIndex + 3u );
396 faces.push_back( faceIndex + 1u );
401 topLeft.x = currentX;
402 topLeft.y += vertexBlockHeight;
405 // If there's only one block then skip this next vertex optimisation
406 if ( widthInBlocks * heightInBlocks > 1 )
408 Dali::MeshData::VertexContainer optimizedVertices;
409 OptimizeVertices( vertices, faces, optimizedVertices );
410 meshData.SetVertices( optimizedVertices );
414 meshData.SetVertices( vertices );
417 meshData.SetFaceIndices( faces );
418 meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
421 void AtlasManager::PrintMeshData( const MeshData& meshData )
423 std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
424 std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
426 Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
427 Dali::MeshData::FaceIndices faces = meshData.GetFaces();
429 for ( SizeType v = 0; v < vertices.size(); ++v )
431 std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
432 std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
433 std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
436 std::cout << "\n Indices: ";
437 for ( SizeType i = 0; i < faces.size(); ++i )
439 std::cout << " " << faces[ i ];
441 std::cout << std::endl;
444 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
445 MeshData::FaceIndices& faces,
446 MeshData::VertexContainer& out )
448 unsigned short vertexIndex = 0;
450 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
451 for ( SizeType i = 0; i < faces.size(); ++i )
453 // Fetch a vertex, has it already been assigned?
454 bool foundVertex = false;
455 Dali::MeshData::Vertex v = in[ faces [ i ] ];
456 for ( SizeType j = 0; j < vertexIndex; ++j )
458 if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
459 v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
460 v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
462 // Yes, so store this down as the vertex to use
469 // Did we find a vertex ?
473 faces[ i ] = vertexIndex++;
479 void AtlasManager::StitchMesh( MeshData& first,
480 const MeshData& second,
484 // Would be much quicker to be able to get a non-const reference to these containers and update in situ
485 MeshData::VertexContainer v1 = first.GetVertices();
486 MeshData::VertexContainer v2 = second.GetVertices();
487 MeshData::FaceIndices f1 = first.GetFaces();
488 MeshData::FaceIndices f2 = second.GetFaces();
490 uint32_t vc1 = first.GetVertexCount();
491 uint32_t vc2 = second.GetVertexCount();
493 for ( uint32_t v = 0; v < vc2; ++v )
495 v1.push_back( v2[ v ] );
498 for ( uint32_t f = 0; f < f2.size(); ++f )
500 f1.push_back( f2[ f ] + vc1 );
505 MeshData::VertexContainer optimizedVertices;
506 OptimizeVertices( v1, f1, optimizedVertices );
507 first.SetVertices( optimizedVertices );
511 first.SetVertices( v1 );
514 first.SetFaceIndices( f1 );
517 void AtlasManager::StitchMesh( const MeshData& first,
518 const MeshData& second,
522 MeshData::VertexContainer v1 = first.GetVertices();
523 MeshData::VertexContainer v2 = second.GetVertices();
524 MeshData::FaceIndices f1 = first.GetFaces();
525 MeshData::FaceIndices f2 = second.GetFaces();
527 uint32_t vc1 = first.GetVertexCount();
528 uint32_t vc2 = second.GetVertexCount();
530 MeshData::VertexContainer vertices;
532 MeshData::FaceIndices faces;
534 MeshData::Vertex vertex;
536 for ( uint32_t v = 0; v < vc1; ++v )
538 vertices.push_back( v1[ v ] );
541 for ( uint32_t v = 0; v < vc2; ++v )
543 vertices.push_back( v2[ v ] );
546 for ( uint32_t f = 0; f < f1.size(); ++f )
548 faces.push_back( f1[ f ] );
551 for ( uint32_t f = 0; f < f2.size(); ++f )
553 faces.push_back( f2[ f ] + vc1 );
558 MeshData::VertexContainer optimizedVertices;
559 OptimizeVertices( vertices, faces, optimizedVertices );
560 out.SetVertices( optimizedVertices );
564 out.SetVertices( vertices );
567 out.SetMaterial( first.GetMaterial() );
568 out.SetFaceIndices( faces );
571 void AtlasManager::UploadImage( const BufferImage& image,
572 const AtlasSlotDescriptor& desc )
574 // Get the atlas to upload the image to
575 SizeType atlas = desc.mAtlasId - 1u;
577 // Check to see that the pixel formats are compatible
578 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
580 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
584 SizeType atlasBlockWidth = mAtlasList[ atlas ].mBlockWidth;
585 SizeType atlasBlockHeight = mAtlasList[ atlas ].mBlockHeight;
586 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
588 SizeType block = desc.mBlocksList[ 0 ];
589 SizeType blockX = block % atlasWidthInBlocks;
590 SizeType blockY = block / atlasWidthInBlocks;
591 SizeType blockOffsetX = blockX * atlasBlockWidth;
592 SizeType blockOffsetY = blockY * atlasBlockHeight;
594 SizeType width = image.GetWidth();
595 SizeType height = image.GetHeight();
597 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
598 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
599 blockOffsetX + SINGLE_PIXEL_PADDING,
600 blockOffsetY + SINGLE_PIXEL_PADDING ) )
602 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
605 // If this is the first block then we need to keep the first pixel free for underline texture
610 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
614 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
618 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
620 blockOffsetY + SINGLE_PIXEL_PADDING ) )
622 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
627 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
629 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
631 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
633 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
638 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
640 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
641 blockOffsetX + width + SINGLE_PIXEL_PADDING,
642 blockOffsetY + SINGLE_PIXEL_PADDING ) )
644 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
649 void AtlasManager::GenerateMeshData( ImageId id,
650 const Vector2& position,
653 // Read the atlas Id to use for this image
654 SizeType imageId = id - 1u;
655 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
656 SizeType width = mImageList[ imageId ].mImageWidth;
657 SizeType height = mImageList[ imageId ].mImageHeight;
659 SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
660 if ( width % mAtlasList[ atlas ].mBlockWidth )
664 SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
665 if ( height % mAtlasList[ atlas ].mBlockHeight )
670 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
672 // Mesh created so increase the reference count
673 mImageList[ imageId ].mCount++;
676 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
679 if ( !atlas || atlas > mAtlasList.size( ) )
682 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
685 return mAtlasList[ atlas -1u ].mAtlas;
688 bool AtlasManager::Remove( ImageId id )
690 // Decrements the reference count of this image, and removes the blocks if zero.
691 SizeType imageId = id - 1u;
692 bool removed = false;
694 if ( id > mImageList.size() )
696 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
700 // If we attempt to free an image that is already freed then do nothing, other than log
701 if ( !mImageList[ imageId ].mCount )
703 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
707 if ( 1u == --mImageList[ imageId ].mCount )
709 // 'Remove the blocks' from this image and add to the atlas' freelist
711 mImageList[ imageId ].mCount = 0;
712 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
713 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
715 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
721 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
723 if ( id && id <= mImageList.size() )
725 return mImageList[ id - 1u ].mAtlasId;
733 void AtlasManager::SetNewAtlasSize( const Vector2& size,
734 const Vector2& blockSize )
736 mNewAtlasSize = size;
737 mNewBlockSize = blockSize;
740 Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
742 if ( atlas && atlas <= mAtlasList.size() )
744 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ),
745 static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) );
749 return Vector2::ZERO;
753 Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
755 if ( atlas && atlas <= mAtlasList.size() )
757 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mWidth ),
758 static_cast< float >( mAtlasList[ atlas - 1u ].mHeight ) );
762 return Vector2::ZERO;
766 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
768 if ( atlas && atlas <= mAtlasList.size() )
770 uint32_t index = atlas - 1u;
771 uint32_t width = mAtlasList[ index ].mWidth;
772 uint32_t height = mAtlasList[ index ].mHeight;
773 uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
774 uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
776 SizeType widthInBlocks = width / blockWidth;
777 SizeType heightInBlocks = height / blockHeight;
778 uint32_t blockCount = widthInBlocks * heightInBlocks;
780 // Check free previously unallocated blocks and any free blocks
781 blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size();
790 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
792 return mAtlasList.size();
795 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
797 if ( !atlas || atlas > mAtlasList.size( ) )
800 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
803 return mAtlasList[ atlas -1u ].mPixelFormat;
806 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
808 Toolkit::AtlasManager::AtlasMetricsEntry entry;
809 uint32_t textureMemoryUsed = 0;
810 uint32_t atlasCount = mAtlasList.size();
811 metrics.mAtlasCount = atlasCount;
812 metrics.mAtlasMetrics.Resize(0);
814 for ( uint32_t i = 0; i < atlasCount; ++i )
816 SizeType width = mAtlasList[ i ].mWidth;
817 SizeType height = mAtlasList[ i ].mHeight;
818 SizeType blockWidth = mAtlasList[ i ].mBlockWidth;
819 SizeType blockHeight = mAtlasList[ i ].mBlockHeight;
821 entry.mWidth = width;
822 entry.mHeight = height;
823 entry.mBlockWidth = blockWidth;
824 entry.mBlockHeight = blockHeight;
825 entry.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
826 uint32_t reuseBlocks = mAtlasList[ i ].mFreeBlocksList.Size();
827 entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock - reuseBlocks - 1u: entry.mTotalBlocks - reuseBlocks;
828 entry.mPixelFormat = GetPixelFormat( i + 1 );
830 metrics.mAtlasMetrics.PushBack( entry );
832 uint32_t size = width * height;
833 if ( entry.mPixelFormat == Pixel::BGRA8888 )
838 textureMemoryUsed += size;
841 metrics.mTextureMemoryUsed = textureMemoryUsed;
845 } // namespace Internal
847 } // namespace Toolkit