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 );
42 AtlasManager::AtlasManager()
43 : mNewAtlasSize( DEFAULT_ATLAS_SIZE ),
44 mNewBlockSize( DEFAULT_BLOCK_SIZE ),
45 mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES )
49 AtlasManagerPtr AtlasManager::New()
51 AtlasManagerPtr internal = new AtlasManager();
55 AtlasManager::~AtlasManager()
57 for ( uint32_t i = 0; i < mAtlasList.size(); ++i )
59 delete[] mAtlasList[ i ].mStripBuffer;
63 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width,
67 Pixel::Format pixelformat )
69 // Check to see if the atlas is large enough to hold a single block even ?
70 if ( blockWidth > width || blockHeight > height )
72 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
73 width, height, blockWidth, blockHeight );
77 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
78 AtlasDescriptor atlasDescriptor;
79 atlasDescriptor.mAtlas = atlas;
80 atlasDescriptor.mWidth = width;
81 atlasDescriptor.mHeight = height;
82 atlasDescriptor.mBlockWidth = blockWidth;
83 atlasDescriptor.mBlockHeight = blockHeight;
84 atlasDescriptor.mPixelFormat = pixelformat;
85 std::stringstream materialLabel;
86 materialLabel << "Atlas Material - ";
87 materialLabel << mAtlasList.size();
88 atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
89 atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
90 atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
92 // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
93 uint32_t neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
94 atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
95 memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
97 atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
102 atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
103 SINGLE_PIXEL_PADDING,
104 blockHeight - DOUBLE_PIXEL_PADDING,
107 mAtlasList.push_back( atlasDescriptor );
108 return mAtlasList.size();
111 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
113 mAddFailPolicy = policy;
116 void AtlasManager::Add( const BufferImage& image,
117 Toolkit::AtlasManager::AtlasSlot& slot,
118 Toolkit::AtlasManager::AtlasId atlas )
120 // See if there's a slot in an atlas that matches the requirements of this image
121 // A bitmap must be sliceable into a single atlas
122 Pixel::Format pixelFormat = image.GetPixelFormat();
123 SizeType width = image.GetWidth();
124 SizeType height = image.GetHeight();
125 SizeType blockArea = 0;
126 SizeType totalBlocks = 0;
127 SizeType foundAtlas = 0;
131 AtlasSlotDescriptor desc;
133 // If there is a preferred atlas then check for room in that first
136 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
139 // Search current atlases to see if there is a good match
141 while( !foundAtlas && index < mAtlasList.size() )
143 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
147 // If we can't find a suitable atlas then check the policy to determine action
150 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
152 SizeType newAtlas = CreateAtlas( mNewAtlasSize.x, mNewAtlasSize.y, mNewBlockSize.x, mNewBlockSize.y, pixelFormat );
159 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
163 if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
165 // Haven't found an atlas for this image!!!!!!
170 // Work out where the blocks are we're going to use
171 for ( SizeType i = 0; i < blockArea; ++i )
173 // Is there currently a next free block available ?
174 if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
176 // Yes, so use this for our next block
177 SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
178 desc.mBlocksList.PushBack( selectedBlock );
180 // Any blocks going to be available after this one (adjust to store +1 )?
183 if ( selectedBlock > totalBlocks )
185 // No so start trying to use free blocks list
188 mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
192 // Our next block must be from the free list, fetch from the start of the list
193 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
194 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
198 desc.mImageWidth = width;
199 desc.mImageHeight = height;
200 desc.mAtlasId = foundAtlas + 1u;
203 // See if there's a previously freed image ID that we can assign to this new image
204 uint32_t imageId = 0;
205 for ( uint32_t i = 0; i < mImageList.size(); ++i )
207 if ( !mImageList[ i ].mCount )
215 mImageList.push_back( desc );
216 slot.mImageId = mImageList.size();
220 mImageList[ imageId - 1u ] = desc;
221 slot.mImageId = imageId;
223 slot.mAtlasId = foundAtlas + 1u;
224 UploadImage( image, desc );
227 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
230 Pixel::Format pixelFormat,
232 SizeType& totalBlocks )
234 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
236 // Check to see if there are any unused blocks in this atlas to accomodate our image
237 SizeType blocksInX = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
238 SizeType blocksInY = mAtlasList[ atlas ].mHeight / mAtlasList[ atlas ].mBlockHeight;
239 totalBlocks = blocksInX * blocksInY;
240 SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ?
241 totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u :
242 mAtlasList[ atlas ].mFreeBlocksList.Size();
244 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
246 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
247 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
250 return ( atlas + 1u );
256 void AtlasManager::CreateMesh( SizeType atlas,
258 SizeType imageHeight,
259 const Vector2& position,
260 SizeType widthInBlocks,
261 SizeType heightInBlocks,
262 Dali::MeshData& meshData,
263 AtlasSlotDescriptor& desc )
265 Dali::MeshData::Vertex vertex;
266 Dali::MeshData::VertexContainer vertices;
267 Dali::MeshData::FaceIndices faces;
268 Dali::MeshData::FaceIndex faceIndex = 0;
269 meshData.SetHasNormals( false );
270 meshData.SetHasColor( true );
271 meshData.SetHasTextureCoords( true );
273 SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth;
274 SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight;
276 float vertexBlockWidth = static_cast< float >( blockWidth );
277 float vertexBlockHeight = static_cast< float >( blockHeight );
279 SizeType width = mAtlasList[ atlas ].mWidth;
280 SizeType height = mAtlasList[ atlas ].mHeight;
282 SizeType atlasWidthInBlocks = width / blockWidth;
284 // Get the normalized size of a texel in both directions
285 // TODO when texture resizing and passing texture size via uniforms is available,
286 // we will encode pixel positions into the vertex data rather than normalized
287 // meaning that geometry needn't be changed on an atlas resize
288 float texelX = 1.0f / static_cast< float >( width );
289 float texelY = 1.0f / static_cast< float >( height );
291 // Get the normalized size of a block in texels
292 float texelBlockWidth = texelX * vertexBlockWidth;
293 float texelBlockHeight = texelY * vertexBlockHeight;
295 // Get partial block space
296 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
297 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
300 float texelEdgeWidth = vertexEdgeWidth * texelX;
301 float texelEdgeHeight = vertexEdgeHeight * texelY;
303 // Block by block create the two triangles for the quad
304 SizeType blockIndex = 0;
310 Vector2 topLeft = position;
312 for ( SizeType y = 0; y < heightInBlocks; ++y )
315 float currentX = position.x;
317 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
319 ndcHeight = texelEdgeHeight;
320 ndcVHeight = vertexEdgeHeight;
324 ndcHeight = texelBlockHeight;
325 ndcVHeight = vertexBlockHeight;
328 for ( SizeType x = 0; x < widthInBlocks; ++x )
330 SizeType block = desc.mBlocksList[ blockIndex++ ];
332 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
333 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
335 // Add on texture filtering compensation
339 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
341 ndcWidth = texelEdgeWidth;
342 ndcVWidth = vertexEdgeWidth;
346 ndcWidth = texelBlockWidth;
347 ndcVWidth = vertexBlockWidth;
351 vertex.x = topLeft.x;
352 vertex.y = topLeft.y;
357 vertices.push_back( vertex );
360 vertex.x = topLeft.x + ndcVWidth;
361 vertex.y = topLeft.y;
363 vertex.u = fBlockX + ndcWidth;
366 vertices.push_back( vertex );
369 vertex.x = topLeft.x;
370 vertex.y = topLeft.y + ndcVHeight;
373 vertex.v = fBlockY + ndcHeight;
375 vertices.push_back( vertex );
378 topLeft.x += ndcVWidth;
379 vertex.x = topLeft.x;
380 vertex.y = topLeft.y + ndcVHeight;
382 vertex.u = fBlockX + ndcWidth;
383 vertex.v = fBlockY + ndcHeight;
385 vertices.push_back( vertex );
387 // Six indices in counter clockwise winding
388 faces.push_back( faceIndex + 1u );
389 faces.push_back( faceIndex );
390 faces.push_back( faceIndex + 2u );
391 faces.push_back( faceIndex + 2u );
392 faces.push_back( faceIndex + 3u );
393 faces.push_back( faceIndex + 1u );
398 topLeft.x = currentX;
399 topLeft.y += vertexBlockHeight;
402 // If there's only one block then skip this next vertex optimisation
403 if ( widthInBlocks * heightInBlocks > 1 )
405 Dali::MeshData::VertexContainer optimizedVertices;
406 OptimizeVertices( vertices, faces, optimizedVertices );
407 meshData.SetVertices( optimizedVertices );
411 meshData.SetVertices( vertices );
414 meshData.SetFaceIndices( faces );
415 meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
416 //PrintMeshData( meshData );
419 void AtlasManager::PrintMeshData( const MeshData& meshData )
421 std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
422 std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
424 Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
425 Dali::MeshData::FaceIndices faces = meshData.GetFaces();
427 for ( SizeType v = 0; v < vertices.size(); ++v )
429 std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
430 std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
431 std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
434 std::cout << "\n Indices: ";
435 for ( SizeType i = 0; i < faces.size(); ++i )
437 std::cout << " " << faces[ i ];
439 std::cout << std::endl;
442 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
443 MeshData::FaceIndices& faces,
444 MeshData::VertexContainer& out )
446 unsigned short vertexIndex = 0;
448 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
449 for ( SizeType i = 0; i < faces.size(); ++i )
451 // Fetch a vertex, has it already been assigned?
452 bool foundVertex = false;
453 Dali::MeshData::Vertex v = in[ faces [ i ] ];
454 for ( SizeType j = 0; j < vertexIndex; ++j )
456 if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
457 v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
458 v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
460 // Yes, so store this down as the vertex to use
467 // Did we find a vertex ?
471 faces[ i ] = vertexIndex++;
477 void AtlasManager::StitchMesh( MeshData& first,
478 const MeshData& second,
482 // Would be much quicker to be able to get a non-const reference to these containers and update in situ
483 MeshData::VertexContainer v1 = first.GetVertices();
484 MeshData::VertexContainer v2 = second.GetVertices();
485 MeshData::FaceIndices f1 = first.GetFaces();
486 MeshData::FaceIndices f2 = second.GetFaces();
488 uint32_t vc1 = first.GetVertexCount();
489 uint32_t vc2 = second.GetVertexCount();
491 for ( uint32_t v = 0; v < vc2; ++v )
493 v1.push_back( v2[ v ] );
496 for ( uint32_t f = 0; f < f2.size(); ++f )
498 f1.push_back( f2[ f ] + vc1 );
503 MeshData::VertexContainer optimizedVertices;
504 OptimizeVertices( v1, f1, optimizedVertices );
505 first.SetVertices( optimizedVertices );
509 first.SetVertices( v1 );
512 first.SetFaceIndices( f1 );
514 // TODO rather than set the material to the second, check to see if there's a match and return if not
515 first.SetMaterial( second.GetMaterial() );
518 void AtlasManager::StitchMesh( const MeshData& first,
519 const MeshData& second,
523 MeshData::VertexContainer v1 = first.GetVertices();
524 MeshData::VertexContainer v2 = second.GetVertices();
525 MeshData::FaceIndices f1 = first.GetFaces();
526 MeshData::FaceIndices f2 = second.GetFaces();
528 uint32_t vc1 = first.GetVertexCount();
529 uint32_t vc2 = second.GetVertexCount();
531 MeshData::VertexContainer vertices;
533 MeshData::FaceIndices faces;
535 MeshData::Vertex vertex;
537 for ( uint32_t v = 0; v < vc1; ++v )
539 vertices.push_back( v1[ v ] );
542 for ( uint32_t v = 0; v < vc2; ++v )
544 vertices.push_back( v2[ v ] );
547 for ( uint32_t f = 0; f < f1.size(); ++f )
549 faces.push_back( f1[ f ] );
552 for ( uint32_t f = 0; f < f2.size(); ++f )
554 faces.push_back( f2[ f ] + vc1 );
559 MeshData::VertexContainer optimizedVertices;
560 OptimizeVertices( vertices, faces, optimizedVertices );
561 out.SetVertices( optimizedVertices );
565 out.SetVertices( vertices );
568 // TODO rather than set the material to the second, check to see if there's a match and return if not
569 out.SetMaterial( second.GetMaterial() );
570 out.SetFaceIndices( faces );
573 void AtlasManager::UploadImage( const BufferImage& image,
574 const AtlasSlotDescriptor& desc )
576 // Get the atlas to upload the image to
577 SizeType atlas = desc.mAtlasId - 1u;
579 // Check to see that the pixel formats are compatible
580 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
582 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
586 SizeType atlasBlockWidth = mAtlasList[ atlas ].mBlockWidth;
587 SizeType atlasBlockHeight = mAtlasList[ atlas ].mBlockHeight;
588 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
590 SizeType block = desc.mBlocksList[ 0 ];
591 SizeType blockX = block % atlasWidthInBlocks;
592 SizeType blockY = block / atlasWidthInBlocks;
593 SizeType blockOffsetX = blockX * atlasBlockWidth;
594 SizeType blockOffsetY = blockY * atlasBlockHeight;
596 SizeType width = image.GetWidth();
597 SizeType height = image.GetHeight();
599 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
600 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
601 blockOffsetX + SINGLE_PIXEL_PADDING,
602 blockOffsetY + SINGLE_PIXEL_PADDING ) )
604 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
608 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
612 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
616 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
618 blockOffsetY + SINGLE_PIXEL_PADDING ) )
620 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
624 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
626 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
628 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
630 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
635 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
637 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
638 blockOffsetX + width + SINGLE_PIXEL_PADDING,
639 blockOffsetY + SINGLE_PIXEL_PADDING ) )
641 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
646 void AtlasManager::GenerateMeshData( ImageId id,
647 const Vector2& position,
650 // Read the atlas Id to use for this image
651 SizeType imageId = id - 1u;
652 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
653 SizeType width = mImageList[ imageId ].mImageWidth;
654 SizeType height = mImageList[ imageId ].mImageHeight;
656 SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
657 if ( width % mAtlasList[ atlas ].mBlockWidth )
661 SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
662 if ( height % mAtlasList[ atlas ].mBlockHeight )
667 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
669 // Mesh created so increase the reference count
670 mImageList[ imageId ].mCount++;
673 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
676 if ( !atlas || atlas > mAtlasList.size( ) )
679 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
682 return mAtlasList[ atlas -1u ].mAtlas;
685 bool AtlasManager::Remove( ImageId id )
687 // Decrements the reference count of this image, and removes the blocks if zero.
688 SizeType imageId = id - 1u;
689 bool removed = false;
691 if ( id > mImageList.size() )
693 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
697 // If we attempt to free an image that is already freed then do nothing, other than log
698 if ( !mImageList[ imageId ].mCount )
700 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
704 if ( 1u == --mImageList[ imageId ].mCount )
706 // 'Remove the blocks' from this image and add to the atlas' freelist
708 mImageList[ imageId ].mCount = 0;
709 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
710 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
712 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
718 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
720 if ( id && id <= mImageList.size() )
722 return mImageList[ id - 1u ].mAtlasId;
730 void AtlasManager::SetNewAtlasSize( const Vector2& size,
731 const Vector2& blockSize )
733 mNewAtlasSize = size;
734 mNewBlockSize = blockSize;
737 Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
739 if ( atlas && atlas <= mAtlasList.size() )
741 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ),
742 static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) );
746 return Vector2( 0.0f, 0.0f );
750 Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
752 if ( atlas && atlas <= mAtlasList.size() )
754 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mWidth ),
755 static_cast< float >( mAtlasList[ atlas - 1u ].mHeight ) );
759 return Vector2( 0.0f, 0.0f );
763 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
765 if ( atlas && atlas <= mAtlasList.size() )
767 uint32_t index = atlas - 1u;
768 uint32_t width = mAtlasList[ index ].mWidth;
769 uint32_t height = mAtlasList[ index ].mHeight;
770 uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
771 uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
773 SizeType widthInBlocks = width / blockWidth;
774 SizeType heightInBlocks = height / blockHeight;
775 uint32_t blockCount = widthInBlocks * heightInBlocks;
777 // Check free previously unallocated blocks and any free blocks
778 blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size();
787 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
789 return mAtlasList.size();
792 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
794 if ( !atlas || atlas > mAtlasList.size( ) )
797 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
800 return mAtlasList[ atlas -1u ].mPixelFormat;
803 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
805 Toolkit::AtlasManager::AtlasMetricsEntry entry;
806 uint32_t textureMemoryUsed = 0;
807 uint32_t atlasCount = mAtlasList.size();
808 metrics.mAtlasCount = atlasCount;
809 metrics.mAtlasMetrics.Resize(0);
811 for ( uint32_t i = 0; i < atlasCount; ++i )
813 SizeType width = mAtlasList[ i ].mWidth;
814 SizeType height = mAtlasList[ i ].mHeight;
815 SizeType blockWidth = mAtlasList[ i ].mBlockWidth;
816 SizeType blockHeight = mAtlasList[ i ].mBlockHeight;
818 entry.mWidth = width;
819 entry.mHeight = height;
820 entry.mBlockWidth = blockWidth;
821 entry.mBlockHeight = blockHeight;
822 entry.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
823 uint32_t reuseBlocks = mAtlasList[ i ].mFreeBlocksList.Size();
824 entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock - reuseBlocks - 1u: entry.mTotalBlocks - reuseBlocks;
825 entry.mPixelFormat = GetPixelFormat( i + 1 );
827 metrics.mAtlasMetrics.PushBack( entry );
829 uint32_t size = width * height;
830 if ( entry.mPixelFormat == Pixel::BGRA8888 )
835 textureMemoryUsed += size;
838 metrics.mTextureMemoryUsed = textureMemoryUsed;
842 } // namespace Internal
844 } // namespace Toolkit