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/devel-api/rendering/sampler.h>
24 #include <dali/devel-api/rendering/shader.h>
25 #include <dali/integration-api/debug.h>
38 const uint32_t DEFAULT_ATLAS_WIDTH( 512u );
39 const uint32_t DEFAULT_ATLAS_HEIGHT( 512u );
40 const uint32_t DEFAULT_BLOCK_WIDTH( 16u );
41 const uint32_t DEFAULT_BLOCK_HEIGHT( 16u );
42 const uint32_t SINGLE_PIXEL_PADDING( 1u );
43 const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
44 const uint32_t FILLED_PIXEL( -1 );
45 Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
47 #define MAKE_SHADER(A)#A
49 const char* VERTEX_SHADER = MAKE_SHADER(
50 attribute mediump vec2 aPosition;
51 attribute mediump vec2 aTexCoord;
52 uniform mediump mat4 uMvpMatrix;
53 varying mediump vec2 vTexCoord;
57 mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
58 gl_Position = uMvpMatrix * position;
59 vTexCoord = aTexCoord;
63 const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
64 uniform lowp vec4 uColor;
65 uniform sampler2D sTexture;
66 varying mediump vec2 vTexCoord;
70 mediump vec4 color = texture2D( sTexture, vTexCoord );
71 gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
75 const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
76 uniform sampler2D sTexture;
77 varying mediump vec2 vTexCoord;
81 gl_FragColor = texture2D( sTexture, vTexCoord );
87 AtlasManager::AtlasManager()
88 : mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES )
90 mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
91 mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
92 mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
93 mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
94 mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
95 mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
98 AtlasManagerPtr AtlasManager::New()
100 AtlasManagerPtr internal = new AtlasManager();
104 AtlasManager::~AtlasManager()
108 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
110 SizeType width = size.mWidth;
111 SizeType height = size.mHeight;
112 SizeType blockWidth = size.mBlockWidth;
113 SizeType blockHeight = size.mBlockHeight;
115 // Check to see if the atlas is large enough to hold a single block even ?
116 if ( blockWidth + DOUBLE_PIXEL_PADDING + 1u > width || blockHeight + DOUBLE_PIXEL_PADDING + 1u > height )
118 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
119 width, height, blockWidth + DOUBLE_PIXEL_PADDING + 1u, blockHeight + DOUBLE_PIXEL_PADDING + 1u );
123 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
124 atlas.Clear( Vector4::ZERO );
125 AtlasDescriptor atlasDescriptor;
126 atlasDescriptor.mAtlas = atlas;
127 atlasDescriptor.mSize = size;
128 atlasDescriptor.mPixelFormat = pixelformat;
129 atlasDescriptor.mTotalBlocks = ( ( width - 1u ) / blockWidth ) * ( ( height - 1u ) / blockHeight );
130 atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks;
132 atlasDescriptor.mHorizontalStrip = BufferImage::New( blockWidth, SINGLE_PIXEL_PADDING, pixelformat );
133 atlasDescriptor.mVerticalStrip = BufferImage::New( SINGLE_PIXEL_PADDING, blockHeight - DOUBLE_PIXEL_PADDING, pixelformat );
135 PixelBuffer* buffer = atlasDescriptor.mHorizontalStrip.GetBuffer();
138 DALI_LOG_ERROR("atlasDescriptor.mHorizontalStrip.GetBuffer() returns NULL\n");
141 memset( buffer, 0, atlasDescriptor.mHorizontalStrip.GetBufferSize() );
143 buffer = atlasDescriptor.mVerticalStrip.GetBuffer();
146 DALI_LOG_ERROR("atlasDescriptor.mVerticalStrip.GetBuffer() returns NULL\n");
149 memset( buffer, 0, atlasDescriptor.mVerticalStrip.GetBufferSize() );
151 BufferImage filledPixelImage = BufferImage::New( 1u, 1u, pixelformat );
152 buffer = filledPixelImage.GetBuffer();
155 DALI_LOG_ERROR("filledPixelImage.GetBuffer() returns NULL\n");
159 memset( buffer, 0xFF, filledPixelImage.GetBufferSize() );
160 atlas.Upload( filledPixelImage, 0, 0 );
162 atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
163 atlasDescriptor.mMaterial.AddTexture(atlas, "sTexture" );
164 atlasDescriptor.mImage = atlas;
165 atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
166 mAtlasList.push_back( atlasDescriptor );
167 return mAtlasList.size();
170 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
172 mAddFailPolicy = policy;
175 void AtlasManager::Add( const BufferImage& image,
176 Toolkit::AtlasManager::AtlasSlot& slot,
177 Toolkit::AtlasManager::AtlasId atlas )
179 // See if there's a slot in an atlas that matches the requirements of this image
180 // A bitmap must be sliceable into a single atlas
181 Pixel::Format pixelFormat = image.GetPixelFormat();
182 SizeType width = image.GetWidth();
183 SizeType height = image.GetHeight();
184 SizeType blockArea = 0;
185 SizeType foundAtlas = 0;
189 AtlasSlotDescriptor desc;
191 // If there is a preferred atlas then check for room in that first
194 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
197 // Search current atlases to see if there is a good match
198 while( !foundAtlas && index < mAtlasList.size() )
200 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
204 // If we can't find a suitable atlas then check the policy to determine action
207 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
209 foundAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
212 DALI_LOG_ERROR("Failed to create an atlas of %i x %i blocksize: %i x %i.\n",
213 mNewAtlasSize.mWidth,
214 mNewAtlasSize.mHeight,
215 mNewAtlasSize.mBlockWidth,
216 mNewAtlasSize.mBlockHeight );
220 foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea );
223 if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
225 // Haven't found an atlas for this image!!!!!!
226 DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
231 // Work out where the blocks are we're going to use
232 for ( SizeType i = 0; i < blockArea; ++i )
234 // Is there currently a next free block available ?
235 if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
237 // Yes, so select our next block
238 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
242 // Our next block must be from the free list, fetch from the start of the list
243 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
244 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
248 desc.mImageWidth = width;
249 desc.mImageHeight = height;
250 desc.mAtlasId = foundAtlas + 1u;
253 // See if there's a previously freed image ID that we can assign to this new image
254 uint32_t imageId = 0u;
255 for ( uint32_t i = 0u; i < mImageList.size(); ++i )
257 if ( !mImageList[ i ].mCount )
265 mImageList.push_back( desc );
266 slot.mImageId = mImageList.size();
270 mImageList[ imageId - 1u ] = desc;
271 slot.mImageId = imageId;
273 slot.mAtlasId = foundAtlas + 1u;
274 UploadImage( image, desc );
277 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
280 Pixel::Format pixelFormat,
281 SizeType& blockArea )
283 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
285 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
286 if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
287 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
288 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
291 return ( atlas + 1u );
297 void AtlasManager::CreateMesh( SizeType atlas,
299 SizeType imageHeight,
300 const Vector2& position,
301 SizeType widthInBlocks,
302 SizeType heightInBlocks,
303 Toolkit::AtlasManager::Mesh2D& mesh,
304 AtlasSlotDescriptor& desc )
306 Toolkit::AtlasManager::Vertex2D vertex;
307 uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
309 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
310 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
312 float vertexBlockWidth = static_cast< float >( blockWidth );
313 float vertexBlockHeight = static_cast< float >( blockHeight );
315 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
316 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
318 SizeType atlasWidthInBlocks = ( width - 1u ) / blockWidth;
320 // Get the normalized size of a texel in both directions
321 // TODO when texture resizing and passing texture size via uniforms is available,
322 // we will encode pixel positions into the vertex data rather than normalized
323 // meaning that geometry needn't be changed on an atlas resize
324 float texelX = 1.0f / static_cast< float >( width );
325 float texelY = 1.0f / static_cast< float >( height );
327 float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
328 float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
330 // Get the normalized size of a block in texels
331 float texelBlockWidth = texelX * vertexBlockWidth;
332 float texelBlockHeight = texelY * vertexBlockHeight;
334 // Get partial block space
335 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
336 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
339 float texelEdgeWidth = texelX * vertexEdgeWidth;
340 float texelEdgeHeight = texelY * vertexEdgeHeight;
342 // We're going to 'blit' half a pixel more on each edge
348 // Block by block create the two triangles for the quad
349 SizeType blockIndex = 0;
355 // Move back half a pixel
356 Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
358 for ( SizeType y = 0; y < heightInBlocks; ++y )
361 float currentX = position.x;
363 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
365 ndcHeight = texelEdgeHeight + texelY;
366 ndcVHeight = vertexEdgeHeight;
370 ndcHeight = texelBlockHeight + texelY;
371 ndcVHeight = vertexBlockHeight;
374 for ( SizeType x = 0; x < widthInBlocks; ++x )
376 SizeType block = desc.mBlocksList[ blockIndex++ ];
378 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
379 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
381 // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
382 fBlockX += oneAndAHalfTexelX;
383 fBlockY += oneAndAHalfTexelY;
385 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
387 ndcWidth = texelEdgeWidth + texelX;
388 ndcVWidth = vertexEdgeWidth;
392 ndcWidth = texelBlockWidth + texelX;
393 ndcVWidth = vertexBlockWidth;
397 vertex.mPosition.x = topLeft.x;
398 vertex.mPosition.y = topLeft.y;
399 vertex.mTexCoords.x = fBlockX;
400 vertex.mTexCoords.y = fBlockY;
402 mesh.mVertices.PushBack( vertex );
405 vertex.mPosition.x = topLeft.x + ndcVWidth;
406 vertex.mPosition.y = topLeft.y;
407 vertex.mTexCoords.x = fBlockX + ndcWidth;
408 vertex.mTexCoords.y = fBlockY;
410 mesh.mVertices.PushBack( vertex );
413 vertex.mPosition.x = topLeft.x;
414 vertex.mPosition.y = topLeft.y + ndcVHeight;
415 vertex.mTexCoords.x = fBlockX;
416 vertex.mTexCoords.y = fBlockY + ndcHeight;
418 mesh.mVertices.PushBack( vertex );
421 topLeft.x += ndcVWidth;
422 vertex.mPosition.x = topLeft.x;
423 vertex.mPosition.y = topLeft.y + ndcVHeight;
424 vertex.mTexCoords.x = fBlockX + ndcWidth;
425 vertex.mTexCoords.y = fBlockY + ndcHeight;
427 mesh.mVertices.PushBack( vertex );
429 // Six indices in counter clockwise winding
430 mesh.mIndices.PushBack( faceIndex + 1u );
431 mesh.mIndices.PushBack( faceIndex );
432 mesh.mIndices.PushBack( faceIndex + 2u );
433 mesh.mIndices.PushBack( faceIndex + 2u );
434 mesh.mIndices.PushBack( faceIndex + 3u );
435 mesh.mIndices.PushBack( faceIndex + 1u );
440 topLeft.x = currentX;
441 topLeft.y += vertexBlockHeight;
444 // If there's only one block then skip this next vertex optimisation
445 if ( widthInBlocks * heightInBlocks > 1 )
447 Toolkit::AtlasManager::Mesh2D optimizedMesh;
448 OptimizeMesh( mesh, optimizedMesh );
452 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
454 uint32_t vertexCount = mesh.mVertices.Size();
455 uint32_t indexCount = mesh.mIndices.Size();
456 std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
457 std::cout << ", Triangles = " << indexCount / 3 << std::endl;
459 for ( SizeType v = 0; v < vertexCount; ++v )
461 std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
462 std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
463 std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
464 std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
467 std::cout << "\n Indices: ";
468 for ( SizeType i = 0; i < indexCount; ++i )
470 std::cout << " " << mesh.mIndices[ i ];
472 std::cout << std::endl;
475 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
476 Toolkit::AtlasManager::Mesh2D& out )
478 unsigned short vertexIndex = 0;
480 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
481 for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
483 // Fetch a vertex, has it already been assigned?
484 bool foundVertex = false;
485 Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
486 for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
488 if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
489 ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
490 ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
491 ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
493 // Yes, so store this down as the vertex to use
494 out.mIndices.PushBack( j );
500 // Did we find a vertex ?
503 // No so add a new one
504 out.mVertices.PushBack( v );
510 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
511 const Toolkit::AtlasManager::Mesh2D& second,
514 const uint32_t verticesCount = first.mVertices.Size();
515 first.mVertices.Insert( first.mVertices.End(),
516 second.mVertices.Begin(),
517 second.mVertices.End() );
519 const uint32_t indicesCount = first.mIndices.Size();
520 first.mIndices.Insert( first.mIndices.End(),
521 second.mIndices.Begin(),
522 second.mIndices.End() );
524 for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
525 endIt = first.mIndices.End();
529 *it += verticesCount;
534 Toolkit::AtlasManager::Mesh2D optimizedMesh;
535 OptimizeMesh( first, optimizedMesh );
536 first = optimizedMesh;
540 void AtlasManager::UploadImage( const BufferImage& image,
541 const AtlasSlotDescriptor& desc )
543 // Get the atlas to upload the image to
544 SizeType atlas = desc.mAtlasId - 1u;
546 // Check to see that the pixel formats are compatible
547 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
549 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
553 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
554 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
555 SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth;
557 SizeType block = desc.mBlocksList[ 0 ];
558 SizeType blockX = block % atlasWidthInBlocks;
559 SizeType blockY = block / atlasWidthInBlocks;
560 SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
561 SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u;
563 SizeType width = image.GetWidth();
564 SizeType height = image.GetHeight();
566 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
567 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
568 blockOffsetX + SINGLE_PIXEL_PADDING,
569 blockOffsetY + SINGLE_PIXEL_PADDING ) )
571 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
575 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
579 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
583 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
585 blockOffsetY + SINGLE_PIXEL_PADDING ) )
587 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
591 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
593 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
595 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
597 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
602 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
604 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
605 blockOffsetX + width + SINGLE_PIXEL_PADDING,
606 blockOffsetY + SINGLE_PIXEL_PADDING ) )
608 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
613 void AtlasManager::GenerateMeshData( ImageId id,
614 const Vector2& position,
615 Toolkit::AtlasManager::Mesh2D& meshData,
620 // Read the atlas Id to use for this image
621 SizeType imageId = id - 1u;
622 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
623 SizeType width = mImageList[ imageId ].mImageWidth;
624 SizeType height = mImageList[ imageId ].mImageHeight;
626 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
627 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
631 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
632 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
637 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
639 // Mesh created so increase the reference count, if we're asked to
642 mImageList[ imageId ].mCount++;
647 DALI_LOG_ERROR("Cannot generate mesh with invalid AtlasId\n");
651 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
654 if ( !atlas || atlas > mAtlasList.size( ) )
657 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
660 return mAtlasList[ atlas -1u ].mAtlas;
663 bool AtlasManager::Remove( ImageId id )
665 // Decrements the reference count of this image, and removes the blocks if zero.
666 SizeType imageId = id - 1u;
667 bool removed = false;
669 if ( id > mImageList.size() )
671 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
675 // If we attempt to free an image that is already freed then do nothing, other than log
676 if ( !mImageList[ imageId ].mCount )
678 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
682 if ( 2u > --mImageList[ imageId ].mCount )
684 // 'Remove the blocks' from this image and add to the atlas' freelist
686 mImageList[ imageId ].mCount = 0;
687 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
688 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
690 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
696 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
698 if ( id && id <= mImageList.size() )
700 return mImageList[ id - 1u ].mAtlasId;
708 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
710 mNewAtlasSize = size;
712 // Add on padding for borders around atlas entries
713 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
714 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
717 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
719 if ( atlas && atlas-- <= mAtlasList.size() )
721 return mAtlasList[ atlas ].mSize;
726 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
728 if ( atlas && atlas-- <= mAtlasList.size() )
730 return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
738 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
740 return mAtlasList.size();
743 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
745 if ( !atlas || atlas > mAtlasList.size( ) )
748 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
751 return mAtlasList[ --atlas].mPixelFormat;
754 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
756 Toolkit::AtlasManager::AtlasMetricsEntry entry;
757 uint32_t textureMemoryUsed = 0;
758 uint32_t atlasCount = mAtlasList.size();
759 metrics.mAtlasCount = atlasCount;
760 metrics.mAtlasMetrics.Resize(0);
762 for ( uint32_t i = 0; i < atlasCount; ++i )
764 entry.mSize = mAtlasList[ i ].mSize;
765 entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
766 entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
767 entry.mPixelFormat = GetPixelFormat( i + 1 );
769 metrics.mAtlasMetrics.PushBack( entry );
771 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
772 if ( entry.mPixelFormat == Pixel::BGRA8888 )
777 textureMemoryUsed += size;
780 metrics.mTextureMemoryUsed = textureMemoryUsed;
783 Material AtlasManager::GetMaterial( AtlasId atlas ) const
785 if ( atlas && atlas-- <= mAtlasList.size() )
787 return mAtlasList[ atlas ].mMaterial;
793 Image AtlasManager::GetImage( AtlasId atlas ) const
795 if ( atlas && atlas-- <= mAtlasList.size() )
797 return mAtlasList[ atlas ].mImage;
803 } // namespace Internal
805 } // namespace Toolkit