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 > width || blockHeight > height )
118 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
119 width, height, blockWidth, blockHeight );
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 / blockWidth ) * ( height / blockHeight );
130 atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks - 1u;
132 atlasDescriptor.mHorizontalStrip = BufferImage::New( blockWidth, SINGLE_PIXEL_PADDING, pixelformat );
133 atlasDescriptor.mVerticalStrip = BufferImage::New( SINGLE_PIXEL_PADDING, blockHeight - DOUBLE_PIXEL_PADDING, pixelformat );
135 memset( atlasDescriptor.mHorizontalStrip.GetBuffer(), 0, atlasDescriptor.mHorizontalStrip.GetBufferSize() );
136 memset( atlasDescriptor.mVerticalStrip.GetBuffer(), 0, atlasDescriptor.mVerticalStrip.GetBufferSize() );
138 BufferImage filledPixelImage = BufferImage::New( 1u, 1u, pixelformat );
139 memset( filledPixelImage.GetBuffer(), 0xFF, filledPixelImage.GetBufferSize() );
140 atlas.Upload( filledPixelImage, 0, 0 );
142 Sampler sampler = Sampler::New( atlas, "sTexture" );
143 sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
144 atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
145 atlasDescriptor.mMaterial.AddSampler( sampler );
146 atlasDescriptor.mSampler = sampler;
147 atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
148 mAtlasList.push_back( atlasDescriptor );
149 return mAtlasList.size();
152 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
154 mAddFailPolicy = policy;
157 void AtlasManager::Add( const BufferImage& image,
158 Toolkit::AtlasManager::AtlasSlot& slot,
159 Toolkit::AtlasManager::AtlasId atlas )
161 // See if there's a slot in an atlas that matches the requirements of this image
162 // A bitmap must be sliceable into a single atlas
163 Pixel::Format pixelFormat = image.GetPixelFormat();
164 SizeType width = image.GetWidth();
165 SizeType height = image.GetHeight();
166 SizeType blockArea = 0;
167 SizeType foundAtlas = 0;
171 AtlasSlotDescriptor desc;
173 // If there is a preferred atlas then check for room in that first
176 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
179 // Search current atlases to see if there is a good match
180 while( !foundAtlas && index < mAtlasList.size() )
182 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
186 // If we can't find a suitable atlas then check the policy to determine action
189 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
191 SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
198 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea );
202 if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
204 // Haven't found an atlas for this image!!!!!!
209 // Work out where the blocks are we're going to use
210 for ( SizeType i = 0; i < blockArea; ++i )
212 // Is there currently a next free block available ?
213 if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
215 // Yes, so select our next block
216 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
220 // Our next block must be from the free list, fetch from the start of the list
221 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
222 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
226 desc.mImageWidth = width;
227 desc.mImageHeight = height;
228 desc.mAtlasId = foundAtlas + 1u;
231 // See if there's a previously freed image ID that we can assign to this new image
232 uint32_t imageId = 0u;
233 for ( uint32_t i = 0u; i < mImageList.size(); ++i )
235 if ( !mImageList[ i ].mCount )
243 mImageList.push_back( desc );
244 slot.mImageId = mImageList.size();
248 mImageList[ imageId - 1u ] = desc;
249 slot.mImageId = imageId;
251 slot.mAtlasId = foundAtlas + 1u;
252 UploadImage( image, desc );
255 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
258 Pixel::Format pixelFormat,
259 SizeType& blockArea )
261 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
263 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
264 if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
265 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
266 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
269 return ( atlas + 1u );
275 void AtlasManager::CreateMesh( SizeType atlas,
277 SizeType imageHeight,
278 const Vector2& position,
279 SizeType widthInBlocks,
280 SizeType heightInBlocks,
281 Toolkit::AtlasManager::Mesh2D& mesh,
282 AtlasSlotDescriptor& desc )
284 Toolkit::AtlasManager::Vertex2D vertex;
285 uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
287 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
288 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
290 float vertexBlockWidth = static_cast< float >( blockWidth );
291 float vertexBlockHeight = static_cast< float >( blockHeight );
293 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
294 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
296 SizeType atlasWidthInBlocks = width / blockWidth;
298 // Get the normalized size of a texel in both directions
299 // TODO when texture resizing and passing texture size via uniforms is available,
300 // we will encode pixel positions into the vertex data rather than normalized
301 // meaning that geometry needn't be changed on an atlas resize
302 float texelX = 1.0f / static_cast< float >( width );
303 float texelY = 1.0f / static_cast< float >( height );
305 float halfTexelX = texelX * 0.5f;
306 float halfTexelY = texelY * 0.5f;
308 // Get the normalized size of a block in texels
309 float texelBlockWidth = texelX * vertexBlockWidth;
310 float texelBlockHeight = texelY * vertexBlockHeight;
312 // Get partial block space
313 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
314 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
317 float texelEdgeWidth = texelX * vertexEdgeWidth;
318 float texelEdgeHeight = texelY * vertexEdgeHeight;
320 // We're going to 'blit' half a pixel more on each edge
326 // Block by block create the two triangles for the quad
327 SizeType blockIndex = 0;
333 // Move back half a pixel
334 Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
336 for ( SizeType y = 0; y < heightInBlocks; ++y )
339 float currentX = position.x;
341 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
343 ndcHeight = texelEdgeHeight + texelY;
344 ndcVHeight = vertexEdgeHeight;
348 ndcHeight = texelBlockHeight + texelY;
349 ndcVHeight = vertexBlockHeight;
352 for ( SizeType x = 0; x < widthInBlocks; ++x )
354 SizeType block = desc.mBlocksList[ blockIndex++ ];
356 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
357 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
359 // Add on texture filtering compensation
360 fBlockX += halfTexelX;
361 fBlockY += halfTexelY;
363 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
365 ndcWidth = texelEdgeWidth + texelX;
366 ndcVWidth = vertexEdgeWidth;
370 ndcWidth = texelBlockWidth + texelX;
371 ndcVWidth = vertexBlockWidth;
375 vertex.mPosition.x = topLeft.x;
376 vertex.mPosition.y = topLeft.y;
377 vertex.mTexCoords.x = fBlockX;
378 vertex.mTexCoords.y = fBlockY;
380 mesh.mVertices.PushBack( vertex );
383 vertex.mPosition.x = topLeft.x + ndcVWidth;
384 vertex.mPosition.y = topLeft.y;
385 vertex.mTexCoords.x = fBlockX + ndcWidth;
386 vertex.mTexCoords.y = fBlockY;
388 mesh.mVertices.PushBack( vertex );
391 vertex.mPosition.x = topLeft.x;
392 vertex.mPosition.y = topLeft.y + ndcVHeight;
393 vertex.mTexCoords.x = fBlockX;
394 vertex.mTexCoords.y = fBlockY + ndcHeight;
396 mesh.mVertices.PushBack( vertex );
399 topLeft.x += ndcVWidth;
400 vertex.mPosition.x = topLeft.x;
401 vertex.mPosition.y = topLeft.y + ndcVHeight;
402 vertex.mTexCoords.x = fBlockX + ndcWidth;
403 vertex.mTexCoords.y = fBlockY + ndcHeight;
405 mesh.mVertices.PushBack( vertex );
407 // Six indices in counter clockwise winding
408 mesh.mIndices.PushBack( faceIndex + 1u );
409 mesh.mIndices.PushBack( faceIndex );
410 mesh.mIndices.PushBack( faceIndex + 2u );
411 mesh.mIndices.PushBack( faceIndex + 2u );
412 mesh.mIndices.PushBack( faceIndex + 3u );
413 mesh.mIndices.PushBack( faceIndex + 1u );
418 topLeft.x = currentX;
419 topLeft.y += vertexBlockHeight;
422 // If there's only one block then skip this next vertex optimisation
423 if ( widthInBlocks * heightInBlocks > 1 )
425 Toolkit::AtlasManager::Mesh2D optimizedMesh;
426 OptimizeMesh( mesh, optimizedMesh );
430 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
432 uint32_t vertexCount = mesh.mVertices.Size();
433 uint32_t indexCount = mesh.mIndices.Size();
434 std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
435 std::cout << ", Triangles = " << indexCount / 3 << std::endl;
437 for ( SizeType v = 0; v < vertexCount; ++v )
439 std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
440 std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
441 std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
442 std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
445 std::cout << "\n Indices: ";
446 for ( SizeType i = 0; i < indexCount; ++i )
448 std::cout << " " << mesh.mIndices[ i ];
450 std::cout << std::endl;
453 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
454 Toolkit::AtlasManager::Mesh2D& out )
456 unsigned short vertexIndex = 0;
458 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
459 for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
461 // Fetch a vertex, has it already been assigned?
462 bool foundVertex = false;
463 Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
464 for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
466 if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
467 ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
468 ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
469 ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
471 // Yes, so store this down as the vertex to use
472 out.mIndices.PushBack( j );
478 // Did we find a vertex ?
481 // No so add a new one
482 out.mVertices.PushBack( v );
488 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
489 const Toolkit::AtlasManager::Mesh2D& second,
492 const uint32_t verticesCount = first.mVertices.Size();
493 first.mVertices.Insert( first.mVertices.End(),
494 second.mVertices.Begin(),
495 second.mVertices.End() );
497 const uint32_t indicesCount = first.mIndices.Size();
498 first.mIndices.Insert( first.mIndices.End(),
499 second.mIndices.Begin(),
500 second.mIndices.End() );
502 for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
503 endIt = first.mIndices.End();
507 *it += verticesCount;
512 Toolkit::AtlasManager::Mesh2D optimizedMesh;
513 OptimizeMesh( first, optimizedMesh );
514 first = optimizedMesh;
518 void AtlasManager::UploadImage( const BufferImage& image,
519 const AtlasSlotDescriptor& desc )
521 // Get the atlas to upload the image to
522 SizeType atlas = desc.mAtlasId - 1u;
524 // Check to see that the pixel formats are compatible
525 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
527 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
531 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
532 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
533 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
535 SizeType block = desc.mBlocksList[ 0 ];
536 SizeType blockX = block % atlasWidthInBlocks;
537 SizeType blockY = block / atlasWidthInBlocks;
538 SizeType blockOffsetX = blockX * atlasBlockWidth;
539 SizeType blockOffsetY = blockY * atlasBlockHeight;
541 SizeType width = image.GetWidth();
542 SizeType height = image.GetHeight();
544 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
545 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
546 blockOffsetX + SINGLE_PIXEL_PADDING,
547 blockOffsetY + SINGLE_PIXEL_PADDING ) )
549 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
553 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
557 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
561 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
563 blockOffsetY + SINGLE_PIXEL_PADDING ) )
565 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
569 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
571 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
573 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
575 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
580 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
582 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
583 blockOffsetX + width + SINGLE_PIXEL_PADDING,
584 blockOffsetY + SINGLE_PIXEL_PADDING ) )
586 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
591 void AtlasManager::GenerateMeshData( ImageId id,
592 const Vector2& position,
593 Toolkit::AtlasManager::Mesh2D& meshData,
596 // Read the atlas Id to use for this image
597 SizeType imageId = id - 1u;
598 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
599 SizeType width = mImageList[ imageId ].mImageWidth;
600 SizeType height = mImageList[ imageId ].mImageHeight;
602 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
603 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
607 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
608 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
613 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
615 // Mesh created so increase the reference count, if we're asked to
618 mImageList[ imageId ].mCount++;
622 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
625 if ( !atlas || atlas > mAtlasList.size( ) )
628 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
631 return mAtlasList[ atlas -1u ].mAtlas;
634 bool AtlasManager::Remove( ImageId id )
636 // Decrements the reference count of this image, and removes the blocks if zero.
637 SizeType imageId = id - 1u;
638 bool removed = false;
640 if ( id > mImageList.size() )
642 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
646 // If we attempt to free an image that is already freed then do nothing, other than log
647 if ( !mImageList[ imageId ].mCount )
649 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
653 if ( 2u > --mImageList[ imageId ].mCount )
655 // 'Remove the blocks' from this image and add to the atlas' freelist
657 mImageList[ imageId ].mCount = 0;
658 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
659 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
661 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
667 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
669 if ( id && id <= mImageList.size() )
671 return mImageList[ id - 1u ].mAtlasId;
679 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
681 mNewAtlasSize = size;
682 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
683 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
686 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
688 if ( atlas && atlas-- <= mAtlasList.size() )
690 return mAtlasList[ atlas ].mSize;
695 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
697 if ( atlas && atlas-- <= mAtlasList.size() )
699 return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
707 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
709 return mAtlasList.size();
712 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
714 if ( !atlas || atlas > mAtlasList.size( ) )
717 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
720 return mAtlasList[ --atlas].mPixelFormat;
723 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
725 Toolkit::AtlasManager::AtlasMetricsEntry entry;
726 uint32_t textureMemoryUsed = 0;
727 uint32_t atlasCount = mAtlasList.size();
728 metrics.mAtlasCount = atlasCount;
729 metrics.mAtlasMetrics.Resize(0);
731 for ( uint32_t i = 0; i < atlasCount; ++i )
733 entry.mSize = mAtlasList[ i ].mSize;
734 entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
735 entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
736 entry.mPixelFormat = GetPixelFormat( i + 1 );
738 metrics.mAtlasMetrics.PushBack( entry );
740 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
741 if ( entry.mPixelFormat == Pixel::BGRA8888 )
746 textureMemoryUsed += size;
749 metrics.mTextureMemoryUsed = textureMemoryUsed;
752 Material AtlasManager::GetMaterial( AtlasId atlas ) const
754 if ( atlas && atlas-- <= mAtlasList.size() )
756 return mAtlasList[ atlas ].mMaterial;
762 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
764 if ( atlas && atlas-- <= mAtlasList.size() )
766 return mAtlasList[ atlas ].mSampler;
772 } // namespace Internal
774 } // namespace Toolkit