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 uniform mediump vec3 uSize;
54 varying mediump vec2 vTexCoord;
58 mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
59 position.xyz *= uSize;
60 gl_Position = uMvpMatrix * position;
61 vTexCoord = aTexCoord;
65 const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
66 uniform lowp vec4 uColor;
67 uniform sampler2D sTexture;
68 varying mediump vec2 vTexCoord;
72 mediump vec4 color = texture2D( sTexture, vTexCoord );
73 gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
77 const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
78 uniform sampler2D sTexture;
79 varying mediump vec2 vTexCoord;
83 gl_FragColor = texture2D( sTexture, vTexCoord );
89 AtlasManager::AtlasManager()
90 : mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
91 mFilledPixel( FILLED_PIXEL )
93 mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
94 mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
95 mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
96 mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
97 mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
98 mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
101 AtlasManagerPtr AtlasManager::New()
103 AtlasManagerPtr internal = new AtlasManager();
107 AtlasManager::~AtlasManager()
109 for ( SizeType i = 0; i < mAtlasList.size(); ++i )
111 mAtlasList[ i ].mAtlas.UploadedSignal().Disconnect( this, &AtlasManager::OnUpload );
112 delete[] mAtlasList[ i ].mStripBuffer;
115 // Are there any upload signals pending? Free up those buffer images now.
116 for ( SizeType i = 0; i < mUploadedImages.Size(); ++i )
118 delete[] mUploadedImages[ i ];
122 void AtlasManager::OnUpload( Image image )
124 if ( mUploadedImages.Size() )
126 delete[] mUploadedImages[ 0 ];
127 mUploadedImages.Erase( mUploadedImages.Begin() );
131 DALI_LOG_ERROR("Atlas Image Upload List should not be empty\n");
135 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
137 SizeType width = size.mWidth;
138 SizeType height = size.mHeight;
139 SizeType blockWidth = size.mBlockWidth;
140 SizeType blockHeight = size.mBlockHeight;
142 // Check to see if the atlas is large enough to hold a single block even ?
143 if ( blockWidth > width || blockHeight > height )
145 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
146 width, height, blockWidth, blockHeight );
150 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
151 atlas.Clear( Vector4::ZERO );
152 mUploadedImages.PushBack( NULL );
153 AtlasDescriptor atlasDescriptor;
154 atlasDescriptor.mAtlas = atlas;
155 atlasDescriptor.mSize = size;
156 atlasDescriptor.mPixelFormat = pixelformat;
157 atlasDescriptor.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
158 atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks - 1u;
159 atlas.UploadedSignal().Connect( this, &AtlasManager::OnUpload );
161 // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
162 SizeType neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
163 atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
164 memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
166 atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
168 SINGLE_PIXEL_PADDING,
171 atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
172 SINGLE_PIXEL_PADDING,
173 blockHeight - DOUBLE_PIXEL_PADDING,
175 mUploadedImages.PushBack( NULL );
176 atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
177 atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
179 Sampler sampler = Sampler::New( atlas, "sTexture" );
180 sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
181 atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
182 atlasDescriptor.mMaterial.AddSampler( sampler );
183 atlasDescriptor.mSampler = sampler;
184 atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
185 mAtlasList.push_back( atlasDescriptor );
186 return mAtlasList.size();
189 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
191 mAddFailPolicy = policy;
194 void AtlasManager::Add( const BufferImage& image,
195 Toolkit::AtlasManager::AtlasSlot& slot,
196 Toolkit::AtlasManager::AtlasId atlas )
198 // See if there's a slot in an atlas that matches the requirements of this image
199 // A bitmap must be sliceable into a single atlas
200 Pixel::Format pixelFormat = image.GetPixelFormat();
201 SizeType width = image.GetWidth();
202 SizeType height = image.GetHeight();
203 SizeType blockArea = 0;
204 SizeType foundAtlas = 0;
208 AtlasSlotDescriptor desc;
210 // If there is a preferred atlas then check for room in that first
213 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
216 // Search current atlases to see if there is a good match
217 while( !foundAtlas && index < mAtlasList.size() )
219 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
223 // If we can't find a suitable atlas then check the policy to determine action
226 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
228 SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
235 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea );
239 if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
241 // Haven't found an atlas for this image!!!!!!
246 // Work out where the blocks are we're going to use
247 for ( SizeType i = 0; i < blockArea; ++i )
249 // Is there currently a next free block available ?
250 if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
252 // Yes, so select our next block
253 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
257 // Our next block must be from the free list, fetch from the start of the list
258 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
259 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
263 desc.mImageWidth = width;
264 desc.mImageHeight = height;
265 desc.mAtlasId = foundAtlas + 1u;
268 // See if there's a previously freed image ID that we can assign to this new image
269 uint32_t imageId = 0u;
270 for ( uint32_t i = 0u; i < mImageList.size(); ++i )
272 if ( !mImageList[ i ].mCount )
280 mImageList.push_back( desc );
281 slot.mImageId = mImageList.size();
285 mImageList[ imageId - 1u ] = desc;
286 slot.mImageId = imageId;
288 slot.mAtlasId = foundAtlas + 1u;
289 UploadImage( image, desc );
292 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
295 Pixel::Format pixelFormat,
296 SizeType& blockArea )
298 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
300 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
301 if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
302 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
303 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
306 return ( atlas + 1u );
312 void AtlasManager::CreateMesh( SizeType atlas,
314 SizeType imageHeight,
315 const Vector2& position,
316 SizeType widthInBlocks,
317 SizeType heightInBlocks,
318 Toolkit::AtlasManager::Mesh2D& mesh,
319 AtlasSlotDescriptor& desc )
321 Toolkit::AtlasManager::Vertex2D vertex;
322 uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
324 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
325 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
327 float vertexBlockWidth = static_cast< float >( blockWidth );
328 float vertexBlockHeight = static_cast< float >( blockHeight );
330 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
331 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
333 SizeType atlasWidthInBlocks = width / blockWidth;
335 // Get the normalized size of a texel in both directions
336 // TODO when texture resizing and passing texture size via uniforms is available,
337 // we will encode pixel positions into the vertex data rather than normalized
338 // meaning that geometry needn't be changed on an atlas resize
339 float texelX = 1.0f / static_cast< float >( width );
340 float texelY = 1.0f / static_cast< float >( height );
342 float halfTexelX = texelX * 0.5f;
343 float halfTexelY = texelY * 0.5f;
345 // Get the normalized size of a block in texels
346 float texelBlockWidth = texelX * vertexBlockWidth;
347 float texelBlockHeight = texelY * vertexBlockHeight;
349 // Get partial block space
350 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
351 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
354 float texelEdgeWidth = texelX * vertexEdgeWidth;
355 float texelEdgeHeight = texelY * vertexEdgeHeight;
357 // We're going to 'blit' half a pixel more on each edge
363 // Block by block create the two triangles for the quad
364 SizeType blockIndex = 0;
370 // Move back half a pixel
371 Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
373 for ( SizeType y = 0; y < heightInBlocks; ++y )
376 float currentX = position.x;
378 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
380 ndcHeight = texelEdgeHeight + texelY;
381 ndcVHeight = vertexEdgeHeight;
385 ndcHeight = texelBlockHeight + texelY;
386 ndcVHeight = vertexBlockHeight;
389 for ( SizeType x = 0; x < widthInBlocks; ++x )
391 SizeType block = desc.mBlocksList[ blockIndex++ ];
393 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
394 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
396 // Add on texture filtering compensation
397 fBlockX += halfTexelX;
398 fBlockY += halfTexelY;
400 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
402 ndcWidth = texelEdgeWidth + texelX;
403 ndcVWidth = vertexEdgeWidth;
407 ndcWidth = texelBlockWidth + texelX;
408 ndcVWidth = vertexBlockWidth;
412 vertex.mPosition.x = topLeft.x;
413 vertex.mPosition.y = topLeft.y;
414 vertex.mTexCoords.x = fBlockX;
415 vertex.mTexCoords.y = fBlockY;
417 mesh.mVertices.PushBack( vertex );
420 vertex.mPosition.x = topLeft.x + ndcVWidth;
421 vertex.mPosition.y = topLeft.y;
422 vertex.mTexCoords.x = fBlockX + ndcWidth;
423 vertex.mTexCoords.y = fBlockY;
425 mesh.mVertices.PushBack( vertex );
428 vertex.mPosition.x = topLeft.x;
429 vertex.mPosition.y = topLeft.y + ndcVHeight;
430 vertex.mTexCoords.x = fBlockX;
431 vertex.mTexCoords.y = fBlockY + ndcHeight;
433 mesh.mVertices.PushBack( vertex );
436 topLeft.x += ndcVWidth;
437 vertex.mPosition.x = topLeft.x;
438 vertex.mPosition.y = topLeft.y + ndcVHeight;
439 vertex.mTexCoords.x = fBlockX + ndcWidth;
440 vertex.mTexCoords.y = fBlockY + ndcHeight;
442 mesh.mVertices.PushBack( vertex );
444 // Six indices in counter clockwise winding
445 mesh.mIndices.PushBack( faceIndex + 1u );
446 mesh.mIndices.PushBack( faceIndex );
447 mesh.mIndices.PushBack( faceIndex + 2u );
448 mesh.mIndices.PushBack( faceIndex + 2u );
449 mesh.mIndices.PushBack( faceIndex + 3u );
450 mesh.mIndices.PushBack( faceIndex + 1u );
455 topLeft.x = currentX;
456 topLeft.y += vertexBlockHeight;
459 // If there's only one block then skip this next vertex optimisation
460 if ( widthInBlocks * heightInBlocks > 1 )
462 Toolkit::AtlasManager::Mesh2D optimizedMesh;
463 OptimizeMesh( mesh, optimizedMesh );
467 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
469 uint32_t vertexCount = mesh.mVertices.Size();
470 uint32_t indexCount = mesh.mIndices.Size();
471 std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
472 std::cout << ", Triangles = " << indexCount / 3 << std::endl;
474 for ( SizeType v = 0; v < vertexCount; ++v )
476 std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
477 std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
478 std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
479 std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
482 std::cout << "\n Indices: ";
483 for ( SizeType i = 0; i < indexCount; ++i )
485 std::cout << " " << mesh.mIndices[ i ];
487 std::cout << std::endl;
490 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
491 Toolkit::AtlasManager::Mesh2D& out )
493 unsigned short vertexIndex = 0;
495 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
496 for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
498 // Fetch a vertex, has it already been assigned?
499 bool foundVertex = false;
500 Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
501 for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
503 if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
504 ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
505 ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
506 ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
508 // Yes, so store this down as the vertex to use
509 out.mIndices.PushBack( j );
515 // Did we find a vertex ?
518 // No so add a new one
519 out.mVertices.PushBack( v );
525 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
526 const Toolkit::AtlasManager::Mesh2D& second,
529 uint32_t vc = first.mVertices.Size();
531 for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
533 first.mVertices.PushBack( second.mVertices[ v ] );
536 for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
538 first.mIndices.PushBack( second.mIndices[ i ] + vc );
543 Toolkit::AtlasManager::Mesh2D optimizedMesh;
544 OptimizeMesh( first, optimizedMesh );
545 first = optimizedMesh;
549 void AtlasManager::StitchMesh( const Toolkit::AtlasManager::Mesh2D& first,
550 const Toolkit::AtlasManager::Mesh2D& second,
551 Toolkit::AtlasManager::Mesh2D& out,
554 uint32_t vc = first.mVertices.Size();
556 for ( uint32_t v = 0; v < vc; ++v )
558 out.mVertices.PushBack( first.mVertices[ v ] );
561 for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
563 out.mVertices.PushBack( second.mVertices[ v ] );
566 for ( uint32_t i = 0; i < first.mIndices.Size(); ++i )
568 out.mIndices.PushBack( first.mIndices[ i ] );
571 for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
573 out.mIndices.PushBack( second.mIndices[ i ] + vc );
578 Toolkit::AtlasManager::Mesh2D optimizedMesh;
579 OptimizeMesh( out, optimizedMesh );
584 void AtlasManager::UploadImage( const BufferImage& image,
585 const AtlasSlotDescriptor& desc )
587 // Get the atlas to upload the image to
588 SizeType atlas = desc.mAtlasId - 1u;
590 // Check to see that the pixel formats are compatible
591 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
593 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
597 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
598 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
599 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
601 SizeType block = desc.mBlocksList[ 0 ];
602 SizeType blockX = block % atlasWidthInBlocks;
603 SizeType blockY = block / atlasWidthInBlocks;
604 SizeType blockOffsetX = blockX * atlasBlockWidth;
605 SizeType blockOffsetY = blockY * atlasBlockHeight;
607 SizeType width = image.GetWidth();
608 SizeType height = image.GetHeight();
610 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
611 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
612 blockOffsetX + SINGLE_PIXEL_PADDING,
613 blockOffsetY + SINGLE_PIXEL_PADDING ) )
615 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
619 mUploadedImages.PushBack( const_cast< BufferImage& >( image ).GetBuffer() );
623 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
627 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
631 mUploadedImages.PushBack( NULL );
635 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
637 blockOffsetY + SINGLE_PIXEL_PADDING ) )
639 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
643 mUploadedImages.PushBack( NULL );
647 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
649 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
651 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
653 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
657 mUploadedImages.PushBack( NULL );
662 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
664 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
665 blockOffsetX + width + SINGLE_PIXEL_PADDING,
666 blockOffsetY + SINGLE_PIXEL_PADDING ) )
668 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
672 mUploadedImages.PushBack( NULL );
677 void AtlasManager::GenerateMeshData( ImageId id,
678 const Vector2& position,
679 Toolkit::AtlasManager::Mesh2D& meshData,
682 // Read the atlas Id to use for this image
683 SizeType imageId = id - 1u;
684 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
685 SizeType width = mImageList[ imageId ].mImageWidth;
686 SizeType height = mImageList[ imageId ].mImageHeight;
688 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
689 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
693 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
694 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
699 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
701 // Mesh created so increase the reference count, if we're asked to
704 mImageList[ imageId ].mCount++;
708 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
711 if ( !atlas || atlas > mAtlasList.size( ) )
714 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
717 return mAtlasList[ atlas -1u ].mAtlas;
720 bool AtlasManager::Remove( ImageId id )
722 // Decrements the reference count of this image, and removes the blocks if zero.
723 SizeType imageId = id - 1u;
724 bool removed = false;
726 if ( id > mImageList.size() )
728 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
732 // If we attempt to free an image that is already freed then do nothing, other than log
733 if ( !mImageList[ imageId ].mCount )
735 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
739 if ( 2u > --mImageList[ imageId ].mCount )
741 // 'Remove the blocks' from this image and add to the atlas' freelist
743 mImageList[ imageId ].mCount = 0;
744 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
745 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
747 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
753 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
755 if ( id && id <= mImageList.size() )
757 return mImageList[ id - 1u ].mAtlasId;
765 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
767 mNewAtlasSize = size;
768 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
769 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
772 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
774 if ( atlas && atlas-- <= mAtlasList.size() )
776 return mAtlasList[ atlas ].mSize;
781 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
783 if ( atlas && atlas-- <= mAtlasList.size() )
785 return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
793 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
795 return mAtlasList.size();
798 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
800 if ( !atlas || atlas > mAtlasList.size( ) )
803 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
806 return mAtlasList[ --atlas].mPixelFormat;
809 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
811 Toolkit::AtlasManager::AtlasMetricsEntry entry;
812 uint32_t textureMemoryUsed = 0;
813 uint32_t atlasCount = mAtlasList.size();
814 metrics.mAtlasCount = atlasCount;
815 metrics.mAtlasMetrics.Resize(0);
817 for ( uint32_t i = 0; i < atlasCount; ++i )
819 entry.mSize = mAtlasList[ i ].mSize;
820 entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
821 entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
822 entry.mPixelFormat = GetPixelFormat( i + 1 );
824 metrics.mAtlasMetrics.PushBack( entry );
826 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
827 if ( entry.mPixelFormat == Pixel::BGRA8888 )
832 textureMemoryUsed += size;
835 metrics.mTextureMemoryUsed = textureMemoryUsed;
838 Material AtlasManager::GetMaterial( AtlasId atlas ) const
840 if ( atlas && atlas-- <= mAtlasList.size() )
842 return mAtlasList[ atlas ].mMaterial;
848 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
850 if ( atlas && atlas-- <= mAtlasList.size() )
852 return mAtlasList[ atlas ].mSampler;
858 } // namespace Internal
860 } // namespace Toolkit