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 ),
89 mFilledPixel( FILLED_PIXEL )
91 mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
92 mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
93 mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
94 mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
95 mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
96 mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
99 AtlasManagerPtr AtlasManager::New()
101 AtlasManagerPtr internal = new AtlasManager();
105 AtlasManager::~AtlasManager()
107 for ( SizeType i = 0; i < mAtlasList.size(); ++i )
109 mAtlasList[ i ].mAtlas.UploadedSignal().Disconnect( this, &AtlasManager::OnUpload );
110 delete[] mAtlasList[ i ].mStripBuffer;
113 // Are there any upload signals pending? Free up those buffer images now.
114 for ( SizeType i = 0; i < mUploadedImages.Size(); ++i )
116 delete[] mUploadedImages[ i ];
120 void AtlasManager::OnUpload( Image image )
122 if ( mUploadedImages.Size() )
124 delete[] mUploadedImages[ 0 ];
125 mUploadedImages.Erase( mUploadedImages.Begin() );
129 DALI_LOG_ERROR("Atlas Image Upload List should not be empty\n");
133 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
135 SizeType width = size.mWidth;
136 SizeType height = size.mHeight;
137 SizeType blockWidth = size.mBlockWidth;
138 SizeType blockHeight = size.mBlockHeight;
140 // Check to see if the atlas is large enough to hold a single block even ?
141 if ( blockWidth > width || blockHeight > height )
143 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
144 width, height, blockWidth, blockHeight );
148 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
149 atlas.Clear( Vector4::ZERO );
150 mUploadedImages.PushBack( NULL );
151 AtlasDescriptor atlasDescriptor;
152 atlasDescriptor.mAtlas = atlas;
153 atlasDescriptor.mSize = size;
154 atlasDescriptor.mPixelFormat = pixelformat;
155 atlasDescriptor.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
156 atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks - 1u;
157 atlas.UploadedSignal().Connect( this, &AtlasManager::OnUpload );
159 // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
160 SizeType neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
161 atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
162 memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
164 atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
166 SINGLE_PIXEL_PADDING,
169 atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
170 SINGLE_PIXEL_PADDING,
171 blockHeight - DOUBLE_PIXEL_PADDING,
173 mUploadedImages.PushBack( NULL );
174 atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
175 atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
177 Sampler sampler = Sampler::New( atlas, "sTexture" );
178 sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
179 atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
180 atlasDescriptor.mMaterial.AddSampler( sampler );
181 atlasDescriptor.mSampler = sampler;
182 atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
183 mAtlasList.push_back( atlasDescriptor );
184 return mAtlasList.size();
187 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
189 mAddFailPolicy = policy;
192 void AtlasManager::Add( const BufferImage& image,
193 Toolkit::AtlasManager::AtlasSlot& slot,
194 Toolkit::AtlasManager::AtlasId atlas )
196 // See if there's a slot in an atlas that matches the requirements of this image
197 // A bitmap must be sliceable into a single atlas
198 Pixel::Format pixelFormat = image.GetPixelFormat();
199 SizeType width = image.GetWidth();
200 SizeType height = image.GetHeight();
201 SizeType blockArea = 0;
202 SizeType foundAtlas = 0;
206 AtlasSlotDescriptor desc;
208 // If there is a preferred atlas then check for room in that first
211 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
214 // Search current atlases to see if there is a good match
215 while( !foundAtlas && index < mAtlasList.size() )
217 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
221 // If we can't find a suitable atlas then check the policy to determine action
224 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
226 SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
233 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea );
237 if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
239 // Haven't found an atlas for this image!!!!!!
244 // Work out where the blocks are we're going to use
245 for ( SizeType i = 0; i < blockArea; ++i )
247 // Is there currently a next free block available ?
248 if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
250 // Yes, so select our next block
251 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
255 // Our next block must be from the free list, fetch from the start of the list
256 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
257 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
261 desc.mImageWidth = width;
262 desc.mImageHeight = height;
263 desc.mAtlasId = foundAtlas + 1u;
266 // See if there's a previously freed image ID that we can assign to this new image
267 uint32_t imageId = 0u;
268 for ( uint32_t i = 0u; i < mImageList.size(); ++i )
270 if ( !mImageList[ i ].mCount )
278 mImageList.push_back( desc );
279 slot.mImageId = mImageList.size();
283 mImageList[ imageId - 1u ] = desc;
284 slot.mImageId = imageId;
286 slot.mAtlasId = foundAtlas + 1u;
287 UploadImage( image, desc );
290 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
293 Pixel::Format pixelFormat,
294 SizeType& blockArea )
296 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
298 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
299 if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
300 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
301 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
304 return ( atlas + 1u );
310 void AtlasManager::CreateMesh( SizeType atlas,
312 SizeType imageHeight,
313 const Vector2& position,
314 SizeType widthInBlocks,
315 SizeType heightInBlocks,
316 Toolkit::AtlasManager::Mesh2D& mesh,
317 AtlasSlotDescriptor& desc )
319 Toolkit::AtlasManager::Vertex2D vertex;
320 uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
322 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
323 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
325 float vertexBlockWidth = static_cast< float >( blockWidth );
326 float vertexBlockHeight = static_cast< float >( blockHeight );
328 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
329 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
331 SizeType atlasWidthInBlocks = width / blockWidth;
333 // Get the normalized size of a texel in both directions
334 // TODO when texture resizing and passing texture size via uniforms is available,
335 // we will encode pixel positions into the vertex data rather than normalized
336 // meaning that geometry needn't be changed on an atlas resize
337 float texelX = 1.0f / static_cast< float >( width );
338 float texelY = 1.0f / static_cast< float >( height );
340 float halfTexelX = texelX * 0.5f;
341 float halfTexelY = texelY * 0.5f;
343 // Get the normalized size of a block in texels
344 float texelBlockWidth = texelX * vertexBlockWidth;
345 float texelBlockHeight = texelY * vertexBlockHeight;
347 // Get partial block space
348 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
349 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
352 float texelEdgeWidth = texelX * vertexEdgeWidth;
353 float texelEdgeHeight = texelY * vertexEdgeHeight;
355 // We're going to 'blit' half a pixel more on each edge
361 // Block by block create the two triangles for the quad
362 SizeType blockIndex = 0;
368 // Move back half a pixel
369 Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
371 for ( SizeType y = 0; y < heightInBlocks; ++y )
374 float currentX = position.x;
376 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
378 ndcHeight = texelEdgeHeight + texelY;
379 ndcVHeight = vertexEdgeHeight;
383 ndcHeight = texelBlockHeight + texelY;
384 ndcVHeight = vertexBlockHeight;
387 for ( SizeType x = 0; x < widthInBlocks; ++x )
389 SizeType block = desc.mBlocksList[ blockIndex++ ];
391 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
392 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
394 // Add on texture filtering compensation
395 fBlockX += halfTexelX;
396 fBlockY += halfTexelY;
398 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
400 ndcWidth = texelEdgeWidth + texelX;
401 ndcVWidth = vertexEdgeWidth;
405 ndcWidth = texelBlockWidth + texelX;
406 ndcVWidth = vertexBlockWidth;
410 vertex.mPosition.x = topLeft.x;
411 vertex.mPosition.y = topLeft.y;
412 vertex.mTexCoords.x = fBlockX;
413 vertex.mTexCoords.y = fBlockY;
415 mesh.mVertices.PushBack( vertex );
418 vertex.mPosition.x = topLeft.x + ndcVWidth;
419 vertex.mPosition.y = topLeft.y;
420 vertex.mTexCoords.x = fBlockX + ndcWidth;
421 vertex.mTexCoords.y = fBlockY;
423 mesh.mVertices.PushBack( vertex );
426 vertex.mPosition.x = topLeft.x;
427 vertex.mPosition.y = topLeft.y + ndcVHeight;
428 vertex.mTexCoords.x = fBlockX;
429 vertex.mTexCoords.y = fBlockY + ndcHeight;
431 mesh.mVertices.PushBack( vertex );
434 topLeft.x += ndcVWidth;
435 vertex.mPosition.x = topLeft.x;
436 vertex.mPosition.y = topLeft.y + ndcVHeight;
437 vertex.mTexCoords.x = fBlockX + ndcWidth;
438 vertex.mTexCoords.y = fBlockY + ndcHeight;
440 mesh.mVertices.PushBack( vertex );
442 // Six indices in counter clockwise winding
443 mesh.mIndices.PushBack( faceIndex + 1u );
444 mesh.mIndices.PushBack( faceIndex );
445 mesh.mIndices.PushBack( faceIndex + 2u );
446 mesh.mIndices.PushBack( faceIndex + 2u );
447 mesh.mIndices.PushBack( faceIndex + 3u );
448 mesh.mIndices.PushBack( faceIndex + 1u );
453 topLeft.x = currentX;
454 topLeft.y += vertexBlockHeight;
457 // If there's only one block then skip this next vertex optimisation
458 if ( widthInBlocks * heightInBlocks > 1 )
460 Toolkit::AtlasManager::Mesh2D optimizedMesh;
461 OptimizeMesh( mesh, optimizedMesh );
465 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
467 uint32_t vertexCount = mesh.mVertices.Size();
468 uint32_t indexCount = mesh.mIndices.Size();
469 std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
470 std::cout << ", Triangles = " << indexCount / 3 << std::endl;
472 for ( SizeType v = 0; v < vertexCount; ++v )
474 std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
475 std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
476 std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
477 std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
480 std::cout << "\n Indices: ";
481 for ( SizeType i = 0; i < indexCount; ++i )
483 std::cout << " " << mesh.mIndices[ i ];
485 std::cout << std::endl;
488 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
489 Toolkit::AtlasManager::Mesh2D& out )
491 unsigned short vertexIndex = 0;
493 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
494 for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
496 // Fetch a vertex, has it already been assigned?
497 bool foundVertex = false;
498 Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
499 for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
501 if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
502 ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
503 ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
504 ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
506 // Yes, so store this down as the vertex to use
507 out.mIndices.PushBack( j );
513 // Did we find a vertex ?
516 // No so add a new one
517 out.mVertices.PushBack( v );
523 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
524 const Toolkit::AtlasManager::Mesh2D& second,
527 uint32_t vc = first.mVertices.Size();
529 for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
531 first.mVertices.PushBack( second.mVertices[ v ] );
534 for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
536 first.mIndices.PushBack( second.mIndices[ i ] + vc );
541 Toolkit::AtlasManager::Mesh2D optimizedMesh;
542 OptimizeMesh( first, optimizedMesh );
543 first = optimizedMesh;
547 void AtlasManager::StitchMesh( const Toolkit::AtlasManager::Mesh2D& first,
548 const Toolkit::AtlasManager::Mesh2D& second,
549 Toolkit::AtlasManager::Mesh2D& out,
552 uint32_t vc = first.mVertices.Size();
554 for ( uint32_t v = 0; v < vc; ++v )
556 out.mVertices.PushBack( first.mVertices[ v ] );
559 for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
561 out.mVertices.PushBack( second.mVertices[ v ] );
564 for ( uint32_t i = 0; i < first.mIndices.Size(); ++i )
566 out.mIndices.PushBack( first.mIndices[ i ] );
569 for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
571 out.mIndices.PushBack( second.mIndices[ i ] + vc );
576 Toolkit::AtlasManager::Mesh2D optimizedMesh;
577 OptimizeMesh( out, optimizedMesh );
582 void AtlasManager::UploadImage( const BufferImage& image,
583 const AtlasSlotDescriptor& desc )
585 // Get the atlas to upload the image to
586 SizeType atlas = desc.mAtlasId - 1u;
588 // Check to see that the pixel formats are compatible
589 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
591 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
595 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
596 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
597 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
599 SizeType block = desc.mBlocksList[ 0 ];
600 SizeType blockX = block % atlasWidthInBlocks;
601 SizeType blockY = block / atlasWidthInBlocks;
602 SizeType blockOffsetX = blockX * atlasBlockWidth;
603 SizeType blockOffsetY = blockY * atlasBlockHeight;
605 SizeType width = image.GetWidth();
606 SizeType height = image.GetHeight();
608 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
609 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
610 blockOffsetX + SINGLE_PIXEL_PADDING,
611 blockOffsetY + SINGLE_PIXEL_PADDING ) )
613 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
617 mUploadedImages.PushBack( const_cast< BufferImage& >( image ).GetBuffer() );
621 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
625 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
629 mUploadedImages.PushBack( NULL );
633 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
635 blockOffsetY + SINGLE_PIXEL_PADDING ) )
637 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
641 mUploadedImages.PushBack( NULL );
645 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
647 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
649 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
651 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
655 mUploadedImages.PushBack( NULL );
660 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
662 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
663 blockOffsetX + width + SINGLE_PIXEL_PADDING,
664 blockOffsetY + SINGLE_PIXEL_PADDING ) )
666 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
670 mUploadedImages.PushBack( NULL );
675 void AtlasManager::GenerateMeshData( ImageId id,
676 const Vector2& position,
677 Toolkit::AtlasManager::Mesh2D& meshData,
680 // Read the atlas Id to use for this image
681 SizeType imageId = id - 1u;
682 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
683 SizeType width = mImageList[ imageId ].mImageWidth;
684 SizeType height = mImageList[ imageId ].mImageHeight;
686 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
687 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
691 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
692 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
697 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
699 // Mesh created so increase the reference count, if we're asked to
702 mImageList[ imageId ].mCount++;
706 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
709 if ( !atlas || atlas > mAtlasList.size( ) )
712 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
715 return mAtlasList[ atlas -1u ].mAtlas;
718 bool AtlasManager::Remove( ImageId id )
720 // Decrements the reference count of this image, and removes the blocks if zero.
721 SizeType imageId = id - 1u;
722 bool removed = false;
724 if ( id > mImageList.size() )
726 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
730 // If we attempt to free an image that is already freed then do nothing, other than log
731 if ( !mImageList[ imageId ].mCount )
733 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
737 if ( 2u > --mImageList[ imageId ].mCount )
739 // 'Remove the blocks' from this image and add to the atlas' freelist
741 mImageList[ imageId ].mCount = 0;
742 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
743 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
745 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
751 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
753 if ( id && id <= mImageList.size() )
755 return mImageList[ id - 1u ].mAtlasId;
763 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
765 mNewAtlasSize = size;
766 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
767 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
770 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
772 if ( atlas && atlas-- <= mAtlasList.size() )
774 return mAtlasList[ atlas ].mSize;
779 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
781 if ( atlas && atlas-- <= mAtlasList.size() )
783 return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
791 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
793 return mAtlasList.size();
796 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
798 if ( !atlas || atlas > mAtlasList.size( ) )
801 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
804 return mAtlasList[ --atlas].mPixelFormat;
807 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
809 Toolkit::AtlasManager::AtlasMetricsEntry entry;
810 uint32_t textureMemoryUsed = 0;
811 uint32_t atlasCount = mAtlasList.size();
812 metrics.mAtlasCount = atlasCount;
813 metrics.mAtlasMetrics.Resize(0);
815 for ( uint32_t i = 0; i < atlasCount; ++i )
817 entry.mSize = mAtlasList[ i ].mSize;
818 entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
819 entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
820 entry.mPixelFormat = GetPixelFormat( i + 1 );
822 metrics.mAtlasMetrics.PushBack( entry );
824 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
825 if ( entry.mPixelFormat == Pixel::BGRA8888 )
830 textureMemoryUsed += size;
833 metrics.mTextureMemoryUsed = textureMemoryUsed;
836 Material AtlasManager::GetMaterial( AtlasId atlas ) const
838 if ( atlas && atlas-- <= mAtlasList.size() )
840 return mAtlasList[ atlas ].mMaterial;
846 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
848 if ( atlas && atlas-- <= mAtlasList.size() )
850 return mAtlasList[ atlas ].mSampler;
856 } // namespace Internal
858 } // namespace Toolkit