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 Sampler sampler = Sampler::New( atlas, "sTexture" );
163 sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
164 atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
165 atlasDescriptor.mMaterial.AddSampler( sampler );
166 atlasDescriptor.mSampler = sampler;
167 atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
168 mAtlasList.push_back( atlasDescriptor );
169 return mAtlasList.size();
172 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
174 mAddFailPolicy = policy;
177 void AtlasManager::Add( const BufferImage& image,
178 Toolkit::AtlasManager::AtlasSlot& slot,
179 Toolkit::AtlasManager::AtlasId atlas )
181 // See if there's a slot in an atlas that matches the requirements of this image
182 // A bitmap must be sliceable into a single atlas
183 Pixel::Format pixelFormat = image.GetPixelFormat();
184 SizeType width = image.GetWidth();
185 SizeType height = image.GetHeight();
186 SizeType blockArea = 0;
187 SizeType foundAtlas = 0;
191 AtlasSlotDescriptor desc;
193 // If there is a preferred atlas then check for room in that first
196 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
199 // Search current atlases to see if there is a good match
200 while( !foundAtlas && index < mAtlasList.size() )
202 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
206 // If we can't find a suitable atlas then check the policy to determine action
209 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
211 foundAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
214 DALI_LOG_ERROR("Failed to create an atlas of %i x %i blocksize: %i x %i.\n",
215 mNewAtlasSize.mWidth,
216 mNewAtlasSize.mHeight,
217 mNewAtlasSize.mBlockWidth,
218 mNewAtlasSize.mBlockHeight );
222 foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea );
225 if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
227 // Haven't found an atlas for this image!!!!!!
228 DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
233 // Work out where the blocks are we're going to use
234 for ( SizeType i = 0; i < blockArea; ++i )
236 // Is there currently a next free block available ?
237 if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
239 // Yes, so select our next block
240 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
244 // Our next block must be from the free list, fetch from the start of the list
245 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
246 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
250 desc.mImageWidth = width;
251 desc.mImageHeight = height;
252 desc.mAtlasId = foundAtlas + 1u;
255 // See if there's a previously freed image ID that we can assign to this new image
256 uint32_t imageId = 0u;
257 for ( uint32_t i = 0u; i < mImageList.size(); ++i )
259 if ( !mImageList[ i ].mCount )
267 mImageList.push_back( desc );
268 slot.mImageId = mImageList.size();
272 mImageList[ imageId - 1u ] = desc;
273 slot.mImageId = imageId;
275 slot.mAtlasId = foundAtlas + 1u;
276 UploadImage( image, desc );
279 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
282 Pixel::Format pixelFormat,
283 SizeType& blockArea )
285 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
287 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
288 if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
289 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
290 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
293 return ( atlas + 1u );
299 void AtlasManager::CreateMesh( SizeType atlas,
301 SizeType imageHeight,
302 const Vector2& position,
303 SizeType widthInBlocks,
304 SizeType heightInBlocks,
305 Toolkit::AtlasManager::Mesh2D& mesh,
306 AtlasSlotDescriptor& desc )
308 Toolkit::AtlasManager::Vertex2D vertex;
309 uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
311 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
312 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
314 float vertexBlockWidth = static_cast< float >( blockWidth );
315 float vertexBlockHeight = static_cast< float >( blockHeight );
317 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
318 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
320 SizeType atlasWidthInBlocks = ( width - 1u ) / blockWidth;
322 // Get the normalized size of a texel in both directions
323 // TODO when texture resizing and passing texture size via uniforms is available,
324 // we will encode pixel positions into the vertex data rather than normalized
325 // meaning that geometry needn't be changed on an atlas resize
326 float texelX = 1.0f / static_cast< float >( width );
327 float texelY = 1.0f / static_cast< float >( height );
329 float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
330 float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
332 // Get the normalized size of a block in texels
333 float texelBlockWidth = texelX * vertexBlockWidth;
334 float texelBlockHeight = texelY * vertexBlockHeight;
336 // Get partial block space
337 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
338 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
341 float texelEdgeWidth = texelX * vertexEdgeWidth;
342 float texelEdgeHeight = texelY * vertexEdgeHeight;
344 // We're going to 'blit' half a pixel more on each edge
350 // Block by block create the two triangles for the quad
351 SizeType blockIndex = 0;
357 // Move back half a pixel
358 Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
360 for ( SizeType y = 0; y < heightInBlocks; ++y )
363 float currentX = position.x;
365 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
367 ndcHeight = texelEdgeHeight + texelY;
368 ndcVHeight = vertexEdgeHeight;
372 ndcHeight = texelBlockHeight + texelY;
373 ndcVHeight = vertexBlockHeight;
376 for ( SizeType x = 0; x < widthInBlocks; ++x )
378 SizeType block = desc.mBlocksList[ blockIndex++ ];
380 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
381 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
383 // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
384 fBlockX += oneAndAHalfTexelX;
385 fBlockY += oneAndAHalfTexelY;
387 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
389 ndcWidth = texelEdgeWidth + texelX;
390 ndcVWidth = vertexEdgeWidth;
394 ndcWidth = texelBlockWidth + texelX;
395 ndcVWidth = vertexBlockWidth;
399 vertex.mPosition.x = topLeft.x;
400 vertex.mPosition.y = topLeft.y;
401 vertex.mTexCoords.x = fBlockX;
402 vertex.mTexCoords.y = fBlockY;
404 mesh.mVertices.PushBack( vertex );
407 vertex.mPosition.x = topLeft.x + ndcVWidth;
408 vertex.mPosition.y = topLeft.y;
409 vertex.mTexCoords.x = fBlockX + ndcWidth;
410 vertex.mTexCoords.y = fBlockY;
412 mesh.mVertices.PushBack( vertex );
415 vertex.mPosition.x = topLeft.x;
416 vertex.mPosition.y = topLeft.y + ndcVHeight;
417 vertex.mTexCoords.x = fBlockX;
418 vertex.mTexCoords.y = fBlockY + ndcHeight;
420 mesh.mVertices.PushBack( vertex );
423 topLeft.x += ndcVWidth;
424 vertex.mPosition.x = topLeft.x;
425 vertex.mPosition.y = topLeft.y + ndcVHeight;
426 vertex.mTexCoords.x = fBlockX + ndcWidth;
427 vertex.mTexCoords.y = fBlockY + ndcHeight;
429 mesh.mVertices.PushBack( vertex );
431 // Six indices in counter clockwise winding
432 mesh.mIndices.PushBack( faceIndex + 1u );
433 mesh.mIndices.PushBack( faceIndex );
434 mesh.mIndices.PushBack( faceIndex + 2u );
435 mesh.mIndices.PushBack( faceIndex + 2u );
436 mesh.mIndices.PushBack( faceIndex + 3u );
437 mesh.mIndices.PushBack( faceIndex + 1u );
442 topLeft.x = currentX;
443 topLeft.y += vertexBlockHeight;
446 // If there's only one block then skip this next vertex optimisation
447 if ( widthInBlocks * heightInBlocks > 1 )
449 Toolkit::AtlasManager::Mesh2D optimizedMesh;
450 OptimizeMesh( mesh, optimizedMesh );
454 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
456 uint32_t vertexCount = mesh.mVertices.Size();
457 uint32_t indexCount = mesh.mIndices.Size();
458 std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
459 std::cout << ", Triangles = " << indexCount / 3 << std::endl;
461 for ( SizeType v = 0; v < vertexCount; ++v )
463 std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
464 std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
465 std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
466 std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
469 std::cout << "\n Indices: ";
470 for ( SizeType i = 0; i < indexCount; ++i )
472 std::cout << " " << mesh.mIndices[ i ];
474 std::cout << std::endl;
477 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
478 Toolkit::AtlasManager::Mesh2D& out )
480 unsigned short vertexIndex = 0;
482 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
483 for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
485 // Fetch a vertex, has it already been assigned?
486 bool foundVertex = false;
487 Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
488 for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
490 if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
491 ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
492 ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
493 ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
495 // Yes, so store this down as the vertex to use
496 out.mIndices.PushBack( j );
502 // Did we find a vertex ?
505 // No so add a new one
506 out.mVertices.PushBack( v );
512 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
513 const Toolkit::AtlasManager::Mesh2D& second,
516 const uint32_t verticesCount = first.mVertices.Size();
517 first.mVertices.Insert( first.mVertices.End(),
518 second.mVertices.Begin(),
519 second.mVertices.End() );
521 const uint32_t indicesCount = first.mIndices.Size();
522 first.mIndices.Insert( first.mIndices.End(),
523 second.mIndices.Begin(),
524 second.mIndices.End() );
526 for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
527 endIt = first.mIndices.End();
531 *it += verticesCount;
536 Toolkit::AtlasManager::Mesh2D optimizedMesh;
537 OptimizeMesh( first, optimizedMesh );
538 first = optimizedMesh;
542 void AtlasManager::UploadImage( const BufferImage& image,
543 const AtlasSlotDescriptor& desc )
545 // Get the atlas to upload the image to
546 SizeType atlas = desc.mAtlasId - 1u;
548 // Check to see that the pixel formats are compatible
549 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
551 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
555 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
556 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
557 SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth;
559 SizeType block = desc.mBlocksList[ 0 ];
560 SizeType blockX = block % atlasWidthInBlocks;
561 SizeType blockY = block / atlasWidthInBlocks;
562 SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
563 SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u;
565 SizeType width = image.GetWidth();
566 SizeType height = image.GetHeight();
568 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
569 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
570 blockOffsetX + SINGLE_PIXEL_PADDING,
571 blockOffsetY + SINGLE_PIXEL_PADDING ) )
573 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
577 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
581 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
585 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
587 blockOffsetY + SINGLE_PIXEL_PADDING ) )
589 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
593 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
595 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
597 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
599 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
604 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
606 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
607 blockOffsetX + width + SINGLE_PIXEL_PADDING,
608 blockOffsetY + SINGLE_PIXEL_PADDING ) )
610 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
615 void AtlasManager::GenerateMeshData( ImageId id,
616 const Vector2& position,
617 Toolkit::AtlasManager::Mesh2D& meshData,
622 // Read the atlas Id to use for this image
623 SizeType imageId = id - 1u;
624 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
625 SizeType width = mImageList[ imageId ].mImageWidth;
626 SizeType height = mImageList[ imageId ].mImageHeight;
628 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
629 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
633 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
634 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
639 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
641 // Mesh created so increase the reference count, if we're asked to
644 mImageList[ imageId ].mCount++;
649 DALI_LOG_ERROR("Cannot generate mesh with invalid AtlasId\n");
653 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
656 if ( !atlas || atlas > mAtlasList.size( ) )
659 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
662 return mAtlasList[ atlas -1u ].mAtlas;
665 bool AtlasManager::Remove( ImageId id )
667 // Decrements the reference count of this image, and removes the blocks if zero.
668 SizeType imageId = id - 1u;
669 bool removed = false;
671 if ( id > mImageList.size() )
673 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
677 // If we attempt to free an image that is already freed then do nothing, other than log
678 if ( !mImageList[ imageId ].mCount )
680 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
684 if ( 2u > --mImageList[ imageId ].mCount )
686 // 'Remove the blocks' from this image and add to the atlas' freelist
688 mImageList[ imageId ].mCount = 0;
689 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
690 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
692 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
698 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
700 if ( id && id <= mImageList.size() )
702 return mImageList[ id - 1u ].mAtlasId;
710 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
712 mNewAtlasSize = size;
714 // Add on padding for borders around atlas entries
715 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
716 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
719 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
721 if ( atlas && atlas-- <= mAtlasList.size() )
723 return mAtlasList[ atlas ].mSize;
728 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
730 if ( atlas && atlas-- <= mAtlasList.size() )
732 return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
740 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
742 return mAtlasList.size();
745 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
747 if ( !atlas || atlas > mAtlasList.size( ) )
750 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
753 return mAtlasList[ --atlas].mPixelFormat;
756 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
758 Toolkit::AtlasManager::AtlasMetricsEntry entry;
759 uint32_t textureMemoryUsed = 0;
760 uint32_t atlasCount = mAtlasList.size();
761 metrics.mAtlasCount = atlasCount;
762 metrics.mAtlasMetrics.Resize(0);
764 for ( uint32_t i = 0; i < atlasCount; ++i )
766 entry.mSize = mAtlasList[ i ].mSize;
767 entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
768 entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
769 entry.mPixelFormat = GetPixelFormat( i + 1 );
771 metrics.mAtlasMetrics.PushBack( entry );
773 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
774 if ( entry.mPixelFormat == Pixel::BGRA8888 )
779 textureMemoryUsed += size;
782 metrics.mTextureMemoryUsed = textureMemoryUsed;
785 Material AtlasManager::GetMaterial( AtlasId atlas ) const
787 if ( atlas && atlas-- <= mAtlasList.size() )
789 return mAtlasList[ atlas ].mMaterial;
795 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
797 if ( atlas && atlas-- <= mAtlasList.size() )
799 return mAtlasList[ atlas ].mSampler;
805 } // namespace Internal
807 } // namespace Toolkit