// CLASS HEADER
#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
-// EXTERNAL INCLUDES
+// EXTERNAL INCLUDE
#include <iostream>
+#include <string.h>
#include <dali/integration-api/debug.h>
namespace Dali
{
const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
const Vector2 DEFAULT_BLOCK_SIZE( 32.0f, 32.0f );
+ const uint32_t SINGLE_PIXEL_PADDING( 1u );
+ const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
}
AtlasManager::AtlasManager()
AtlasManager::~AtlasManager()
{
+ for ( uint32_t i = 0; i < mAtlasList.size(); ++i )
+ {
+ delete[] mAtlasList[ i ].mStripBuffer;
+ }
}
Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width,
// Check to see if the atlas is large enough to hold a single block even ?
if ( blockWidth > width || blockHeight > height )
{
- DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %i x %i\n",
+ DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
width, height, blockWidth, blockHeight );
return 0;
}
atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
+
+ // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
+ uint32_t neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
+ atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
+ memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
+
+ atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
+ blockWidth,
+ SINGLE_PIXEL_PADDING,
+ pixelformat );
+
+ atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
+ SINGLE_PIXEL_PADDING,
+ blockHeight - DOUBLE_PIXEL_PADDING,
+ pixelformat );
+
mAtlasList.push_back( atlasDescriptor );
return mAtlasList.size();
}
{
if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
{
- // Work out how many blocks wide and high our bitmap is in the atlas' block size
- SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
- if ( width % mAtlasList[ atlas ].mBlockWidth )
- {
- widthInBlocks++;
- }
- SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
- if ( height % mAtlasList[ atlas ].mBlockHeight )
- {
- heightInBlocks++;
- }
- blockArea = widthInBlocks * heightInBlocks;
-
// Check to see if there are any unused blocks in this atlas to accomodate our image
SizeType blocksInX = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
SizeType blocksInY = mAtlasList[ atlas ].mHeight / mAtlasList[ atlas ].mBlockHeight;
totalBlocks = blocksInX * blocksInY;
- SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ? totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u : 0;
-
- // Check to see if there are enough blocks to accomodate our sliced image ?
- if ( blockArea <= ( mAtlasList[ atlas ].mFreeBlocksList.Size() + blocksFree ) )
+ SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ?
+ totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u :
+ mAtlasList[ atlas ].mFreeBlocksList.Size();
+
+ // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
+ if ( blocksFree
+ && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
+ && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
{
- // Yes, we've found room
+ blockArea = 1u;
return ( atlas + 1u );
}
}
float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
+ // Add on texture filtering compensation
+ fBlockX += texelX;
+ fBlockY += texelY;
+
if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
{
ndcWidth = texelEdgeWidth;
MeshData& out,
bool optimize )
{
- // TODO Would be much quicker to be able to get a non-const reference to these containers and update in situ
MeshData::VertexContainer v1 = first.GetVertices();
MeshData::VertexContainer v2 = second.GetVertices();
MeshData::FaceIndices f1 = first.GetFaces();
SizeType blockOffsetX = blockX * atlasBlockWidth;
SizeType blockOffsetY = blockY * atlasBlockHeight;
- if ( !mAtlasList[ atlas ].mAtlas.Upload( image, blockOffsetX, blockOffsetY ) )
+ SizeType width = image.GetWidth();
+ SizeType height = image.GetHeight();
+
+ // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
+ blockOffsetX + SINGLE_PIXEL_PADDING,
+ blockOffsetY + SINGLE_PIXEL_PADDING ) )
+ {
+ DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
+ }
+
+ // Blit top strip
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
+ blockOffsetX,
+ blockOffsetY ) )
+ {
+ DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
+ }
+
+ // Blit left strip
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
+ blockOffsetX,
+ blockOffsetY + SINGLE_PIXEL_PADDING ) )
{
- DALI_LOG_ERROR("Uploading block to Atlas Failed!.\n");
+ DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
+ }
+
+ // Blit bottom strip
+ if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
+ {
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
+ blockOffsetX,
+ blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
+ {
+ DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
+ }
+ }
+
+ // Blit right strip
+ if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
+ {
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
+ blockOffsetX + width + SINGLE_PIXEL_PADDING,
+ blockOffsetY + SINGLE_PIXEL_PADDING ) )
+ {
+ DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
+ }
}
}
}
}
-void AtlasManager::SetAtlasSize( const Vector2& size,
- const Vector2& blockSize )
+void AtlasManager::SetNewAtlasSize( const Vector2& size,
+ const Vector2& blockSize )
{
mNewAtlasSize = size;
mNewBlockSize = blockSize;
}
}
+Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
+{
+ if ( atlas && atlas <= mAtlasList.size() )
+ {
+ return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mWidth ),
+ static_cast< float >( mAtlasList[ atlas - 1u ].mHeight ) );
+ }
+ else
+ {
+ return Vector2( 0.0f, 0.0f );
+ }
+}
+
AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
{
if ( atlas && atlas <= mAtlasList.size() )
uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
- //Work out how many blocks wide and high our bitmap is in the atlas' block size
SizeType widthInBlocks = width / blockWidth;
- if ( width % blockWidth )
- {
- widthInBlocks++;
- }
SizeType heightInBlocks = height / blockHeight;
- if ( height % blockHeight )
- {
- heightInBlocks++;
- }
-
uint32_t blockCount = widthInBlocks * heightInBlocks;
// Check free previously unallocated blocks and any free blocks
return mAtlasList[ atlas -1u ].mPixelFormat;
}
+void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
+{
+ Toolkit::AtlasManager::AtlasMetricsEntry entry;
+ uint32_t textureMemoryUsed = 0;
+ uint32_t atlasCount = mAtlasList.size();
+ metrics.mAtlasCount = atlasCount;
+ metrics.mAtlasMetrics.Resize(0);
+
+ for ( uint32_t i = 0; i < atlasCount; ++i )
+ {
+ SizeType width = mAtlasList[ i ].mWidth;
+ SizeType height = mAtlasList[ i ].mHeight;
+ SizeType blockWidth = mAtlasList[ i ].mBlockWidth;
+ SizeType blockHeight = mAtlasList[ i ].mBlockHeight;
+
+ entry.mWidth = width;
+ entry.mHeight = height;
+ entry.mBlockWidth = blockWidth;
+ entry.mBlockHeight = blockHeight;
+ entry.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
+ uint32_t reuseBlocks = mAtlasList[ i ].mFreeBlocksList.Size();
+ entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock - reuseBlocks - 1u: entry.mTotalBlocks - reuseBlocks;
+ entry.mPixelFormat = GetPixelFormat( i + 1 );
+
+ metrics.mAtlasMetrics.PushBack( entry );
+
+ uint32_t size = width * height;
+ if ( entry.mPixelFormat == Pixel::BGRA8888 )
+ {
+ size <<= 2;
+ }
+
+ textureMemoryUsed += size;
+
+ }
+ metrics.mTextureMemoryUsed = textureMemoryUsed;
+}
+
} // namespace Internal