// EXTERNAL INCLUDE
#include <iostream>
#include <string.h>
+#include <dali/devel-api/rendering/sampler.h>
+#include <dali/devel-api/rendering/shader.h>
#include <dali/integration-api/debug.h>
namespace Dali
namespace
{
- const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
- const Vector2 DEFAULT_BLOCK_SIZE( 32.0f, 32.0f );
- const uint32_t PIXEL_PADDING( 2u );
+ const uint32_t DEFAULT_ATLAS_WIDTH( 512u );
+ const uint32_t DEFAULT_ATLAS_HEIGHT( 512u );
+ const uint32_t DEFAULT_BLOCK_WIDTH( 16u );
+ const uint32_t DEFAULT_BLOCK_HEIGHT( 16u );
+ const uint32_t SINGLE_PIXEL_PADDING( 1u );
+ const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
+ const uint32_t FILLED_PIXEL( -1 );
+ Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
+
+ #define MAKE_SHADER(A)#A
+
+ const char* VERTEX_SHADER = MAKE_SHADER(
+ attribute mediump vec2 aPosition;
+ attribute mediump vec2 aTexCoord;
+ uniform mediump mat4 uMvpMatrix;
+ varying mediump vec2 vTexCoord;
+
+ void main()
+ {
+ mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
+ gl_Position = uMvpMatrix * position;
+ vTexCoord = aTexCoord;
+ }
+ );
+
+ const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
+ uniform lowp vec4 uColor;
+ uniform sampler2D sTexture;
+ varying mediump vec2 vTexCoord;
+
+ void main()
+ {
+ mediump vec4 color = texture2D( sTexture, vTexCoord );
+ gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
+ }
+ );
+
+ const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
+ uniform sampler2D sTexture;
+ varying mediump vec2 vTexCoord;
+
+ void main()
+ {
+ gl_FragColor = texture2D( sTexture, vTexCoord );
+ }
+ );
+
}
AtlasManager::AtlasManager()
-: mNewAtlasSize( DEFAULT_ATLAS_SIZE ),
- mNewBlockSize( DEFAULT_BLOCK_SIZE ),
- mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
- mEdgeBuffer( NULL ),
- mEdgeBufferSize( 0 )
+: mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES )
{
+ mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
+ mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
+ mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
+ mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
+ mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
+ mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
}
AtlasManagerPtr AtlasManager::New()
AtlasManager::~AtlasManager()
{
- delete[] mEdgeBuffer;
}
-Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width,
- SizeType height,
- SizeType blockWidth,
- SizeType blockHeight,
- Pixel::Format pixelformat )
+Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
{
+ SizeType width = size.mWidth;
+ SizeType height = size.mHeight;
+ SizeType blockWidth = size.mBlockWidth;
+ SizeType blockHeight = size.mBlockHeight;
+
// Check to see if the atlas is large enough to hold a single block even ?
- if ( blockWidth > width || blockHeight > height )
+ if ( blockWidth + DOUBLE_PIXEL_PADDING + 1u > width || blockHeight + DOUBLE_PIXEL_PADDING + 1u > height )
{
DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
- width, height, blockWidth, blockHeight );
+ width, height, blockWidth + DOUBLE_PIXEL_PADDING + 1u, blockHeight + DOUBLE_PIXEL_PADDING + 1u );
return 0;
}
Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
+ atlas.Clear( Vector4::ZERO );
AtlasDescriptor atlasDescriptor;
atlasDescriptor.mAtlas = atlas;
- atlasDescriptor.mWidth = width;
- atlasDescriptor.mHeight = height;
- atlasDescriptor.mBlockWidth = blockWidth;
- atlasDescriptor.mBlockHeight = blockHeight;
+ atlasDescriptor.mSize = size;
atlasDescriptor.mPixelFormat = pixelformat;
- std::stringstream materialLabel;
- materialLabel << "Atlas Material - ";
- materialLabel << mAtlasList.size();
- atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
- atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
- atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
+ atlasDescriptor.mTotalBlocks = ( ( width - 1u ) / blockWidth ) * ( ( height - 1u ) / blockHeight );
+ atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks;
- // What size do we need for this atlas' edge buffer ( assume RGBA pixel format )?
- uint32_t neededEdgeSize = ( blockWidth > blockHeight ? blockWidth : blockHeight ) << 2;
+ atlasDescriptor.mHorizontalStrip = BufferImage::New( blockWidth, SINGLE_PIXEL_PADDING, pixelformat );
+ atlasDescriptor.mVerticalStrip = BufferImage::New( SINGLE_PIXEL_PADDING, blockHeight - DOUBLE_PIXEL_PADDING, pixelformat );
- // Is the current edge buffer large enough?
- if ( neededEdgeSize > mEdgeBufferSize )
+ PixelBuffer* buffer = atlasDescriptor.mHorizontalStrip.GetBuffer();
+ if( buffer == NULL )
{
- delete[] mEdgeBuffer;
- mEdgeBuffer = new PixelBuffer[ neededEdgeSize ];
- memset( mEdgeBuffer, 0, neededEdgeSize );
- mEdgeBufferSize = neededEdgeSize;
+ DALI_LOG_ERROR("atlasDescriptor.mHorizontalStrip.GetBuffer() returns NULL\n");
+ return 0;
}
+ memset( buffer, 0, atlasDescriptor.mHorizontalStrip.GetBufferSize() );
- atlasDescriptor.mEdgeX = BufferImage::New( mEdgeBuffer, blockWidth, PIXEL_PADDING, pixelformat );
- atlasDescriptor.mEdgeY = BufferImage::New( mEdgeBuffer, PIXEL_PADDING, blockHeight, pixelformat );
+ buffer = atlasDescriptor.mVerticalStrip.GetBuffer();
+ if( buffer == NULL )
+ {
+ DALI_LOG_ERROR("atlasDescriptor.mVerticalStrip.GetBuffer() returns NULL\n");
+ return 0;
+ }
+ memset( buffer, 0, atlasDescriptor.mVerticalStrip.GetBufferSize() );
+
+ BufferImage filledPixelImage = BufferImage::New( 1u, 1u, pixelformat );
+ buffer = filledPixelImage.GetBuffer();
+ if( buffer == NULL)
+ {
+ DALI_LOG_ERROR("filledPixelImage.GetBuffer() returns NULL\n");
+ return 0;
+ }
+
+ memset( buffer, 0xFF, filledPixelImage.GetBufferSize() );
+ atlas.Upload( filledPixelImage, 0, 0 );
+ Sampler sampler = Sampler::New( atlas, "sTexture" );
+ sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
+ atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
+ atlasDescriptor.mMaterial.AddSampler( sampler );
+ atlasDescriptor.mSampler = sampler;
+ atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
mAtlasList.push_back( atlasDescriptor );
return mAtlasList.size();
}
SizeType width = image.GetWidth();
SizeType height = image.GetHeight();
SizeType blockArea = 0;
- SizeType totalBlocks = 0;
SizeType foundAtlas = 0;
SizeType index = 0;
slot.mImageId = 0;
// If there is a preferred atlas then check for room in that first
if ( atlas-- )
{
- foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
+ foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
}
// Search current atlases to see if there is a good match
-
while( !foundAtlas && index < mAtlasList.size() )
{
- foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
+ foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
++index;
}
{
if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
{
- SizeType newAtlas = CreateAtlas( mNewAtlasSize.x, mNewAtlasSize.y, mNewBlockSize.x, mNewBlockSize.y, pixelFormat );
- if ( !newAtlas-- )
+ foundAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
+ if ( !foundAtlas-- )
{
+ DALI_LOG_ERROR("Failed to create an atlas of %i x %i blocksize: %i x %i.\n",
+ mNewAtlasSize.mWidth,
+ mNewAtlasSize.mHeight,
+ mNewAtlasSize.mBlockWidth,
+ mNewAtlasSize.mBlockHeight );
return;
}
- else
- {
- foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
- }
+
+ foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea );
}
- if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
+ if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
{
// Haven't found an atlas for this image!!!!!!
- return;
+ DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
+ return;
}
}
for ( SizeType i = 0; i < blockArea; ++i )
{
// Is there currently a next free block available ?
- if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
+ if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
{
- // Yes, so use this for our next block
- SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
- desc.mBlocksList.PushBack( selectedBlock );
-
- // Any blocks going to be available after this one (adjust to store +1 )?
- selectedBlock++;
- selectedBlock++;
- if ( selectedBlock > totalBlocks )
- {
- // No so start trying to use free blocks list
- selectedBlock = 0;
- }
- mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
+ // Yes, so select our next block
+ desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
}
else
{
desc.mCount = 1u;
// See if there's a previously freed image ID that we can assign to this new image
- uint32_t imageId = 0;
- for ( uint32_t i = 0; i < mImageList.size(); ++i )
+ uint32_t imageId = 0u;
+ for ( uint32_t i = 0u; i < mImageList.size(); ++i )
{
if ( !mImageList[ i ].mCount )
{
SizeType width,
SizeType height,
Pixel::Format pixelFormat,
- SizeType& blockArea,
- SizeType& totalBlocks )
+ SizeType& blockArea )
{
if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
{
- // 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 the image will fit in these blocks, if not we'll need to create a new atlas
- if ( blocksFree
- && width + PIXEL_PADDING <= mAtlasList[ atlas ].mBlockWidth
- && height + PIXEL_PADDING <= mAtlasList[ atlas ].mBlockHeight )
+ if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
+ && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
+ && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
{
blockArea = 1u;
return ( atlas + 1u );
}
}
- return 0;
+ return 0u;
}
void AtlasManager::CreateMesh( SizeType atlas,
const Vector2& position,
SizeType widthInBlocks,
SizeType heightInBlocks,
- Dali::MeshData& meshData,
+ Toolkit::AtlasManager::Mesh2D& mesh,
AtlasSlotDescriptor& desc )
{
- Dali::MeshData::Vertex vertex;
- Dali::MeshData::VertexContainer vertices;
- Dali::MeshData::FaceIndices faces;
- Dali::MeshData::FaceIndex faceIndex = 0;
- meshData.SetHasNormals( false );
- meshData.SetHasColor( true );
- meshData.SetHasTextureCoords( true );
+ Toolkit::AtlasManager::Vertex2D vertex;
+ uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
- SizeType blockWidth = mAtlasList[ atlas ].mBlockWidth;
- SizeType blockHeight = mAtlasList[ atlas ].mBlockHeight;
+ SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
+ SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
float vertexBlockWidth = static_cast< float >( blockWidth );
float vertexBlockHeight = static_cast< float >( blockHeight );
- SizeType width = mAtlasList[ atlas ].mWidth;
- SizeType height = mAtlasList[ atlas ].mHeight;
+ SizeType width = mAtlasList[ atlas ].mSize.mWidth;
+ SizeType height = mAtlasList[ atlas ].mSize.mHeight;
- SizeType atlasWidthInBlocks = width / blockWidth;
+ SizeType atlasWidthInBlocks = ( width - 1u ) / blockWidth;
// Get the normalized size of a texel in both directions
// TODO when texture resizing and passing texture size via uniforms is available,
float texelX = 1.0f / static_cast< float >( width );
float texelY = 1.0f / static_cast< float >( height );
+ float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
+ float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
+
// Get the normalized size of a block in texels
float texelBlockWidth = texelX * vertexBlockWidth;
float texelBlockHeight = texelY * vertexBlockHeight;
float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
// And in texels
- float texelEdgeWidth = vertexEdgeWidth * texelX;
- float texelEdgeHeight = vertexEdgeHeight * texelY;
+ float texelEdgeWidth = texelX * vertexEdgeWidth;
+ float texelEdgeHeight = texelY * vertexEdgeHeight;
+
+ // We're going to 'blit' half a pixel more on each edge
+ vertexBlockWidth++;
+ vertexEdgeWidth++;
+ vertexBlockHeight++;
+ vertexEdgeHeight++;
// Block by block create the two triangles for the quad
SizeType blockIndex = 0;
float ndcVWidth;
float ndcVHeight;
- Vector2 topLeft = position;
+ // Move back half a pixel
+ Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
for ( SizeType y = 0; y < heightInBlocks; ++y )
{
if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
{
- ndcHeight = texelEdgeHeight;
+ ndcHeight = texelEdgeHeight + texelY;
ndcVHeight = vertexEdgeHeight;
}
else
{
- ndcHeight = texelBlockHeight;
+ ndcHeight = texelBlockHeight + texelY;
ndcVHeight = vertexBlockHeight;
}
float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
+ // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
+ fBlockX += oneAndAHalfTexelX;
+ fBlockY += oneAndAHalfTexelY;
+
if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
{
- ndcWidth = texelEdgeWidth;
+ ndcWidth = texelEdgeWidth + texelX;
ndcVWidth = vertexEdgeWidth;
}
else
{
- ndcWidth = texelBlockWidth;
+ ndcWidth = texelBlockWidth + texelX;
ndcVWidth = vertexBlockWidth;
}
// Top left
- vertex.x = topLeft.x;
- vertex.y = topLeft.y;
- vertex.z = 0.0f;
- vertex.u = fBlockX;
- vertex.v = fBlockY;
+ vertex.mPosition.x = topLeft.x;
+ vertex.mPosition.y = topLeft.y;
+ vertex.mTexCoords.x = fBlockX;
+ vertex.mTexCoords.y = fBlockY;
- vertices.push_back( vertex );
+ mesh.mVertices.PushBack( vertex );
// Top Right
- vertex.x = topLeft.x + ndcVWidth;
- vertex.y = topLeft.y;
- vertex.z = 0.0f;
- vertex.u = fBlockX + ndcWidth;
- vertex.v = fBlockY;
+ vertex.mPosition.x = topLeft.x + ndcVWidth;
+ vertex.mPosition.y = topLeft.y;
+ vertex.mTexCoords.x = fBlockX + ndcWidth;
+ vertex.mTexCoords.y = fBlockY;
- vertices.push_back( vertex );
+ mesh.mVertices.PushBack( vertex );
// Bottom Left
- vertex.x = topLeft.x;
- vertex.y = topLeft.y + ndcVHeight;
- vertex.z = 0.0f;
- vertex.u = fBlockX;
- vertex.v = fBlockY + ndcHeight;
+ vertex.mPosition.x = topLeft.x;
+ vertex.mPosition.y = topLeft.y + ndcVHeight;
+ vertex.mTexCoords.x = fBlockX;
+ vertex.mTexCoords.y = fBlockY + ndcHeight;
- vertices.push_back( vertex );
+ mesh.mVertices.PushBack( vertex );
// Bottom Right
topLeft.x += ndcVWidth;
- vertex.x = topLeft.x;
- vertex.y = topLeft.y + ndcVHeight;
- vertex.z = 0.0f;
- vertex.u = fBlockX + ndcWidth;
- vertex.v = fBlockY + ndcHeight;
+ vertex.mPosition.x = topLeft.x;
+ vertex.mPosition.y = topLeft.y + ndcVHeight;
+ vertex.mTexCoords.x = fBlockX + ndcWidth;
+ vertex.mTexCoords.y = fBlockY + ndcHeight;
- vertices.push_back( vertex );
+ mesh.mVertices.PushBack( vertex );
// Six indices in counter clockwise winding
- faces.push_back( faceIndex + 1u );
- faces.push_back( faceIndex );
- faces.push_back( faceIndex + 2u );
- faces.push_back( faceIndex + 2u );
- faces.push_back( faceIndex + 3u );
- faces.push_back( faceIndex + 1u );
+ mesh.mIndices.PushBack( faceIndex + 1u );
+ mesh.mIndices.PushBack( faceIndex );
+ mesh.mIndices.PushBack( faceIndex + 2u );
+ mesh.mIndices.PushBack( faceIndex + 2u );
+ mesh.mIndices.PushBack( faceIndex + 3u );
+ mesh.mIndices.PushBack( faceIndex + 1u );
faceIndex += 4;
}
// If there's only one block then skip this next vertex optimisation
if ( widthInBlocks * heightInBlocks > 1 )
{
- Dali::MeshData::VertexContainer optimizedVertices;
- OptimizeVertices( vertices, faces, optimizedVertices );
- meshData.SetVertices( optimizedVertices );
+ Toolkit::AtlasManager::Mesh2D optimizedMesh;
+ OptimizeMesh( mesh, optimizedMesh );
}
- else
- {
- meshData.SetVertices( vertices );
- }
-
- meshData.SetFaceIndices( faces );
- meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
- //PrintMeshData( meshData );
}
-void AtlasManager::PrintMeshData( const MeshData& meshData )
+void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
{
- std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
- std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
+ uint32_t vertexCount = mesh.mVertices.Size();
+ uint32_t indexCount = mesh.mIndices.Size();
+ std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
+ std::cout << ", Triangles = " << indexCount / 3 << std::endl;
- Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
- Dali::MeshData::FaceIndices faces = meshData.GetFaces();
-
- for ( SizeType v = 0; v < vertices.size(); ++v )
+ for ( SizeType v = 0; v < vertexCount; ++v )
{
- std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
- std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
- std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
+ std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
+ std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
+ std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
+ std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
}
std::cout << "\n Indices: ";
- for ( SizeType i = 0; i < faces.size(); ++i )
+ for ( SizeType i = 0; i < indexCount; ++i )
{
- std::cout << " " << faces[ i ];
+ std::cout << " " << mesh.mIndices[ i ];
}
std::cout << std::endl;
}
-void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
- MeshData::FaceIndices& faces,
- MeshData::VertexContainer& out )
+void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
+ Toolkit::AtlasManager::Mesh2D& out )
{
unsigned short vertexIndex = 0;
// We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
- for ( SizeType i = 0; i < faces.size(); ++i )
+ for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
{
// Fetch a vertex, has it already been assigned?
bool foundVertex = false;
- Dali::MeshData::Vertex v = in[ faces [ i ] ];
- for ( SizeType j = 0; j < vertexIndex; ++j )
+ Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
+ for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
{
- if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
- v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
- v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
+ if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
+ ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
+ ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
+ ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
{
// Yes, so store this down as the vertex to use
- faces[ i ] = j;
+ out.mIndices.PushBack( j );
foundVertex = true;
break;
}
// Did we find a vertex ?
if ( !foundVertex )
{
- // Add a new vertex
- faces[ i ] = vertexIndex++;
- out.push_back( v );
+ // No so add a new one
+ out.mVertices.PushBack( v );
+ vertexIndex++;
}
}
}
-void AtlasManager::StitchMesh( MeshData& first,
- const MeshData& second,
+void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
+ const Toolkit::AtlasManager::Mesh2D& second,
bool optimize )
{
+ const uint32_t verticesCount = first.mVertices.Size();
+ first.mVertices.Insert( first.mVertices.End(),
+ second.mVertices.Begin(),
+ second.mVertices.End() );
- // 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();
- MeshData::FaceIndices f2 = second.GetFaces();
-
- uint32_t vc1 = first.GetVertexCount();
- uint32_t vc2 = second.GetVertexCount();
+ const uint32_t indicesCount = first.mIndices.Size();
+ first.mIndices.Insert( first.mIndices.End(),
+ second.mIndices.Begin(),
+ second.mIndices.End() );
- for ( uint32_t v = 0; v < vc2; ++v )
+ for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
+ endIt = first.mIndices.End();
+ it != endIt;
+ ++it )
{
- v1.push_back( v2[ v ] );
- }
-
- for ( uint32_t f = 0; f < f2.size(); ++f )
- {
- f1.push_back( f2[ f ] + vc1 );
+ *it += verticesCount;
}
if ( optimize )
{
- MeshData::VertexContainer optimizedVertices;
- OptimizeVertices( v1, f1, optimizedVertices );
- first.SetVertices( optimizedVertices );
- }
- else
- {
- first.SetVertices( v1 );
+ Toolkit::AtlasManager::Mesh2D optimizedMesh;
+ OptimizeMesh( first, optimizedMesh );
+ first = optimizedMesh;
}
-
- first.SetFaceIndices( f1 );
-
- // TODO rather than set the material to the second, check to see if there's a match and return if not
- first.SetMaterial( second.GetMaterial() );
-}
-
-void AtlasManager::StitchMesh( const MeshData& first,
- const MeshData& second,
- 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();
- MeshData::FaceIndices f2 = second.GetFaces();
-
- uint32_t vc1 = first.GetVertexCount();
- uint32_t vc2 = second.GetVertexCount();
-
- MeshData::VertexContainer vertices;
-
- MeshData::FaceIndices faces;
-
- MeshData::Vertex vertex;
-
- for ( uint32_t v = 0; v < vc1; ++v )
- {
- vertices.push_back( v1[ v ] );
- }
-
- for ( uint32_t v = 0; v < vc2; ++v )
- {
- vertices.push_back( v2[ v ] );
- }
-
- for ( uint32_t f = 0; f < f1.size(); ++f )
- {
- faces.push_back( f1[ f ] );
- }
-
- for ( uint32_t f = 0; f < f2.size(); ++f )
- {
- faces.push_back( f2[ f ] + vc1 );
- }
-
- if ( optimize )
- {
- MeshData::VertexContainer optimizedVertices;
- OptimizeVertices( vertices, faces, optimizedVertices );
- out.SetVertices( optimizedVertices );
- }
- else
- {
- out.SetVertices( vertices );
- }
-
- // TODO rather than set the material to the second, check to see if there's a match and return if not
- out.SetMaterial( second.GetMaterial() );
- out.SetFaceIndices( faces );
}
void AtlasManager::UploadImage( const BufferImage& image,
return;
}
- SizeType atlasBlockWidth = mAtlasList[ atlas ].mBlockWidth;
- SizeType atlasBlockHeight = mAtlasList[ atlas ].mBlockHeight;
- SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mWidth / mAtlasList[ atlas ].mBlockWidth;
+ SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
+ SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
+ SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth;
SizeType block = desc.mBlocksList[ 0 ];
SizeType blockX = block % atlasWidthInBlocks;
SizeType blockY = block / atlasWidthInBlocks;
- SizeType blockOffsetX = blockX * atlasBlockWidth;
- SizeType blockOffsetY = blockY * atlasBlockHeight;
+ SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
+ SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u;
SizeType width = image.GetWidth();
SizeType height = image.GetHeight();
- if ( !mAtlasList[ atlas ].mAtlas.Upload( image, blockOffsetX, blockOffsetY ) )
+ // 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 block to Atlas Failed!.\n");
+ DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
}
- if ( blockOffsetY + height + PIXEL_PADDING <= mAtlasList[ atlas ].mHeight )
+
+ // Blit left strip
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
+ blockOffsetX,
+ blockOffsetY + SINGLE_PIXEL_PADDING ) )
+ {
+ DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
+ }
+
+ // Blit bottom strip
+ if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
{
- if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mEdgeX, blockOffsetX, blockOffsetY + height ) )
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
+ blockOffsetX,
+ blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
{
- DALI_LOG_ERROR("Uploading edgeX to Atlas Failed!.\n");
+ DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
}
}
- if ( blockOffsetX + width + PIXEL_PADDING <= mAtlasList[ atlas ].mWidth )
+
+ // Blit right strip
+ if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
{
- if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mEdgeY, blockOffsetX + width, blockOffsetY ) )
+ if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
+ blockOffsetX + width + SINGLE_PIXEL_PADDING,
+ blockOffsetY + SINGLE_PIXEL_PADDING ) )
{
- DALI_LOG_ERROR("Uploading edgeY to Atlas Failed!.\n");
+ DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
}
}
}
void AtlasManager::GenerateMeshData( ImageId id,
const Vector2& position,
- MeshData& meshData )
+ Toolkit::AtlasManager::Mesh2D& meshData,
+ bool addReference )
{
- // Read the atlas Id to use for this image
- SizeType imageId = id - 1u;
- SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
- SizeType width = mImageList[ imageId ].mImageWidth;
- SizeType height = mImageList[ imageId ].mImageHeight;
-
- SizeType widthInBlocks = width / mAtlasList[ atlas ].mBlockWidth;
- if ( width % mAtlasList[ atlas ].mBlockWidth )
+ if ( id )
{
- widthInBlocks++;
+ // Read the atlas Id to use for this image
+ SizeType imageId = id - 1u;
+ SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
+ SizeType width = mImageList[ imageId ].mImageWidth;
+ SizeType height = mImageList[ imageId ].mImageHeight;
+
+ SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
+ if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
+ {
+ widthInBlocks++;
+ }
+ SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
+ if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
+ {
+ heightInBlocks++;
+ }
+
+ CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
+
+ // Mesh created so increase the reference count, if we're asked to
+ if ( addReference )
+ {
+ mImageList[ imageId ].mCount++;
+ }
}
- SizeType heightInBlocks = height / mAtlasList[ atlas ].mBlockHeight;
- if ( height % mAtlasList[ atlas ].mBlockHeight )
+ else
{
- heightInBlocks++;
+ DALI_LOG_ERROR("Cannot generate mesh with invalid AtlasId\n");
}
-
- CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
-
- // Mesh created so increase the reference count
- mImageList[ imageId ].mCount++;
}
Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
return false;
}
- if ( 1u == --mImageList[ imageId ].mCount )
+ if ( 2u > --mImageList[ imageId ].mCount )
{
// 'Remove the blocks' from this image and add to the atlas' freelist
removed = true;
}
}
-void AtlasManager::SetNewAtlasSize( const Vector2& size,
- const Vector2& blockSize )
+void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
{
mNewAtlasSize = size;
- mNewBlockSize = blockSize;
-}
-Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
-{
- if ( atlas && atlas <= mAtlasList.size() )
- {
- return Vector2( static_cast< float >( mAtlasList[ atlas - 1u ].mBlockWidth ),
- static_cast< float >( mAtlasList[ atlas - 1u ].mBlockHeight) );
- }
- else
- {
- return Vector2( 0.0f, 0.0f );
- }
+ // Add on padding for borders around atlas entries
+ mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
+ mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
}
-Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
+const Toolkit::AtlasManager::AtlasSize& 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
+ if ( atlas && atlas-- <= mAtlasList.size() )
{
- return Vector2( 0.0f, 0.0f );
+ return mAtlasList[ atlas ].mSize;
}
+ return EMPTY_SIZE;
}
AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
{
- if ( atlas && atlas <= mAtlasList.size() )
+ if ( atlas && atlas-- <= mAtlasList.size() )
{
- uint32_t index = atlas - 1u;
- uint32_t width = mAtlasList[ index ].mWidth;
- uint32_t height = mAtlasList[ index ].mHeight;
- uint32_t blockWidth = mAtlasList[ index ].mBlockWidth;
- uint32_t blockHeight = mAtlasList[ index ].mBlockHeight;
-
- SizeType widthInBlocks = width / blockWidth;
- SizeType heightInBlocks = height / blockHeight;
- uint32_t blockCount = widthInBlocks * heightInBlocks;
-
- // Check free previously unallocated blocks and any free blocks
- blockCount -= mAtlasList[ index ].mNextFreeBlock - mAtlasList[ index ].mFreeBlocksList.Size();
- return blockCount;
+ return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
}
else
{
DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
return Pixel::L8;
}
- return mAtlasList[ atlas -1u ].mPixelFormat;
+ return mAtlasList[ --atlas].mPixelFormat;
}
void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
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 );
- entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock : entry.mTotalBlocks - mAtlasList[ i ].mFreeBlocksList.Size();
+ entry.mSize = mAtlasList[ i ].mSize;
+ entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
+ entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
entry.mPixelFormat = GetPixelFormat( i + 1 );
- metrics.mAtlasMetrics.PushBack( entry );
+ metrics.mAtlasMetrics.PushBack( entry );
- uint32_t size = width * height;
+ uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
if ( entry.mPixelFormat == Pixel::BGRA8888 )
{
size <<= 2;
metrics.mTextureMemoryUsed = textureMemoryUsed;
}
+Material AtlasManager::GetMaterial( AtlasId atlas ) const
+{
+ if ( atlas && atlas-- <= mAtlasList.size() )
+ {
+ return mAtlasList[ atlas ].mMaterial;
+ }
+ Material null;
+ return null;
+}
+
+Sampler AtlasManager::GetSampler( AtlasId atlas ) const
+{
+ if ( atlas && atlas-- <= mAtlasList.size() )
+ {
+ return mAtlasList[ atlas ].mSampler;
+ }
+ Sampler null;
+ return null;
+}
} // namespace Internal