# Add local source files here
toolkit_src_files = \
- $(toolkit_src_dir)/atlas-manager/atlas-manager.cpp \
- $(toolkit_src_dir)/atlas-manager/atlas-manager-impl.cpp \
$(toolkit_src_dir)/builder/builder-actor.cpp \
$(toolkit_src_dir)/builder/builder-animations.cpp \
$(toolkit_src_dir)/builder/builder-impl.cpp \
$(toolkit_src_dir)/text/rendering/atlas/text-atlas-renderer.cpp \
$(toolkit_src_dir)/text/rendering/atlas/atlas-glyph-manager.cpp \
$(toolkit_src_dir)/text/rendering/atlas/atlas-glyph-manager-impl.cpp \
+ $(toolkit_src_dir)/text/rendering/atlas/atlas-manager.cpp \
+ $(toolkit_src_dir)/text/rendering/atlas/atlas-manager-impl.cpp \
+ $(toolkit_src_dir)/text/rendering/atlas/atlas-mesh-factory.cpp \
$(toolkit_src_dir)/text/rendering/text-backend-impl.cpp \
$(toolkit_src_dir)/transition-effects/cube-transition-effect-impl.cpp \
$(toolkit_src_dir)/transition-effects/cube-transition-cross-effect-impl.cpp \
// EXTERNAL INCLUDES
#include <dali/integration-api/debug.h>
-#define MAKE_SHADER(A)#A
-
namespace
{
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
#endif
+#define MAKE_SHADER(A)#A
+
const char* VERTEX_SHADER = MAKE_SHADER(
attribute mediump vec2 aPosition;
attribute mediump vec2 aTexCoord;
+uniform mediump vec2 uOffset;
uniform mediump mat4 uMvpMatrix;
varying mediump vec2 vTexCoord;
void main()
{
- mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
+ mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
gl_Position = uMvpMatrix * position;
vTexCoord = aTexCoord;
}
);
-const char* FRAGMENT_SHADER = MAKE_SHADER(
+const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
+uniform lowp vec4 uColor;
uniform sampler2D sTexture;
varying mediump vec2 vTexCoord;
void main()
{
- gl_FragColor = texture2D( sTexture, vTexCoord );
-}
-);
-
-const char* VERTEX_SHADER_SHADOW = MAKE_SHADER(
-attribute mediump vec2 aPosition;
-attribute mediump vec2 aTexCoord;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
- mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
- gl_Position = position;
- vTexCoord = aTexCoord;
+ mediump vec4 color = texture2D( sTexture, vTexCoord );
+ gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
}
);
-const char* FRAGMENT_SHADER_SHADOW = MAKE_SHADER(
+const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
varying mediump vec2 vTexCoord;
void main()
{
- mediump vec4 color = texture2D( sTexture, vTexCoord );
- gl_FragColor = vec4(uColor.rgb, uColor.a*color.r);
+ gl_FragColor = texture2D( sTexture, vTexCoord );
}
);
AtlasGlyphManager::AtlasGlyphManager()
{
+ mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
+ mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
mAtlasManager = Dali::Toolkit::AtlasManager::New();
- mEffectBufferShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- mShadowShader = Shader::New( VERTEX_SHADER_SHADOW, FRAGMENT_SHADER_SHADOW, Dali::Shader::HINT_MODIFIES_GEOMETRY );
}
void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
{
DALI_LOG_INFO( gLogFilter, Debug::General, "Added glyph, font: %d index: %d\n", glyph.fontId, glyph.index );
- mAtlasManager.Add( bitmap, slot );
+ if ( mAtlasManager.Add( bitmap, slot ) )
+ {
+ // A new atlas was created so set the material details for the atlas
+ Dali::Atlas atlas = mAtlasManager.GetAtlasContainer( slot.mAtlasId );
+ Pixel::Format pixelFormat = mAtlasManager.GetPixelFormat( slot.mAtlasId );
+ Material material = Material::New( pixelFormat == Pixel::L8 ? mShaderL8 : mShaderRgba );
+ material.AddTexture( atlas, "sTexture" );
+ material.SetBlendMode( BlendingMode::ON );
+ mAtlasManager.SetMaterial( slot.mAtlasId, material );
+ }
GlyphRecordEntry record;
record.mIndex = glyph.index;
mAtlasManager.GenerateMeshData( imageId, position, mesh, false );
}
-void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second )
-{
- mAtlasManager.StitchMesh( first, second );
-}
-
-bool AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::IsCached( Text::FontId fontId,
Text::GlyphIndex index,
Dali::Toolkit::AtlasManager::AtlasSlot& slot )
{
return mAtlasManager.GetMaterial( atlasId );
}
-Image AtlasGlyphManager::GetImage( uint32_t atlasId ) const
-{
- return mAtlasManager.GetImage( atlasId );
-}
-
AtlasGlyphManager::~AtlasGlyphManager()
{
// mAtlasManager handle is automatically released here
Toolkit::AtlasManager::Mesh2D& mesh );
/**
- * @copydoc Toolkit::AtlasGlyphManager::StitchMesh
+ * @copydoc Toolkit::AtlasGlyphManager::IsCached
*/
- void StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second );
-
- /**
- * @copydoc Toolkit::AtlasGlyphManager::Cached
- */
- bool Cached( Text::FontId fontId,
- Text::GlyphIndex index,
- Dali::Toolkit::AtlasManager::AtlasSlot& slot );
+ bool IsCached( Text::FontId fontId,
+ Text::GlyphIndex index,
+ Dali::Toolkit::AtlasManager::AtlasSlot& slot );
/**
* @copydoc Toolkit::AtlasGlyphManager::GetAtlasSize
Material GetMaterial( uint32_t atlasId ) const;
/**
- * @copydoc Toolkit::AtlasGlyphManager::GetMaterial
- */
- Image GetImage( uint32_t atlasId ) const;
-
- /**
* @copydoc Toolkit::AtlasGlyphManager::GetMetrics
*/
const Toolkit::AtlasGlyphManager::Metrics& GetMetrics();
- /**
- * @copydoc Toolkit::AtlasGlyphManager::GetEffectBufferShader
- */
- Shader GetEffectBufferShader() const
- {
- return mEffectBufferShader;
- }
-
- /**
- * @copydoc Toolkit::AtlasGlyphManager::GetGlyphShadowShader
- */
- Shader GetGlyphShadowShader() const
- {
- return mShadowShader;
- }
-
protected:
/**
Dali::Toolkit::AtlasManager mAtlasManager; ///> Atlas Manager created by GlyphManager
std::vector< FontGlyphRecord > mFontGlyphRecords;
Toolkit::AtlasGlyphManager::Metrics mMetrics; ///> Metrics to pass back on GlyphManager status
- Shader mEffectBufferShader; ///> Shader used to render drop shadow buffer textures
- Shader mShadowShader; ///> Shader used to render drop shadow into buffer
+
+ Shader mShaderL8;
+ Shader mShaderRgba;
};
} // namespace Internal
mesh );
}
-void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second )
+bool AtlasGlyphManager::IsCached( Text::FontId fontId,
+ Text::GlyphIndex index,
+ AtlasManager::AtlasSlot& slot )
{
- GetImplementation(*this).StitchMesh( first, second );
-}
-
-bool AtlasGlyphManager::Cached( Text::FontId fontId,
- Text::GlyphIndex index,
- AtlasManager::AtlasSlot& slot )
-{
- return GetImplementation(*this).Cached( fontId, index, slot );
+ return GetImplementation(*this).IsCached( fontId, index, slot );
}
void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
return GetImplementation(*this).GetMaterial( atlasId );
}
-Image AtlasGlyphManager::GetImage( uint32_t atlasId ) const
-{
- return GetImplementation(*this).GetImage( atlasId );
-}
-
const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
{
return GetImplementation(*this).GetMetrics();
GetImplementation(*this).AdjustReferenceCount( fontId, index, delta );
}
-Shader AtlasGlyphManager::GetEffectBufferShader() const
-{
- return GetImplementation(*this).GetEffectBufferShader();
-}
-
-Shader AtlasGlyphManager::GetGlyphShadowShader() const
-{
- return GetImplementation(*this).GetGlyphShadowShader();
-}
-
} // namespace Toolkit
} // namespace Dali
*/
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
#include <dali-toolkit/internal/text/text-definitions.h>
namespace Dali
Toolkit::AtlasManager::Mesh2D& mesh );
/**
- * @brief Stitch Two Meshes together
- *
- * @param[in] first first mesh
- * @param[in] second second mesh
- */
- void StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second );
-
- /**
* @brief Check to see if a glyph is being cached
*
* @param[in] fontId The font that this glyph comes from
*
* @return Whether glyph is cached or not ?
*/
- bool Cached( Text::FontId fontId,
- Text::GlyphIndex index,
- AtlasManager::AtlasSlot& slot );
+ bool IsCached( Text::FontId fontId,
+ Text::GlyphIndex index,
+ AtlasManager::AtlasSlot& slot );
/**
* @brief Retrieve the size of an atlas
Material GetMaterial( uint32_t atlasId ) const;
/**
- * @brief Get the sampler used by an atlas
- *
- * @param[in] atlasId Id of an atlas
- *
- * @return The sampler used by the atlas
- */
- Image GetImage( uint32_t atlasId ) const;
-
- /**
* @brief Get Glyph Manager metrics
*
* @return const reference to glyph manager metrics
*/
void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta );
- /**
- * @brief Get Shader used for rendering glyph effect buffers
- *
- * @return Handle of shader needed
- */
- Shader GetEffectBufferShader() const;
-
- /**
- * @brief Get Shader used rendering Glyph Shadows
- *
- * @return Handle of shader needed
- */
- Shader GetGlyphShadowShader() const;
-
private:
explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl);
*/
// CLASS HEADER
-#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h>
-// EXTERNAL INCLUDE
-#include <iostream>
+// EXTERNAL INCLUDES
#include <string.h>
-#include <dali/devel-api/rendering/sampler.h>
-#include <dali/devel-api/rendering/shader.h>
#include <dali/integration-api/debug.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+
namespace Dali
{
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.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()
memset( buffer, 0xFF, filledPixelImage.GetBufferSize() );
atlas.Upload( filledPixelImage, 0, 0 );
-
- atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
- atlasDescriptor.mMaterial.AddTexture(atlas, "sTexture" );
- atlasDescriptor.mImage = atlas;
- atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
mAtlasList.push_back( atlasDescriptor );
return mAtlasList.size();
}
mAddFailPolicy = policy;
}
-void AtlasManager::Add( const BufferImage& image,
+bool AtlasManager::Add( const BufferImage& image,
Toolkit::AtlasManager::AtlasSlot& slot,
Toolkit::AtlasManager::AtlasId atlas )
{
- // See if there's a slot in an atlas that matches the requirements of this image
- // A bitmap must be sliceable into a single atlas
+ bool created = false;
Pixel::Format pixelFormat = image.GetPixelFormat();
SizeType width = image.GetWidth();
SizeType height = image.GetHeight();
- SizeType blockArea = 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 );
+ foundAtlas = CheckAtlas( atlas, width, height, pixelFormat );
}
// Search current atlases to see if there is a good match
while( !foundAtlas && index < mAtlasList.size() )
{
- foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
+ foundAtlas = CheckAtlas( index, width, height, pixelFormat );
++index;
}
mNewAtlasSize.mHeight,
mNewAtlasSize.mBlockWidth,
mNewAtlasSize.mBlockHeight );
- return;
+ return created;
}
-
- foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea );
+ created = true;
+ foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat );
}
if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
{
// Haven't found an atlas for this image!!!!!!
DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
- return;
+ return created;
}
}
- // Work out where the blocks are we're going to use
- for ( SizeType i = 0; i < blockArea; ++i )
+ // Work out which the block we're going to use
+ // Is there currently a next free block available ?
+ if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
{
- // Is there currently a next free block available ?
- if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
- {
- // Yes, so select our next block
- desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
- }
- else
- {
- // Our next block must be from the free list, fetch from the start of the list
- desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
- mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
- }
+ // Yes, so select our next block
+ desc.mBlock = mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks--;
+ }
+ else
+ {
+ // Our next block must be from the free list, fetch from the start of the list
+ desc.mBlock = mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ];
+ mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
}
desc.mImageWidth = width;
// See if there's a previously freed image ID that we can assign to this new image
uint32_t imageId = 0u;
- for ( uint32_t i = 0u; i < mImageList.size(); ++i )
+ for ( uint32_t i = 0u; i < mImageList.Size(); ++i )
{
if ( !mImageList[ i ].mCount )
{
}
if ( !imageId )
{
- mImageList.push_back( desc );
- slot.mImageId = mImageList.size();
+ mImageList.PushBack( desc );
+ slot.mImageId = mImageList.Size();
}
else
{
slot.mImageId = imageId;
}
slot.mAtlasId = foundAtlas + 1u;
+
+ // Upload the buffer image into the atlas
UploadImage( image, desc );
+ return created;
}
AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
SizeType width,
SizeType height,
- Pixel::Format pixelFormat,
- SizeType& blockArea )
+ Pixel::Format pixelFormat )
{
+ AtlasManager::SizeType result = 0u;
if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
{
// Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
&& width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
&& height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
{
- blockArea = 1u;
- return ( atlas + 1u );
+ result = atlas + 1u;
}
}
- return 0u;
-}
-
-void AtlasManager::CreateMesh( SizeType atlas,
- SizeType imageWidth,
- SizeType imageHeight,
- const Vector2& position,
- SizeType widthInBlocks,
- SizeType heightInBlocks,
- Toolkit::AtlasManager::Mesh2D& mesh,
- AtlasSlotDescriptor& desc )
-{
- Toolkit::AtlasManager::Vertex2D vertex;
- uint32_t faceIndex = 0; // TODO change to unsigned short when property type is available
-
- 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 ].mSize.mWidth;
- SizeType height = mAtlasList[ atlas ].mSize.mHeight;
-
- 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,
- // we will encode pixel positions into the vertex data rather than normalized
- // meaning that geometry needn't be changed on an atlas resize
- 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;
-
- // Get partial block space
- float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
- float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
-
- // And in texels
- 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 ndcWidth;
- float ndcHeight;
- float ndcVWidth;
- float ndcVHeight;
-
- // Move back half a pixel
- Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
-
- for ( SizeType y = 0; y < heightInBlocks; ++y )
- {
-
- float currentX = position.x;
-
- if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
- {
- ndcHeight = texelEdgeHeight + texelY;
- ndcVHeight = vertexEdgeHeight;
- }
- else
- {
- ndcHeight = texelBlockHeight + texelY;
- ndcVHeight = vertexBlockHeight;
- }
-
- for ( SizeType x = 0; x < widthInBlocks; ++x )
- {
- SizeType block = desc.mBlocksList[ blockIndex++ ];
-
- 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 + texelX;
- ndcVWidth = vertexEdgeWidth;
- }
- else
- {
- ndcWidth = texelBlockWidth + texelX;
- ndcVWidth = vertexBlockWidth;
- }
-
- // Top left
- vertex.mPosition.x = topLeft.x;
- vertex.mPosition.y = topLeft.y;
- vertex.mTexCoords.x = fBlockX;
- vertex.mTexCoords.y = fBlockY;
-
- mesh.mVertices.PushBack( vertex );
-
- // Top Right
- vertex.mPosition.x = topLeft.x + ndcVWidth;
- vertex.mPosition.y = topLeft.y;
- vertex.mTexCoords.x = fBlockX + ndcWidth;
- vertex.mTexCoords.y = fBlockY;
-
- mesh.mVertices.PushBack( vertex );
-
- // Bottom Left
- vertex.mPosition.x = topLeft.x;
- vertex.mPosition.y = topLeft.y + ndcVHeight;
- vertex.mTexCoords.x = fBlockX;
- vertex.mTexCoords.y = fBlockY + ndcHeight;
-
- mesh.mVertices.PushBack( vertex );
-
- // Bottom Right
- topLeft.x += ndcVWidth;
- vertex.mPosition.x = topLeft.x;
- vertex.mPosition.y = topLeft.y + ndcVHeight;
- vertex.mTexCoords.x = fBlockX + ndcWidth;
- vertex.mTexCoords.y = fBlockY + ndcHeight;
-
- mesh.mVertices.PushBack( vertex );
-
- // Six indices in counter clockwise winding
- 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;
- }
-
- // Move down a row
- topLeft.x = currentX;
- topLeft.y += vertexBlockHeight;
- }
-
- // If there's only one block then skip this next vertex optimisation
- if ( widthInBlocks * heightInBlocks > 1 )
- {
- Toolkit::AtlasManager::Mesh2D optimizedMesh;
- OptimizeMesh( mesh, optimizedMesh );
- }
-}
-
-void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
-{
- 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;
-
- for ( SizeType v = 0; v < vertexCount; ++v )
- {
- 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 < indexCount; ++i )
- {
- std::cout << " " << mesh.mIndices[ i ];
- }
- std::cout << std::endl;
-}
-
-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 < in.mIndices.Size(); ++i )
- {
- // Fetch a vertex, has it already been assigned?
- bool foundVertex = false;
- Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
- for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
- {
- 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
- out.mIndices.PushBack( j );
- foundVertex = true;
- break;
- }
- }
-
- // Did we find a vertex ?
- if ( !foundVertex )
- {
- // No so add a new one
- out.mVertices.PushBack( v );
- vertexIndex++;
- }
- }
-}
-
-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() );
-
- const uint32_t indicesCount = first.mIndices.Size();
- first.mIndices.Insert( first.mIndices.End(),
- second.mIndices.Begin(),
- second.mIndices.End() );
-
- for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
- endIt = first.mIndices.End();
- it != endIt;
- ++it )
- {
- *it += verticesCount;
- }
-
- if ( optimize )
- {
- Toolkit::AtlasManager::Mesh2D optimizedMesh;
- OptimizeMesh( first, optimizedMesh );
- first = optimizedMesh;
- }
+ return result;
}
void AtlasManager::UploadImage( const BufferImage& image,
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 blockX = desc.mBlock % atlasWidthInBlocks;
+ SizeType blockY = desc.mBlock / atlasWidthInBlocks;
SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 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 ] );
+ AtlasMeshFactory::CreateQuad( width,
+ height,
+ mImageList[ imageId ].mBlock,
+ mAtlasList[ atlas ].mSize,
+ position,
+ meshData );
// Mesh created so increase the reference count, if we're asked to
if ( addReference )
Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
{
- Dali::Atlas null;
- if ( !atlas || atlas > mAtlasList.size( ) )
+ DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+ Dali::Atlas atlasContainer;
+ if ( atlas && atlas-- <= mAtlasList.size() )
{
-
- DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
- return null;
+ atlasContainer = mAtlasList[ atlas ].mAtlas;
}
- return mAtlasList[ atlas -1u ].mAtlas;
+ return atlasContainer;
}
bool AtlasManager::Remove( ImageId id )
SizeType imageId = id - 1u;
bool removed = false;
- if ( id > mImageList.size() )
+ if ( id > mImageList.Size() )
{
DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
return false;
removed = true;
mImageList[ imageId ].mCount = 0;
SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
- for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
- {
- mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
- }
+ mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlock );
}
return removed;
}
AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
{
- if ( id && id <= mImageList.size() )
- {
- return mImageList[ id - 1u ].mAtlasId;
- }
- else
+ DALI_ASSERT_DEBUG( id && id <= mImageList.Size() );
+ AtlasManager::AtlasId atlasId = 0u;
+ if ( id && id-- <= mImageList.Size() )
{
- return 0;
+ atlasId = mImageList[ id ].mAtlasId;
}
+ return atlasId;
}
void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
{
+ DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
if ( atlas && atlas-- <= mAtlasList.size() )
{
return mAtlasList[ atlas ].mSize;
AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
{
+ DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+ AtlasManager::SizeType freeBlocks = 0u;
if ( atlas && atlas-- <= mAtlasList.size() )
{
- return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
- }
- else
- {
- return 0;
+ freeBlocks = mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size();
}
+ return freeBlocks;
}
AtlasManager::SizeType AtlasManager::GetAtlasCount() const
Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
{
- if ( !atlas || atlas > mAtlasList.size( ) )
+ DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+ Pixel::Format pixelFormat = Pixel::RGBA8888;
+ if ( atlas && atlas-- <= mAtlasList.size() )
{
-
- DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
- return Pixel::L8;
+ pixelFormat = mAtlasList[ atlas ].mPixelFormat;
}
- return mAtlasList[ --atlas].mPixelFormat;
+ return pixelFormat;
}
void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
Material AtlasManager::GetMaterial( AtlasId atlas ) const
{
+ DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+ Material material;
if ( atlas && atlas-- <= mAtlasList.size() )
{
- return mAtlasList[ atlas ].mMaterial;
+ material = mAtlasList[ atlas ].mMaterial;
}
- Material null;
- return null;
+ return material;
}
-Image AtlasManager::GetImage( AtlasId atlas ) const
+void AtlasManager::SetMaterial( AtlasId atlas, Material& material )
{
+ DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
if ( atlas && atlas-- <= mAtlasList.size() )
{
- return mAtlasList[ atlas ].mImage;
+ mAtlasList[ atlas ].mMaterial = material;
}
- Image null;
- return null;
}
} // namespace Internal
#include <dali/public-api/object/base-object.h>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
namespace Dali
{
BufferImage mHorizontalStrip; // Image used to pad upload
BufferImage mVerticalStrip; // Image used to pad upload
Material mMaterial; // material used for atlas texture
- Image mImage;
SizeType mTotalBlocks; // total number of blocks in atlas
SizeType mAvailableBlocks; // number of blocks available in atlas
Dali::Vector< SizeType > mFreeBlocksList; // unless there are any previously freed blocks
SizeType mImageWidth; // Width of image stored
SizeType mImageHeight; // Height of image stored
AtlasId mAtlasId; // Image is stored in this Atlas
- Dali::Vector< SizeType > mBlocksList; // List of blocks within atlas used for image
+ SizeType mBlock; // Block within atlas used for image
};
AtlasManager();
/**
* @copydoc Toolkit::AtlasManager::Add
*/
- void Add( const BufferImage& image,
+ bool Add( const BufferImage& image,
Toolkit::AtlasManager::AtlasSlot& slot,
Toolkit::AtlasManager::AtlasId atlas );
bool addReference );
/**
- * @copydoc Toolkit::AtlasManager::StitchMesh
- */
- void StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second,
- bool optimize );
-
- /**
* @copydoc Toolkit::AtlasManager::Remove
*/
bool Remove( ImageId id );
*/
Material GetMaterial( AtlasId atlas ) const;
-/**
- * @copydoc Toolkit::AtlasManager::GetImage
+ /**
+ * @copydoc Toolkit::AtlasManager::SetMaterial
*/
- Image GetImage( AtlasId atlas ) const;
+ void SetMaterial( AtlasId atlas, Material& material );
private:
std::vector< AtlasDescriptor > mAtlasList; // List of atlases created
- std::vector< AtlasSlotDescriptor > mImageList; // List of bitmaps store in atlases
+ Vector< AtlasSlotDescriptor > mImageList; // List of bitmaps stored in atlases
Toolkit::AtlasManager::AtlasSize mNewAtlasSize; // Atlas size to use in next creation
Toolkit::AtlasManager::AddFailPolicy mAddFailPolicy; // Policy for faling to add an Image
SizeType CheckAtlas( SizeType atlas,
SizeType width,
SizeType height,
- Pixel::Format pixelFormat,
- SizeType& blockArea );
-
- void CreateMesh( SizeType atlas,
- SizeType imageWidth,
- SizeType imageHeight,
- const Vector2& position,
- SizeType widthInBlocks,
- SizeType heightInBlocks,
- Toolkit::AtlasManager::Mesh2D& mesh,
- AtlasSlotDescriptor& desc );
-
- void OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
- Toolkit::AtlasManager::Mesh2D& out );
+ Pixel::Format pixelFormat );
void UploadImage( const BufferImage& image,
const AtlasSlotDescriptor& desc );
- void PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh );
-
- Shader mShaderL8;
- Shader mShaderRgba;
-
};
} // namespace Internal
*/
// CLASS HEADER
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
- // INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h>
namespace Dali
{
GetImplementation(*this).SetAddPolicy( policy );
}
-void AtlasManager::Add( const BufferImage& image,
+bool AtlasManager::Add( const BufferImage& image,
AtlasManager::AtlasSlot& slot,
AtlasManager::AtlasId atlas )
{
- GetImplementation(*this).Add( image, slot, atlas );
+ return GetImplementation(*this).Add( image, slot, atlas );
}
bool AtlasManager::Remove( ImageId id )
addReference );
}
-void AtlasManager::StitchMesh( Mesh2D& first,
- const Mesh2D& second,
- bool optimize )
-{
- GetImplementation(*this).StitchMesh( first, second, optimize );
-}
-
Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
{
return GetImplementation(*this).GetAtlasContainer( atlas );
return GetImplementation(*this).GetMaterial( atlas );
}
-Image AtlasManager::GetImage( AtlasId atlas ) const
+void AtlasManager::SetMaterial( AtlasId atlas, Material& material )
{
- return GetImplementation(*this).GetImage( atlas );
+ GetImplementation(*this).SetMaterial( atlas, material );
}
} // namespace Toolkit
} // namespace Internal
-/**
- * AtlasManager
- * ------------
- *
- * Creates and manages additions and removals of images from Texture Atlases
- *
- * The AtlasManager will match pixeltype and optimal block use to determine
- * the appropriate atlas to upload an image to.
- *
- * A policy can be specified to determine the action the AtlasManager will carry
- * out, should it not be able to add an image. This can return an error, or create
- * a new atlas of pre-determined dimensions to accomodate the new image.
- *
- * Images are referenced by an ImageId once they have been successfully uploaded.
- *
- * Once an image has been successfully uploaded, Geometry can be generated by passing
- * the ImageId to the GenerateMeshData method and geometry can be consolidated via
- * the StitchMesh method.
- *
- * Images are reference counted once mesh data has been generated. An image is removed
- * from the Atlas via the Remove( ImageId ) method. This unreferences the image and only
- * physically removes it from the atlas once all references have been freed.
- *
- * If the AddPolicy is set to generate and error if an image can't be uploaded, then it
- * is the applications responsibility to deal with the situation. An error will be indicated
- * with an ImageId of 0.
- *
- * Examples using the AtlasManager
- *
- * Create or obtain the AtlasManager
- * @code
- *
- * AtlasManager manager = AtlasManager::Get();
- *
- * @endcode
- *
- * Set the AtlasManager AddPolicy
- *
- * @code
- *
- * // Tell the atlas manager to create a new atlas, if it needs to
- * manager.SetAddPolicy( FAIL_ON_ADD_CREATES );
- *
- * // Tell the atlas manager to return an error, if it can't add an image
- * manager.SetAddPolicy( FAIL_ON_ADD_FAILS );
- *
- * @endcode
- *
- * Simple add and removal of BufferImage to and from an atlas
- *
- * @code
- *
- * // Structure returned by AtlasManager operations
- * AtlasSlot slot;
- *
- * // Add image to an atlas ( will be created if none suitable exists )
- * manager.Add( bitmapImage, slot );
- *
- * // slot.mImage returns the imageId for the bitmap, slot.mAtlas indicates the atlasId
- * // that the image was added to. The imageId is used to communicate with the AtlasManager
- * uint32_t imageId = slot.mImage;
- * if ( !imageId )
- * {
- * // Addition has failed.....
- * }
- * ...
- * ...
- * // Done with image, so remove from atlas, if not being used elsewhere
- * manager.Remove( imageId );
- *
- * @endcode
- *
- * Create a Specific Atlas for adding BufferImages to
- *
- * @code
- *
- * // Create an RGB888 atlas of 2048x2848, with a blocksize of 128x128
- * uint32_t atlas = manager.CreateAtlas( 2048u, 2048u, 128u, 128u, Pixel::RGB888 );
- *
- * // Add an image to a preferred atlas ( note not specifying atlas may still result
- * // in the bitmap being added to the atlas above )
- * manager.Add( bitmapImage, slot, atlas );
- *
- * @endcode
- *
- * Create Geometry for a previously added image
- *
- * @code
- *
- * // Top left corner of geometry to be generated
- * Vector2 position( 1.0f, 1.0f );
- *
- * // Geometry will end up here!
- * MeshData meshData;
- * manager.GenerateMeshData( imageId, position, meshData );
- *
- * @endcode
- *
- * Generating Geometry from multiple images in the same atlas
- *
- * @code
- *
- * MeshData firstMesh;
- * MeshData secondMesh;
- * manager.GenerateMeshData( imageid_1, position_1, firstMesh );
- * manager.GenerateMeshData( imageid_2, position_2, secondMesh );
- *
- * // Combine the two meshes. Passing MESH_OPTIMIZE as an optional third parameter will remove duplicate vertices
- * manager.StitchMesh( first, second );
- *
- * @endcode
- *
- */
-
class AtlasManager : public BaseHandle
{
public:
typedef uint32_t SizeType;
typedef SizeType AtlasId;
typedef SizeType ImageId;
- static const bool MESH_OPTIMIZE = true;
struct AtlasSize
{
struct Vertex2D
{
- Vector2 mPosition;
- Vector2 mTexCoords;
+ Vector2 mPosition; ///< Vertex posiiton
+ Vector2 mTexCoords; ///< Vertex texture co-ordinates
};
struct Mesh2D
{
- Vector< Vertex2D > mVertices;
- Vector< unsigned int> mIndices;
+ Vector< Vertex2D > mVertices; ///< container of vertices
+ Vector< SizeType > mIndices; ///< container of indices
};
/**
* @param[in] image reference to a bitmapimage
* @param[out] slot result of add operation
* @param[in] atlas optional preferred atlas
+ *
+ * @return true if a new atlas was created
*/
- void Add( const BufferImage& image,
+ bool Add( const BufferImage& image,
AtlasSlot& slot,
AtlasId atlas = 0 );
bool addReference = true );
/**
- * @brief Append second mesh to the first mesh
- *
- * @param[in] first First mesh
- * @param[in] second Second mesh
- * @param[in] optimize should we optimize vertex data
- */
- void StitchMesh( Mesh2D& first,
- const Mesh2D& second,
- bool optimize = false );
-
- /**
* @brief Get the BufferImage containing an atlas
*
* @param[in] atlas AtlasId returned when atlas was created
/**
* @brief Get Material used by atlas
*
- * @param atlas[in] atlas AtlasId
+ * @param[in] atlas AtlasId
*
* @return Material used by atlas
*/
Material GetMaterial( AtlasId atlas ) const;
- /**
- * @brief Get Image used by atlas
- *
- * @param atlas[in] atlas AtlasId
+ /**
+ * @brief Set the material used by an atlas
*
- * @return Sampler used by atlas
+ * @param[in] atlas AtlasId
+ * @param[in] material The Material to assign
*/
- Image GetImage( AtlasId atlas ) const;
+ void SetMaterial( AtlasId atlas, Material& material );
+
private:
explicit DALI_INTERNAL AtlasManager(Internal::AtlasManager *impl);
--- /dev/null
+ /*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace AtlasMeshFactory
+{
+
+void CreateQuad( SizeType imageWidth,
+ SizeType imageHeight,
+ SizeType block,
+ const Toolkit::AtlasManager::AtlasSize& atlasSize,
+ const Vector2& position,
+ Toolkit::AtlasManager::Mesh2D& mesh )
+{
+ Toolkit::AtlasManager::Vertex2D vertex;
+
+ SizeType blockWidth = atlasSize.mBlockWidth;
+ SizeType blockHeight = atlasSize.mBlockHeight;
+
+ float vertexBlockWidth = static_cast< float >( blockWidth );
+ float vertexBlockHeight = static_cast< float >( blockHeight );
+
+ SizeType atlasWidth = atlasSize.mWidth;
+ SizeType atlasHeight = atlasSize.mHeight;
+
+ SizeType atlasWidthInBlocks = ( atlasWidth - 1u ) / blockWidth;
+
+ // Get the normalized size of a texel in both directions
+ float texelX = 1.0f / static_cast< float >( atlasWidth );
+ float texelY = 1.0f / static_cast< float >( atlasHeight );
+
+ float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
+ float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
+
+ float texelBlockWidth = texelX * vertexBlockWidth;
+ float texelBlockHeight = texelY * vertexBlockHeight;
+
+ uint32_t pixelsX = imageWidth % blockWidth;
+ uint32_t pixelsY = imageHeight % blockHeight;
+
+ if ( !pixelsX )
+ {
+ pixelsX = blockWidth;
+ }
+ if ( !pixelsY )
+ {
+ pixelsY = blockHeight;
+ }
+ float vertexWidth = static_cast< float >( pixelsX );
+ float vertexHeight = static_cast< float >( pixelsY );
+ float texelWidth = texelX * vertexWidth;
+ float texelHeight = texelY * vertexHeight;
+
+ // We're going to 'blit' half a pixel more on each edge
+ vertexWidth++;
+ vertexHeight++;
+
+ // Move back half a pixel
+ Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
+
+ 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;
+
+ float texelWidthOffset = texelWidth + texelX;
+ float texelHeightOffset = texelHeight + texelY;
+
+ // Top left
+ vertex.mPosition.x = topLeft.x;
+ vertex.mPosition.y = topLeft.y;
+ vertex.mTexCoords.x = fBlockX;
+ vertex.mTexCoords.y = fBlockY;
+
+ mesh.mVertices.Reserve( 4u );
+ mesh.mVertices.PushBack( vertex );
+
+ // Top Right
+ vertex.mPosition.x = topLeft.x + vertexWidth;
+ vertex.mPosition.y = topLeft.y;
+ vertex.mTexCoords.x = fBlockX + texelWidthOffset;
+ vertex.mTexCoords.y = fBlockY;
+
+ mesh.mVertices.PushBack( vertex );
+
+ // Bottom Left
+ vertex.mPosition.x = topLeft.x;
+ vertex.mPosition.y = topLeft.y + vertexHeight;
+ vertex.mTexCoords.x = fBlockX;
+ vertex.mTexCoords.y = fBlockY + texelHeightOffset;
+
+ mesh.mVertices.PushBack( vertex );
+
+ // Bottom Right
+ vertex.mPosition.x = topLeft.x + vertexWidth;
+ vertex.mPosition.y = topLeft.y + vertexHeight;
+ vertex.mTexCoords.x = fBlockX + texelWidthOffset;
+ vertex.mTexCoords.y = fBlockY + texelHeightOffset;
+
+ mesh.mVertices.PushBack( vertex );
+
+ // Six indices in counter clockwise winding
+ mesh.mIndices.Reserve( 6u );
+ mesh.mIndices.PushBack( 1u );
+ mesh.mIndices.PushBack( 0u );
+ mesh.mIndices.PushBack( 2u );
+ mesh.mIndices.PushBack( 2u );
+ mesh.mIndices.PushBack( 3u );
+ mesh.mIndices.PushBack( 1u );
+}
+
+void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
+ const Toolkit::AtlasManager::Mesh2D& second )
+{
+ const uint32_t verticesCount = first.mVertices.Size();
+ first.mVertices.Insert( first.mVertices.End(),
+ second.mVertices.Begin(),
+ second.mVertices.End() );
+
+ const uint32_t indicesCount = first.mIndices.Size();
+ first.mIndices.Insert( first.mIndices.End(),
+ second.mIndices.Begin(),
+ second.mIndices.End() );
+
+ for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
+ endIt = first.mIndices.End();
+ it != endIt;
+ ++it )
+ {
+ *it += verticesCount;
+ }
+}
+
+} // namespace AtlasMeshFactory
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__
+#define __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace AtlasMeshFactory
+{
+ typedef uint32_t SizeType;
+
+ /**
+ * @brief Create a Quad that describes an area in an atlas and a position.
+ *
+ * @param[in] width Width of area in pixels.
+ * @param[in] height Height of area in pixels.
+ * @param[in] block Block position in atlas.
+ * @param[in] atlasSize Atlas and block dimensions.
+ * @param[in] position Position to place area in space.
+ * @param[out] mesh Mesh object to hold created quad.
+ */
+ void CreateQuad( SizeType width,
+ SizeType height,
+ SizeType block,
+ const Toolkit::AtlasManager::AtlasSize& atlasSize,
+ const Vector2& position,
+ Toolkit::AtlasManager::Mesh2D& mesh );
+
+ /**
+ * @brief Append one mesh to another.
+ *
+ * @param[in,out] first Mesh to append to.
+ * @param[in] second Mesh to append.
+ */
+ void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
+ const Toolkit::AtlasManager::Mesh2D& second );
+
+} // namespace AtlasMeshFactory
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__
// EXTERNAL INCLUDES
#include <dali/integration-api/debug.h>
-#include <dali/public-api/common/stage.h>
-#include <dali/public-api/images/frame-buffer-image.h>
-#include <dali/public-api/render-tasks/render-task.h>
-#include <dali/public-api/render-tasks/render-task-list.h>
#include <dali/devel-api/rendering/renderer.h>
#include <dali/devel-api/rendering/geometry.h>
#include <dali/devel-api/text-abstraction/font-client.h>
#include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/internal/text/glyph-run.h>
#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
#include <dali-toolkit/internal/text/text-view.h>
using namespace Dali;
const float ZERO( 0.0f );
const float HALF( 0.5f );
const float ONE( 1.0f );
-const float TWO( 2.0f );
const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
}
-struct AtlasRenderer::Impl : public ConnectionTracker
+
+struct AtlasRenderer::Impl
{
enum Style
{
bool IsGlyphUnderlined( GlyphIndex index,
const Vector<GlyphRun>& underlineRuns )
{
- // TODO: At the moment it works because we always traverse the glyphs starting from the beginning
- // and there is only one glyph run! If there are more they should be ordered.
-
for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
endIt = underlineRuns.End();
it != endIt;
lastUnderlinedFontId = glyph.fontId;
} // underline
- if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
+ if ( !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ) )
{
// Select correct size for new atlas if needed....?
if ( lastFontId != glyph.fontId )
// Now remove references for the old text
RemoveText();
mTextCache.Swap( newTextCache );
- RemoveAllShadowRenderTasks();
if( thereAreUnderlinedGlyphs )
{
// Create an effect if necessary
if ( style == STYLE_DROP_SHADOW )
{
- Actor shadowActor = GenerateShadow( *mIt, actorSize, shadowOffset, shadowColor );
- shadowActor.Add( actor );
- actor = shadowActor;
+ // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
+ Actor containerActor = Actor::New();
+ containerActor.SetParentOrigin( ParentOrigin::CENTER );
+ containerActor.SetSize( actorSize );
+
+ Actor shadowActor = Actor::New();
+#if defined(DEBUG_ENABLED)
+ shadowActor.SetName( "Text Shadow renderable actor" );
+#endif
+ // Offset shadow in x and y
+ shadowActor.RegisterProperty("uOffset", shadowOffset );
+ if ( actor.GetRendererCount() )
+ {
+ Dali::Renderer renderer( actor.GetRendererAt( 0 ) );
+ Geometry geometry = renderer.GetGeometry();
+ Material material = renderer.GetMaterial();
+
+ Dali::Renderer shadowRenderer = Dali::Renderer::New( geometry, material );
+ shadowRenderer.SetDepthIndex( renderer.GetDepthIndex() - 1 );
+ shadowActor.AddRenderer( shadowRenderer );
+ shadowActor.SetParentOrigin( ParentOrigin::CENTER );
+ shadowActor.SetSize( actorSize );
+ shadowActor.SetColor( shadowColor );
+ containerActor.Add( shadowActor );
+ containerActor.Add( actor );
+ actor = containerActor;
+ }
}
if( mActor )
actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
actor.SetSize( actorSize );
actor.SetColor( meshRecord.mColor );
+ actor.RegisterProperty("uOffset", Vector2::ZERO );
return actor;
}
{
if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
{
- // Stitch the mesh to the existing mesh and adjust any extents
- mGlyphManager.StitchMesh( mIt->mMesh, newMesh );
+ // Append the mesh to the existing mesh and adjust any extents
+ Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh );
if( underlineGlyph )
{
if ( underlineColor == textColor )
{
- mGlyphManager.StitchMesh( meshRecords[ index ].mMesh, newMesh );
+ Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh );
}
else
{
}
}
- Actor GenerateShadow( MeshRecord& meshRecord,
- const Vector2& actorSize,
- const Vector2& shadowOffset,
- const Vector4& shadowColor )
- {
- // Scan vertex buffer to determine width and height of effect buffer needed
- const Vector< AtlasManager::Vertex2D >& verts = meshRecord.mMesh.mVertices;
- float tlx = verts[ 0 ].mPosition.x;
- float tly = verts[ 0 ].mPosition.y;
- float brx = ZERO;
- float bry = ZERO;
-
- for ( uint32_t i = 0; i < verts.Size(); ++i )
- {
- if ( verts[ i ].mPosition.x < tlx )
- {
- tlx = verts[ i ].mPosition.x;
- }
- if ( verts[ i ].mPosition.y < tly )
- {
- tly = verts[ i ].mPosition.y;
- }
- if ( verts[ i ].mPosition.x > brx )
- {
- brx = verts[ i ].mPosition.x;
- }
- if ( verts[ i ].mPosition.y > bry )
- {
- bry = verts[ i ].mPosition.y;
- }
- }
-
- float width = brx - tlx;
- float height = bry - tly;
- float divWidth = TWO / width;
- float divHeight = TWO / height;
-
- // Create a buffer to render to
- meshRecord.mBuffer = FrameBufferImage::New( width, height );
-
- // We will render a quad into this buffer
- unsigned int indices[ 6 ] = { 1, 0, 2, 2, 3, 1 };
- PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, 4u );
- PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, sizeof(indices)/sizeof(indices[0]) );
-
- AtlasManager::Vertex2D vertices[ 4 ] = {
- { Vector2( tlx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ZERO, ZERO ) },
- { Vector2( brx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ONE, ZERO ) },
- { Vector2( tlx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ZERO, ONE ) },
- { Vector2( brx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ONE, ONE ) } };
-
- quadVertices.SetData( vertices );
- quadIndices.SetData( indices );
-
- Geometry quadGeometry = Geometry::New();
- quadGeometry.AddVertexBuffer( quadVertices );
- quadGeometry.SetIndexBuffer( quadIndices );
-
- Material material = Material::New( mGlyphManager.GetEffectBufferShader() );
- material.AddTexture(meshRecord.mBuffer, "sTexture");
-
- Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-
- // Set depth index to -1.0 to make sure shadow is rendered first in 3D layers
- renderer.SetDepthIndex( -1.0f );
- Actor actor = Actor::New();
- actor.AddRenderer( renderer );
- actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
- actor.SetSize( actorSize );
-
- // Create a sub actor to render the source with normalized vertex positions
- Vector< AtlasManager::Vertex2D > normVertexList;
- for ( uint32_t i = 0; i < verts.Size(); ++i )
- {
- AtlasManager::Vertex2D vertex = verts[ i ];
- vertex.mPosition.x = ( ( vertex.mPosition.x - tlx ) * divWidth ) - ONE;
- vertex.mPosition.y = ( ( vertex.mPosition.y - tly ) * divHeight ) - ONE;
- normVertexList.PushBack( vertex );
- }
-
- PropertyBuffer normVertices = PropertyBuffer::New( mQuadVertexFormat, normVertexList.Size() );
- PropertyBuffer normIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
- normVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &normVertexList[ 0 ] ) );
- normIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) );
-
- Geometry normGeometry = Geometry::New();
- normGeometry.AddVertexBuffer( normVertices );
- normGeometry.SetIndexBuffer( normIndices );
-
- Material normMaterial = Material::New( mGlyphManager.GetGlyphShadowShader() );
- Image normImage = mGlyphManager.GetImage( meshRecord.mAtlasId );
- normMaterial.AddTexture( normImage, "sTexture" );
- Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial );
- Actor subActor = Actor::New();
- subActor.AddRenderer( normRenderer );
- subActor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
- subActor.SetSize( actorSize );
- subActor.SetColor( shadowColor );
-
- // Create a render task to render the effect
- RenderTask shadowTask = Stage::GetCurrent().GetRenderTaskList().CreateTask();
- shadowTask.SetTargetFrameBuffer( meshRecord.mBuffer );
- shadowTask.SetSourceActor( subActor );
- shadowTask.SetClearEnabled( true );
- shadowTask.SetClearColor( Vector4::ZERO );
- shadowTask.SetExclusive( true );
- shadowTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
- shadowTask.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
- mShadowTasks.push_back( shadowTask );
- actor.Add( subActor );
-
- return actor;
- }
-
- void RemoveShadowRenderTask( RenderTask renderTask )
- {
- if( renderTask )
- {
- renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
-
- // Guard to prevent accessing Stage after dali-core destruction
- if( Stage::IsInstalled() )
- {
- Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
- }
- renderTask.Reset();
- }
- }
-
- void RenderComplete( RenderTask& renderTask )
- {
- // Get the actor used for render to buffer and remove it from the parent
- Actor renderActor = renderTask.GetSourceActor();
- if ( renderActor )
- {
- Actor parent = renderActor.GetParent();
- if ( parent )
- {
- parent.Remove( renderActor );
- }
- }
-
- RemoveShadowRenderTask( renderTask );
- }
-
- void RemoveAllShadowRenderTasks()
- {
- for ( std::vector< RenderTask >::iterator shadowIterator = mShadowTasks.begin();
- shadowIterator != mShadowTasks.end(); ++shadowIterator )
- {
- RemoveShadowRenderTask( *shadowIterator );
- }
- }
-
Actor mActor; ///< The actor parent which renders the text
AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching
- std::vector< RenderTask > mShadowTasks; ///< Used to render shadows
TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
std::vector< MaxBlockSize > mBlockSizes; ///> Maximum size needed to contain a glyph in a block within a new atlas
- std::vector< uint32_t > mFace; ///> Face indices for a quad
- Vector< TextCacheEntry > mTextCache;
- Property::Map mQuadVertexFormat;
- Property::Map mQuadIndexFormat;
- int mDepth;
+ Vector< TextCacheEntry > mTextCache; ///> Caches data from previous render
+ Property::Map mQuadVertexFormat; ///> Describes the vertex format for text
+ Property::Map mQuadIndexFormat; ///> Describes the index format for text
+ int mDepth; ///> DepthIndex passed by control when connect to stage
};
Text::RendererPtr AtlasRenderer::New()
AtlasRenderer::~AtlasRenderer()
{
- mImpl->RemoveAllShadowRenderTasks();
-
mImpl->RemoveText();
delete mImpl;
}