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 ? totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u : 0;
242 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
244 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
245 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
248 return ( atlas + 1u );
254 void AtlasManager::CreateMesh( SizeType atlas,
256 SizeType imageHeight,
257 const Vector2& position,
258 SizeType widthInBlocks,
259 SizeType heightInBlocks,
260 Dali::MeshData& meshData,
261 AtlasSlotDescriptor& desc )
263 Dali::MeshData::Vertex vertex;
264 Dali::MeshData::VertexContainer vertices;
265 Dali::MeshData::FaceIndices faces;
266 Dali::MeshData::FaceIndex faceIndex = 0;
267 meshData.SetHasNormals( false );
268 meshData.SetHasColor( true );
269 meshData.SetHasTextureCoords( true );
271 SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth;
272 SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight;
274 float vertexBlockWidth = static_cast< float >( blockWidth );
275 float vertexBlockHeight = static_cast< float >( blockHeight );
277 SizeType width = mAtlasList[ atlas ].mWidth;
278 SizeType height = mAtlasList[ atlas ].mHeight;
280 SizeType atlasWidthInBlocks = width / blockWidth;
282 // Get the normalized size of a texel in both directions
283 // TODO when texture resizing and passing texture size via uniforms is available,
284 // we will encode pixel positions into the vertex data rather than normalized
285 // meaning that geometry needn't be changed on an atlas resize
286 float texelX = 1.0f / static_cast< float >( width );
287 float texelY = 1.0f / static_cast< float >( height );
289 // Get the normalized size of a block in texels
290 float texelBlockWidth = texelX * vertexBlockWidth;
291 float texelBlockHeight = texelY * vertexBlockHeight;
293 // Get partial block space
294 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
295 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
298 float texelEdgeWidth = vertexEdgeWidth * texelX;
299 float texelEdgeHeight = vertexEdgeHeight * texelY;
301 // Block by block create the two triangles for the quad
302 SizeType blockIndex = 0;
308 Vector2 topLeft = position;
310 for ( SizeType y = 0; y < heightInBlocks; ++y )
313 float currentX = position.x;
315 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
317 ndcHeight = texelEdgeHeight;
318 ndcVHeight = vertexEdgeHeight;
322 ndcHeight = texelBlockHeight;
323 ndcVHeight = vertexBlockHeight;
326 for ( SizeType x = 0; x < widthInBlocks; ++x )
328 SizeType block = desc.mBlocksList[ blockIndex++ ];
330 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
331 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
333 // Add on texture filtering compensation
337 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
339 ndcWidth = texelEdgeWidth;
340 ndcVWidth = vertexEdgeWidth;
344 ndcWidth = texelBlockWidth;
345 ndcVWidth = vertexBlockWidth;
349 vertex.x = topLeft.x;
350 vertex.y = topLeft.y;
355 vertices.push_back( vertex );
358 vertex.x = topLeft.x + ndcVWidth;
359 vertex.y = topLeft.y;
361 vertex.u = fBlockX + ndcWidth;
364 vertices.push_back( vertex );
367 vertex.x = topLeft.x;
368 vertex.y = topLeft.y + ndcVHeight;
371 vertex.v = fBlockY + ndcHeight;
373 vertices.push_back( vertex );
376 topLeft.x += ndcVWidth;
377 vertex.x = topLeft.x;
378 vertex.y = topLeft.y + ndcVHeight;
380 vertex.u = fBlockX + ndcWidth;
381 vertex.v = fBlockY + ndcHeight;
383 vertices.push_back( vertex );
385 // Six indices in counter clockwise winding
386 faces.push_back( faceIndex + 1u );
387 faces.push_back( faceIndex );
388 faces.push_back( faceIndex + 2u );
389 faces.push_back( faceIndex + 2u );
390 faces.push_back( faceIndex + 3u );
391 faces.push_back( faceIndex + 1u );
396 topLeft.x = currentX;
397 topLeft.y += vertexBlockHeight;
400 // If there's only one block then skip this next vertex optimisation
401 if ( widthInBlocks * heightInBlocks > 1 )
403 Dali::MeshData::VertexContainer optimizedVertices;
404 OptimizeVertices( vertices, faces, optimizedVertices );
405 meshData.SetVertices( optimizedVertices );
409 meshData.SetVertices( vertices );
412 meshData.SetFaceIndices( faces );
413 meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
414 //PrintMeshData( meshData );
417 void AtlasManager::PrintMeshData( const MeshData& meshData )
419 std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
420 std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
422 Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
423 Dali::MeshData::FaceIndices faces = meshData.GetFaces();
425 for ( SizeType v = 0; v < vertices.size(); ++v )
427 std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
428 std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
429 std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
432 std::cout << "\n Indices: ";
433 for ( SizeType i = 0; i < faces.size(); ++i )
435 std::cout << " " << faces[ i ];
437 std::cout << std::endl;
440 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
441 MeshData::FaceIndices& faces,
442 MeshData::VertexContainer& out )
444 unsigned short vertexIndex = 0;
446 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
447 for ( SizeType i = 0; i < faces.size(); ++i )
449 // Fetch a vertex, has it already been assigned?
450 bool foundVertex = false;
451 Dali::MeshData::Vertex v = in[ faces [ i ] ];
452 for ( SizeType j = 0; j < vertexIndex; ++j )
454 if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
455 v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
456 v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
458 // Yes, so store this down as the vertex to use
465 // Did we find a vertex ?
469 faces[ i ] = vertexIndex++;
475 void AtlasManager::StitchMesh( MeshData& first,
476 const MeshData& second,
480 // Would be much quicker to be able to get a non-const reference to these containers and update in situ
481 MeshData::VertexContainer v1 = first.GetVertices();
482 MeshData::VertexContainer v2 = second.GetVertices();
483 MeshData::FaceIndices f1 = first.GetFaces();
484 MeshData::FaceIndices f2 = second.GetFaces();
486 uint32_t vc1 = first.GetVertexCount();
487 uint32_t vc2 = second.GetVertexCount();
489 for ( uint32_t v = 0; v < vc2; ++v )
491 v1.push_back( v2[ v ] );
494 for ( uint32_t f = 0; f < f2.size(); ++f )
496 f1.push_back( f2[ f ] + vc1 );
501 MeshData::VertexContainer optimizedVertices;
502 OptimizeVertices( v1, f1, optimizedVertices );
503 first.SetVertices( optimizedVertices );
507 first.SetVertices( v1 );
510 first.SetFaceIndices( f1 );
512 // TODO rather than set the material to the second, check to see if there's a match and return if not
513 first.SetMaterial( second.GetMaterial() );
516 void AtlasManager::StitchMesh( const MeshData& first,
517 const MeshData& second,
521 MeshData::VertexContainer v1 = first.GetVertices();
522 MeshData::VertexContainer v2 = second.GetVertices();
523 MeshData::FaceIndices f1 = first.GetFaces();
524 MeshData::FaceIndices f2 = second.GetFaces();
526 uint32_t vc1 = first.GetVertexCount();
527 uint32_t vc2 = second.GetVertexCount();
529 MeshData::VertexContainer vertices;
531 MeshData::FaceIndices faces;
533 MeshData::Vertex vertex;
535 for ( uint32_t v = 0; v < vc1; ++v )
537 vertices.push_back( v1[ v ] );
540 for ( uint32_t v = 0; v < vc2; ++v )
542 vertices.push_back( v2[ v ] );
545 for ( uint32_t f = 0; f < f1.size(); ++f )
547 faces.push_back( f1[ f ] );
550 for ( uint32_t f = 0; f < f2.size(); ++f )
552 faces.push_back( f2[ f ] + vc1 );
557 MeshData::VertexContainer optimizedVertices;
558 OptimizeVertices( vertices, faces, optimizedVertices );
559 out.SetVertices( optimizedVertices );
563 out.SetVertices( vertices );
566 // TODO rather than set the material to the second, check to see if there's a match and return if not
567 out.SetMaterial( second.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");
606 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
610 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
614 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
616 blockOffsetY + SINGLE_PIXEL_PADDING ) )
618 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
622 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
624 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
626 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
628 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
633 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
635 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
636 blockOffsetX + width + SINGLE_PIXEL_PADDING,
637 blockOffsetY + SINGLE_PIXEL_PADDING ) )
639 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
644 void AtlasManager::GenerateMeshData( ImageId id,
645 const Vector2& position,
648 // Read the atlas Id to use for this image
649 SizeType imageId = id - 1u;
650 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
651 SizeType width = mImageList[ imageId ].mImageWidth;
652 SizeType height = mImageList[ imageId ].mImageHeight;
654 SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
655 if ( width % mAtlasList[ atlas ].mBlockWidth )
659 SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
660 if ( height % mAtlasList[ atlas ].mBlockHeight )
665 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
667 // Mesh created so increase the reference count
668 mImageList[ imageId ].mCount++;
671 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
674 if ( !atlas || atlas > mAtlasList.size( ) )
677 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
680 return mAtlasList[ atlas -1u ].mAtlas;
683 bool AtlasManager::Remove( ImageId id )
685 // Decrements the reference count of this image, and removes the blocks if zero.
686 SizeType imageId = id - 1u;
687 bool removed = false;
689 if ( id > mImageList.size() )
691 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
695 // If we attempt to free an image that is already freed then do nothing, other than log
696 if ( !mImageList[ imageId ].mCount )
698 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
702 if ( 1u == --mImageList[ imageId ].mCount )
704 // 'Remove the blocks' from this image and add to the atlas' freelist
706 mImageList[ imageId ].mCount = 0;
707 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
708 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
710 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
716 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
718 if ( id && id <= mImageList.size() )
720 return mImageList[ id - 1u ].mAtlasId;
728 void AtlasManager::SetNewAtlasSize( const Vector2& size,
729 const Vector2& blockSize )
731 mNewAtlasSize = size;
732 mNewBlockSize = blockSize;
735 Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
737 if ( atlas && atlas <= mAtlasList.size() )
739 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ),
740 static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) );
744 return Vector2( 0.0f, 0.0f );
748 Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
750 if ( atlas && atlas <= mAtlasList.size() )
752 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mWidth ),
753 static_cast< float >( mAtlasList[ atlas - 1u ].mHeight ) );
757 return Vector2( 0.0f, 0.0f );
761 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
763 if ( atlas && atlas <= mAtlasList.size() )
765 uint32_t index = atlas - 1u;
766 uint32_t width = mAtlasList[ index ].mWidth;
767 uint32_t height = mAtlasList[ index ].mHeight;
768 uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
769 uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
771 SizeType widthInBlocks = width / blockWidth;
772 SizeType heightInBlocks = height / blockHeight;
773 uint32_t blockCount = widthInBlocks * heightInBlocks;
775 // Check free previously unallocated blocks and any free blocks
776 blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size();
785 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
787 return mAtlasList.size();
790 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
792 if ( !atlas || atlas > mAtlasList.size( ) )
795 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
798 return mAtlasList[ atlas -1u ].mPixelFormat;
801 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
803 Toolkit::AtlasManager::AtlasMetricsEntry entry;
804 uint32_t textureMemoryUsed = 0;
805 uint32_t atlasCount = mAtlasList.size();
806 metrics.mAtlasCount = atlasCount;
807 metrics.mAtlasMetrics.Resize(0);
809 for ( uint32_t i = 0; i < atlasCount; ++i )
811 SizeType width = mAtlasList[ i ].mWidth;
812 SizeType height = mAtlasList[ i ].mHeight;
813 SizeType blockWidth = mAtlasList[ i ].mBlockWidth;
814 SizeType blockHeight = mAtlasList[ i ].mBlockHeight;
816 entry.mWidth = width;
817 entry.mHeight = height;
818 entry.mBlockWidth = blockWidth;
819 entry.mBlockHeight = blockHeight;
820 entry.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
821 entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock : entry.mTotalBlocks - mAtlasList[ i ].mFreeBlocksList.Size();
822 entry.mPixelFormat = GetPixelFormat( i + 1 );
824 metrics.mAtlasMetrics.PushBack( entry );
826 uint32_t size = width * height;
827 if ( entry.mPixelFormat == Pixel::BGRA8888 )
832 textureMemoryUsed += size;
835 metrics.mTextureMemoryUsed = textureMemoryUsed;
839 } // namespace Internal
841 } // namespace Toolkit