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 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 foundAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
194 DALI_LOG_ERROR("Failed to create an atlas of %i x %i blocksize: %i x %i.\n",
195 mNewAtlasSize.mWidth,
196 mNewAtlasSize.mHeight,
197 mNewAtlasSize.mBlockWidth,
198 mNewAtlasSize.mBlockHeight );
202 foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea );
205 if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
207 // Haven't found an atlas for this image!!!!!!
208 DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
213 // Work out where the blocks are we're going to use
214 for ( SizeType i = 0; i < blockArea; ++i )
216 // Is there currently a next free block available ?
217 if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
219 // Yes, so select our next block
220 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
224 // Our next block must be from the free list, fetch from the start of the list
225 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
226 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
230 desc.mImageWidth = width;
231 desc.mImageHeight = height;
232 desc.mAtlasId = foundAtlas + 1u;
235 // See if there's a previously freed image ID that we can assign to this new image
236 uint32_t imageId = 0u;
237 for ( uint32_t i = 0u; i < mImageList.size(); ++i )
239 if ( !mImageList[ i ].mCount )
247 mImageList.push_back( desc );
248 slot.mImageId = mImageList.size();
252 mImageList[ imageId - 1u ] = desc;
253 slot.mImageId = imageId;
255 slot.mAtlasId = foundAtlas + 1u;
256 UploadImage( image, desc );
259 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
262 Pixel::Format pixelFormat,
263 SizeType& blockArea )
265 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
267 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
268 if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
269 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
270 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
273 return ( atlas + 1u );
279 void AtlasManager::CreateMesh( SizeType atlas,
281 SizeType imageHeight,
282 const Vector2& position,
283 SizeType widthInBlocks,
284 SizeType heightInBlocks,
285 Toolkit::AtlasManager::Mesh2D& mesh,
286 AtlasSlotDescriptor& desc )
288 Toolkit::AtlasManager::Vertex2D vertex;
289 uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
291 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
292 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
294 float vertexBlockWidth = static_cast< float >( blockWidth );
295 float vertexBlockHeight = static_cast< float >( blockHeight );
297 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
298 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
300 SizeType atlasWidthInBlocks = ( width - 1u ) / blockWidth;
302 // Get the normalized size of a texel in both directions
303 // TODO when texture resizing and passing texture size via uniforms is available,
304 // we will encode pixel positions into the vertex data rather than normalized
305 // meaning that geometry needn't be changed on an atlas resize
306 float texelX = 1.0f / static_cast< float >( width );
307 float texelY = 1.0f / static_cast< float >( height );
309 float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
310 float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
312 // Get the normalized size of a block in texels
313 float texelBlockWidth = texelX * vertexBlockWidth;
314 float texelBlockHeight = texelY * vertexBlockHeight;
316 // Get partial block space
317 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
318 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
321 float texelEdgeWidth = texelX * vertexEdgeWidth;
322 float texelEdgeHeight = texelY * vertexEdgeHeight;
324 // We're going to 'blit' half a pixel more on each edge
330 // Block by block create the two triangles for the quad
331 SizeType blockIndex = 0;
337 // Move back half a pixel
338 Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
340 for ( SizeType y = 0; y < heightInBlocks; ++y )
343 float currentX = position.x;
345 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
347 ndcHeight = texelEdgeHeight + texelY;
348 ndcVHeight = vertexEdgeHeight;
352 ndcHeight = texelBlockHeight + texelY;
353 ndcVHeight = vertexBlockHeight;
356 for ( SizeType x = 0; x < widthInBlocks; ++x )
358 SizeType block = desc.mBlocksList[ blockIndex++ ];
360 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
361 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
363 // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
364 fBlockX += oneAndAHalfTexelX;
365 fBlockY += oneAndAHalfTexelY;
367 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
369 ndcWidth = texelEdgeWidth + texelX;
370 ndcVWidth = vertexEdgeWidth;
374 ndcWidth = texelBlockWidth + texelX;
375 ndcVWidth = vertexBlockWidth;
379 vertex.mPosition.x = topLeft.x;
380 vertex.mPosition.y = topLeft.y;
381 vertex.mTexCoords.x = fBlockX;
382 vertex.mTexCoords.y = fBlockY;
384 mesh.mVertices.PushBack( vertex );
387 vertex.mPosition.x = topLeft.x + ndcVWidth;
388 vertex.mPosition.y = topLeft.y;
389 vertex.mTexCoords.x = fBlockX + ndcWidth;
390 vertex.mTexCoords.y = fBlockY;
392 mesh.mVertices.PushBack( vertex );
395 vertex.mPosition.x = topLeft.x;
396 vertex.mPosition.y = topLeft.y + ndcVHeight;
397 vertex.mTexCoords.x = fBlockX;
398 vertex.mTexCoords.y = fBlockY + ndcHeight;
400 mesh.mVertices.PushBack( vertex );
403 topLeft.x += ndcVWidth;
404 vertex.mPosition.x = topLeft.x;
405 vertex.mPosition.y = topLeft.y + ndcVHeight;
406 vertex.mTexCoords.x = fBlockX + ndcWidth;
407 vertex.mTexCoords.y = fBlockY + ndcHeight;
409 mesh.mVertices.PushBack( vertex );
411 // Six indices in counter clockwise winding
412 mesh.mIndices.PushBack( faceIndex + 1u );
413 mesh.mIndices.PushBack( faceIndex );
414 mesh.mIndices.PushBack( faceIndex + 2u );
415 mesh.mIndices.PushBack( faceIndex + 2u );
416 mesh.mIndices.PushBack( faceIndex + 3u );
417 mesh.mIndices.PushBack( faceIndex + 1u );
422 topLeft.x = currentX;
423 topLeft.y += vertexBlockHeight;
426 // If there's only one block then skip this next vertex optimisation
427 if ( widthInBlocks * heightInBlocks > 1 )
429 Toolkit::AtlasManager::Mesh2D optimizedMesh;
430 OptimizeMesh( mesh, optimizedMesh );
434 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
436 uint32_t vertexCount = mesh.mVertices.Size();
437 uint32_t indexCount = mesh.mIndices.Size();
438 std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
439 std::cout << ", Triangles = " << indexCount / 3 << std::endl;
441 for ( SizeType v = 0; v < vertexCount; ++v )
443 std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
444 std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
445 std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
446 std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
449 std::cout << "\n Indices: ";
450 for ( SizeType i = 0; i < indexCount; ++i )
452 std::cout << " " << mesh.mIndices[ i ];
454 std::cout << std::endl;
457 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
458 Toolkit::AtlasManager::Mesh2D& out )
460 unsigned short vertexIndex = 0;
462 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
463 for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
465 // Fetch a vertex, has it already been assigned?
466 bool foundVertex = false;
467 Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
468 for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
470 if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
471 ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
472 ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
473 ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
475 // Yes, so store this down as the vertex to use
476 out.mIndices.PushBack( j );
482 // Did we find a vertex ?
485 // No so add a new one
486 out.mVertices.PushBack( v );
492 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
493 const Toolkit::AtlasManager::Mesh2D& second,
496 const uint32_t verticesCount = first.mVertices.Size();
497 first.mVertices.Insert( first.mVertices.End(),
498 second.mVertices.Begin(),
499 second.mVertices.End() );
501 const uint32_t indicesCount = first.mIndices.Size();
502 first.mIndices.Insert( first.mIndices.End(),
503 second.mIndices.Begin(),
504 second.mIndices.End() );
506 for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
507 endIt = first.mIndices.End();
511 *it += verticesCount;
516 Toolkit::AtlasManager::Mesh2D optimizedMesh;
517 OptimizeMesh( first, optimizedMesh );
518 first = optimizedMesh;
522 void AtlasManager::UploadImage( const BufferImage& image,
523 const AtlasSlotDescriptor& desc )
525 // Get the atlas to upload the image to
526 SizeType atlas = desc.mAtlasId - 1u;
528 // Check to see that the pixel formats are compatible
529 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
531 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
535 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
536 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
537 SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth;
539 SizeType block = desc.mBlocksList[ 0 ];
540 SizeType blockX = block % atlasWidthInBlocks;
541 SizeType blockY = block / atlasWidthInBlocks;
542 SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
543 SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u;
545 SizeType width = image.GetWidth();
546 SizeType height = image.GetHeight();
548 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
549 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
550 blockOffsetX + SINGLE_PIXEL_PADDING,
551 blockOffsetY + SINGLE_PIXEL_PADDING ) )
553 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
557 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
561 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
565 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
567 blockOffsetY + SINGLE_PIXEL_PADDING ) )
569 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
573 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
575 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
577 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
579 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
584 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
586 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
587 blockOffsetX + width + SINGLE_PIXEL_PADDING,
588 blockOffsetY + SINGLE_PIXEL_PADDING ) )
590 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
595 void AtlasManager::GenerateMeshData( ImageId id,
596 const Vector2& position,
597 Toolkit::AtlasManager::Mesh2D& meshData,
602 // Read the atlas Id to use for this image
603 SizeType imageId = id - 1u;
604 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
605 SizeType width = mImageList[ imageId ].mImageWidth;
606 SizeType height = mImageList[ imageId ].mImageHeight;
608 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
609 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
613 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
614 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
619 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
621 // Mesh created so increase the reference count, if we're asked to
624 mImageList[ imageId ].mCount++;
629 DALI_LOG_ERROR("Cannot generate mesh with invalid AtlasId\n");
633 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
636 if ( !atlas || atlas > mAtlasList.size( ) )
639 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
642 return mAtlasList[ atlas -1u ].mAtlas;
645 bool AtlasManager::Remove( ImageId id )
647 // Decrements the reference count of this image, and removes the blocks if zero.
648 SizeType imageId = id - 1u;
649 bool removed = false;
651 if ( id > mImageList.size() )
653 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
657 // If we attempt to free an image that is already freed then do nothing, other than log
658 if ( !mImageList[ imageId ].mCount )
660 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
664 if ( 2u > --mImageList[ imageId ].mCount )
666 // 'Remove the blocks' from this image and add to the atlas' freelist
668 mImageList[ imageId ].mCount = 0;
669 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
670 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
672 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
678 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
680 if ( id && id <= mImageList.size() )
682 return mImageList[ id - 1u ].mAtlasId;
690 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
692 mNewAtlasSize = size;
694 // Add on padding for borders around atlas entries
695 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
696 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
699 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
701 if ( atlas && atlas-- <= mAtlasList.size() )
703 return mAtlasList[ atlas ].mSize;
708 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
710 if ( atlas && atlas-- <= mAtlasList.size() )
712 return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
720 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
722 return mAtlasList.size();
725 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
727 if ( !atlas || atlas > mAtlasList.size( ) )
730 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
733 return mAtlasList[ --atlas].mPixelFormat;
736 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
738 Toolkit::AtlasManager::AtlasMetricsEntry entry;
739 uint32_t textureMemoryUsed = 0;
740 uint32_t atlasCount = mAtlasList.size();
741 metrics.mAtlasCount = atlasCount;
742 metrics.mAtlasMetrics.Resize(0);
744 for ( uint32_t i = 0; i < atlasCount; ++i )
746 entry.mSize = mAtlasList[ i ].mSize;
747 entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
748 entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
749 entry.mPixelFormat = GetPixelFormat( i + 1 );
751 metrics.mAtlasMetrics.PushBack( entry );
753 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
754 if ( entry.mPixelFormat == Pixel::BGRA8888 )
759 textureMemoryUsed += size;
762 metrics.mTextureMemoryUsed = textureMemoryUsed;
765 Material AtlasManager::GetMaterial( AtlasId atlas ) const
767 if ( atlas && atlas-- <= mAtlasList.size() )
769 return mAtlasList[ atlas ].mMaterial;
775 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
777 if ( atlas && atlas-- <= mAtlasList.size() )
779 return mAtlasList[ atlas ].mSampler;
785 } // namespace Internal
787 } // namespace Toolkit