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 PIXEL_PADDING( 2u );
41 AtlasManager::AtlasManager()
42 : mNewAtlasSize( DEFAULT_ATLAS_SIZE ),
43 mNewBlockSize( DEFAULT_BLOCK_SIZE ),
44 mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
50 AtlasManagerPtr AtlasManager::New()
52 AtlasManagerPtr internal = new AtlasManager();
56 AtlasManager::~AtlasManager()
61 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width,
65 Pixel::Format pixelformat )
67 // Check to see if the atlas is large enough to hold a single block even ?
68 if ( blockWidth > width || blockHeight > height )
70 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
71 width, height, blockWidth, blockHeight );
75 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
76 AtlasDescriptor atlasDescriptor;
77 atlasDescriptor.mAtlas = atlas;
78 atlasDescriptor.mWidth = width;
79 atlasDescriptor.mHeight = height;
80 atlasDescriptor.mBlockWidth = blockWidth;
81 atlasDescriptor.mBlockHeight = blockHeight;
82 atlasDescriptor.mPixelFormat = pixelformat;
83 std::stringstream materialLabel;
84 materialLabel << "Atlas Material - ";
85 materialLabel << mAtlasList.size();
86 atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
87 atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
88 atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
90 // What size do we need for this atlas' edge buffer ( assume RGBA pixel format )?
91 uint32_t neededEdgeSize = ( blockWidth > blockHeight ? blockWidth : blockHeight ) << 2;
93 // Is the current edge buffer large enough?
94 if ( neededEdgeSize > mEdgeBufferSize )
97 mEdgeBuffer = new PixelBuffer[ neededEdgeSize ];
98 memset( mEdgeBuffer, 0, neededEdgeSize );
99 mEdgeBufferSize = neededEdgeSize;
102 atlasDescriptor.mEdgeX = BufferImage::New( mEdgeBuffer, blockWidth, PIXEL_PADDING, pixelformat );
103 atlasDescriptor.mEdgeY = BufferImage::New( mEdgeBuffer, PIXEL_PADDING, blockHeight, pixelformat );
105 mAtlasList.push_back( atlasDescriptor );
106 return mAtlasList.size();
109 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
111 mAddFailPolicy = policy;
114 void AtlasManager::Add( const BufferImage& image,
115 Toolkit::AtlasManager::AtlasSlot& slot,
116 Toolkit::AtlasManager::AtlasId atlas )
118 // See if there's a slot in an atlas that matches the requirements of this image
119 // A bitmap must be sliceable into a single atlas
120 Pixel::Format pixelFormat = image.GetPixelFormat();
121 SizeType width = image.GetWidth();
122 SizeType height = image.GetHeight();
123 SizeType blockArea = 0;
124 SizeType totalBlocks = 0;
125 SizeType foundAtlas = 0;
129 AtlasSlotDescriptor desc;
131 // If there is a preferred atlas then check for room in that first
134 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
137 // Search current atlases to see if there is a good match
139 while( !foundAtlas && index < mAtlasList.size() )
141 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
145 // If we can't find a suitable atlas then check the policy to determine action
148 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
150 SizeType newAtlas = CreateAtlas( mNewAtlasSize.x, mNewAtlasSize.y, mNewBlockSize.x, mNewBlockSize.y, pixelFormat );
157 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
161 if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
163 // Haven't found an atlas for this image!!!!!!
168 // Work out where the blocks are we're going to use
169 for ( SizeType i = 0; i < blockArea; ++i )
171 // Is there currently a next free block available ?
172 if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
174 // Yes, so use this for our next block
175 SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
176 desc.mBlocksList.PushBack( selectedBlock );
178 // Any blocks going to be available after this one (adjust to store +1 )?
181 if ( selectedBlock > totalBlocks )
183 // No so start trying to use free blocks list
186 mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
190 // Our next block must be from the free list, fetch from the start of the list
191 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
192 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
196 desc.mImageWidth = width;
197 desc.mImageHeight = height;
198 desc.mAtlasId = foundAtlas + 1u;
201 // See if there's a previously freed image ID that we can assign to this new image
202 uint32_t imageId = 0;
203 for ( uint32_t i = 0; i < mImageList.size(); ++i )
205 if ( !mImageList[ i ].mCount )
213 mImageList.push_back( desc );
214 slot.mImageId = mImageList.size();
218 mImageList[ imageId - 1u ] = desc;
219 slot.mImageId = imageId;
221 slot.mAtlasId = foundAtlas + 1u;
222 UploadImage( image, desc );
225 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
228 Pixel::Format pixelFormat,
230 SizeType& totalBlocks )
232 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
234 // Check to see if there are any unused blocks in this atlas to accomodate our image
235 SizeType blocksInX = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
236 SizeType blocksInY = mAtlasList[ atlas ].mHeight / mAtlasList[ atlas ].mBlockHeight;
237 totalBlocks = blocksInX * blocksInY;
238 SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ? totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u : 0;
240 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
242 && width + PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
243 && height + PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
246 return ( atlas + 1u );
252 void AtlasManager::CreateMesh( SizeType atlas,
254 SizeType imageHeight,
255 const Vector2& position,
256 SizeType widthInBlocks,
257 SizeType heightInBlocks,
258 Dali::MeshData& meshData,
259 AtlasSlotDescriptor& desc )
261 Dali::MeshData::Vertex vertex;
262 Dali::MeshData::VertexContainer vertices;
263 Dali::MeshData::FaceIndices faces;
264 Dali::MeshData::FaceIndex faceIndex = 0;
265 meshData.SetHasNormals( false );
266 meshData.SetHasColor( true );
267 meshData.SetHasTextureCoords( true );
269 SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth;
270 SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight;
272 float vertexBlockWidth = static_cast< float >( blockWidth );
273 float vertexBlockHeight = static_cast< float >( blockHeight );
275 SizeType width = mAtlasList[ atlas ].mWidth;
276 SizeType height = mAtlasList[ atlas ].mHeight;
278 SizeType atlasWidthInBlocks = width / blockWidth;
280 // Get the normalized size of a texel in both directions
281 // TODO when texture resizing and passing texture size via uniforms is available,
282 // we will encode pixel positions into the vertex data rather than normalized
283 // meaning that geometry needn't be changed on an atlas resize
284 float texelX = 1.0f / static_cast< float >( width );
285 float texelY = 1.0f / static_cast< float >( height );
287 // Get the normalized size of a block in texels
288 float texelBlockWidth = texelX * vertexBlockWidth;
289 float texelBlockHeight = texelY * vertexBlockHeight;
291 // Get partial block space
292 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
293 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
296 float texelEdgeWidth = vertexEdgeWidth * texelX;
297 float texelEdgeHeight = vertexEdgeHeight * texelY;
299 // Block by block create the two triangles for the quad
300 SizeType blockIndex = 0;
306 Vector2 topLeft = position;
308 for ( SizeType y = 0; y < heightInBlocks; ++y )
311 float currentX = position.x;
313 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
315 ndcHeight = texelEdgeHeight;
316 ndcVHeight = vertexEdgeHeight;
320 ndcHeight = texelBlockHeight;
321 ndcVHeight = vertexBlockHeight;
324 for ( SizeType x = 0; x < widthInBlocks; ++x )
326 SizeType block = desc.mBlocksList[ blockIndex++ ];
328 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
329 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
331 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
333 ndcWidth = texelEdgeWidth;
334 ndcVWidth = vertexEdgeWidth;
338 ndcWidth = texelBlockWidth;
339 ndcVWidth = vertexBlockWidth;
343 vertex.x = topLeft.x;
344 vertex.y = topLeft.y;
349 vertices.push_back( vertex );
352 vertex.x = topLeft.x + ndcVWidth;
353 vertex.y = topLeft.y;
355 vertex.u = fBlockX + ndcWidth;
358 vertices.push_back( vertex );
361 vertex.x = topLeft.x;
362 vertex.y = topLeft.y + ndcVHeight;
365 vertex.v = fBlockY + ndcHeight;
367 vertices.push_back( vertex );
370 topLeft.x += ndcVWidth;
371 vertex.x = topLeft.x;
372 vertex.y = topLeft.y + ndcVHeight;
374 vertex.u = fBlockX + ndcWidth;
375 vertex.v = fBlockY + ndcHeight;
377 vertices.push_back( vertex );
379 // Six indices in counter clockwise winding
380 faces.push_back( faceIndex + 1u );
381 faces.push_back( faceIndex );
382 faces.push_back( faceIndex + 2u );
383 faces.push_back( faceIndex + 2u );
384 faces.push_back( faceIndex + 3u );
385 faces.push_back( faceIndex + 1u );
390 topLeft.x = currentX;
391 topLeft.y += vertexBlockHeight;
394 // If there's only one block then skip this next vertex optimisation
395 if ( widthInBlocks * heightInBlocks > 1 )
397 Dali::MeshData::VertexContainer optimizedVertices;
398 OptimizeVertices( vertices, faces, optimizedVertices );
399 meshData.SetVertices( optimizedVertices );
403 meshData.SetVertices( vertices );
406 meshData.SetFaceIndices( faces );
407 meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
408 //PrintMeshData( meshData );
411 void AtlasManager::PrintMeshData( const MeshData& meshData )
413 std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
414 std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
416 Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
417 Dali::MeshData::FaceIndices faces = meshData.GetFaces();
419 for ( SizeType v = 0; v < vertices.size(); ++v )
421 std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
422 std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
423 std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
426 std::cout << "\n Indices: ";
427 for ( SizeType i = 0; i < faces.size(); ++i )
429 std::cout << " " << faces[ i ];
431 std::cout << std::endl;
434 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
435 MeshData::FaceIndices& faces,
436 MeshData::VertexContainer& out )
438 unsigned short vertexIndex = 0;
440 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
441 for ( SizeType i = 0; i < faces.size(); ++i )
443 // Fetch a vertex, has it already been assigned?
444 bool foundVertex = false;
445 Dali::MeshData::Vertex v = in[ faces [ i ] ];
446 for ( SizeType j = 0; j < vertexIndex; ++j )
448 if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
449 v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
450 v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
452 // Yes, so store this down as the vertex to use
459 // Did we find a vertex ?
463 faces[ i ] = vertexIndex++;
469 void AtlasManager::StitchMesh( MeshData& first,
470 const MeshData& second,
474 // Would be much quicker to be able to get a non-const reference to these containers and update in situ
475 MeshData::VertexContainer v1 = first.GetVertices();
476 MeshData::VertexContainer v2 = second.GetVertices();
477 MeshData::FaceIndices f1 = first.GetFaces();
478 MeshData::FaceIndices f2 = second.GetFaces();
480 uint32_t vc1 = first.GetVertexCount();
481 uint32_t vc2 = second.GetVertexCount();
483 for ( uint32_t v = 0; v < vc2; ++v )
485 v1.push_back( v2[ v ] );
488 for ( uint32_t f = 0; f < f2.size(); ++f )
490 f1.push_back( f2[ f ] + vc1 );
495 MeshData::VertexContainer optimizedVertices;
496 OptimizeVertices( v1, f1, optimizedVertices );
497 first.SetVertices( optimizedVertices );
501 first.SetVertices( v1 );
504 first.SetFaceIndices( f1 );
506 // TODO rather than set the material to the second, check to see if there's a match and return if not
507 first.SetMaterial( second.GetMaterial() );
510 void AtlasManager::StitchMesh( const MeshData& first,
511 const MeshData& second,
515 // TODO Would be much quicker to be able to get a non-const reference to these containers and update in situ
516 MeshData::VertexContainer v1 = first.GetVertices();
517 MeshData::VertexContainer v2 = second.GetVertices();
518 MeshData::FaceIndices f1 = first.GetFaces();
519 MeshData::FaceIndices f2 = second.GetFaces();
521 uint32_t vc1 = first.GetVertexCount();
522 uint32_t vc2 = second.GetVertexCount();
524 MeshData::VertexContainer vertices;
526 MeshData::FaceIndices faces;
528 MeshData::Vertex vertex;
530 for ( uint32_t v = 0; v < vc1; ++v )
532 vertices.push_back( v1[ v ] );
535 for ( uint32_t v = 0; v < vc2; ++v )
537 vertices.push_back( v2[ v ] );
540 for ( uint32_t f = 0; f < f1.size(); ++f )
542 faces.push_back( f1[ f ] );
545 for ( uint32_t f = 0; f < f2.size(); ++f )
547 faces.push_back( f2[ f ] + vc1 );
552 MeshData::VertexContainer optimizedVertices;
553 OptimizeVertices( vertices, faces, optimizedVertices );
554 out.SetVertices( optimizedVertices );
558 out.SetVertices( vertices );
561 // TODO rather than set the material to the second, check to see if there's a match and return if not
562 out.SetMaterial( second.GetMaterial() );
563 out.SetFaceIndices( faces );
566 void AtlasManager::UploadImage( const BufferImage& image,
567 const AtlasSlotDescriptor& desc )
569 // Get the atlas to upload the image to
570 SizeType atlas = desc.mAtlasId - 1u;
572 // Check to see that the pixel formats are compatible
573 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
575 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
579 SizeType atlasBlockWidth = mAtlasList[ atlas ].mBlockWidth;
580 SizeType atlasBlockHeight = mAtlasList[ atlas ].mBlockHeight;
581 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
583 SizeType block = desc.mBlocksList[ 0 ];
584 SizeType blockX = block % atlasWidthInBlocks;
585 SizeType blockY = block / atlasWidthInBlocks;
586 SizeType blockOffsetX = blockX * atlasBlockWidth;
587 SizeType blockOffsetY = blockY * atlasBlockHeight;
589 SizeType width = image.GetWidth();
590 SizeType height = image.GetHeight();
592 if ( !mAtlasList[ atlas ].mAtlas.Upload( image, blockOffsetX, blockOffsetY ) )
594 DALI_LOG_ERROR("Uploading block to Atlas Failed!.\n");
596 if ( blockOffsetY + height + PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
598 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mEdgeX, blockOffsetX, blockOffsetY + height ) )
600 DALI_LOG_ERROR("Uploading edgeX to Atlas Failed!.\n");
603 if ( blockOffsetX + width + PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
605 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mEdgeY, blockOffsetX + width, blockOffsetY ) )
607 DALI_LOG_ERROR("Uploading edgeY to Atlas Failed!.\n");
612 void AtlasManager::GenerateMeshData( ImageId id,
613 const Vector2& position,
616 // Read the atlas Id to use for this image
617 SizeType imageId = id - 1u;
618 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
619 SizeType width = mImageList[ imageId ].mImageWidth;
620 SizeType height = mImageList[ imageId ].mImageHeight;
622 SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
623 if ( width % mAtlasList[ atlas ].mBlockWidth )
627 SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
628 if ( height % mAtlasList[ atlas ].mBlockHeight )
633 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
635 // Mesh created so increase the reference count
636 mImageList[ imageId ].mCount++;
639 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
642 if ( !atlas || atlas > mAtlasList.size( ) )
645 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
648 return mAtlasList[ atlas -1u ].mAtlas;
651 bool AtlasManager::Remove( ImageId id )
653 // Decrements the reference count of this image, and removes the blocks if zero.
654 SizeType imageId = id - 1u;
655 bool removed = false;
657 if ( id > mImageList.size() )
659 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
663 // If we attempt to free an image that is already freed then do nothing, other than log
664 if ( !mImageList[ imageId ].mCount )
666 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
670 if ( 1u == --mImageList[ imageId ].mCount )
672 // 'Remove the blocks' from this image and add to the atlas' freelist
674 mImageList[ imageId ].mCount = 0;
675 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
676 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
678 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
684 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
686 if ( id && id <= mImageList.size() )
688 return mImageList[ id - 1u ].mAtlasId;
696 void AtlasManager::SetNewAtlasSize( const Vector2& size,
697 const Vector2& blockSize )
699 mNewAtlasSize = size;
700 mNewBlockSize = blockSize;
703 Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
705 if ( atlas && atlas <= mAtlasList.size() )
707 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ),
708 static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) );
712 return Vector2( 0.0f, 0.0f );
716 Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
718 if ( atlas && atlas <= mAtlasList.size() )
720 return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mWidth ),
721 static_cast< float >( mAtlasList[ atlas - 1u ].mHeight ) );
725 return Vector2( 0.0f, 0.0f );
729 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
731 if ( atlas && atlas <= mAtlasList.size() )
733 uint32_t index = atlas - 1u;
734 uint32_t width = mAtlasList[ index ].mWidth;
735 uint32_t height = mAtlasList[ index ].mHeight;
736 uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
737 uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
739 SizeType widthInBlocks = width / blockWidth;
740 SizeType heightInBlocks = height / blockHeight;
741 uint32_t blockCount = widthInBlocks * heightInBlocks;
743 // Check free previously unallocated blocks and any free blocks
744 blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size();
753 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
755 return mAtlasList.size();
758 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
760 if ( !atlas || atlas > mAtlasList.size( ) )
763 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
766 return mAtlasList[ atlas -1u ].mPixelFormat;
769 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
771 Toolkit::AtlasManager::AtlasMetricsEntry entry;
772 uint32_t textureMemoryUsed = 0;
773 uint32_t atlasCount = mAtlasList.size();
774 metrics.mAtlasCount = atlasCount;
775 metrics.mAtlasMetrics.Resize(0);
777 for ( uint32_t i = 0; i < atlasCount; ++i )
779 SizeType width = mAtlasList[ i ].mWidth;
780 SizeType height = mAtlasList[ i ].mHeight;
781 SizeType blockWidth = mAtlasList[ i ].mBlockWidth;
782 SizeType blockHeight = mAtlasList[ i ].mBlockHeight;
784 entry.mWidth = width;
785 entry.mHeight = height;
786 entry.mBlockWidth = blockWidth;
787 entry.mBlockHeight = blockHeight;
788 entry.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
789 entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock : entry.mTotalBlocks - mAtlasList[ i ].mFreeBlocksList.Size();
790 entry.mPixelFormat = GetPixelFormat( i + 1 );
792 metrics.mAtlasMetrics.PushBack( entry );
794 uint32_t size = width * height;
795 if ( entry.mPixelFormat == Pixel::BGRA8888 )
800 textureMemoryUsed += size;
803 metrics.mTextureMemoryUsed = textureMemoryUsed;
807 } // namespace Internal
809 } // namespace Toolkit