X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fimage-loader%2Fimage-atlas-impl.cpp;h=d1674990a1b13dae58ccc2633a3934e55210cc53;hp=67f257c206c72339e6d14554ed6b58874da3a586;hb=8b474798c4b5a53412ed526f6279d4d27b440fc9;hpb=bd75dc4cad4ce62cc9206abf19280b40825b9726 diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp index 67f257c..d167499 100644 --- a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp +++ b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp @@ -21,8 +21,7 @@ // EXTERNAL INCLUDES #include #include -#include -#include +#include #include namespace Dali @@ -33,6 +32,50 @@ namespace Toolkit namespace Internal { +typedef unsigned char PixelBuffer; + +Texture ImageAtlas::PackToAtlas( const std::vector& pixelData, Dali::Vector& textureRects ) +{ + // Record each block size + Dali::Vector blockSizes; + SizeType count = pixelData.size(); + for( SizeType index = 0; index < count; index++ ) + { + blockSizes.PushBack( ImageDimensions( pixelData[index].GetWidth(), pixelData[index].GetHeight() ) ); + } + + // Ask atlasPacker for packing position of each block + Dali::Vector packPositions; + ImageDimensions atlasSize = AtlasPacker::GroupPack( blockSizes, packPositions ); + + // Prepare for outout texture rect array + textureRects.Clear(); + textureRects.Resize( count ); + + // create the texture for uploading the multiple pixel data + Texture atlasTexture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, atlasSize.GetWidth(), atlasSize.GetHeight() ); + + float atlasWidth = static_cast( atlasTexture.GetWidth() ); + float atlasHeight = static_cast( atlasTexture.GetHeight() ); + int packPositionX, packPositionY; + // Upload the pixel data one by one to its packing position, and record the texture rects + for( SizeType index = 0; index < count; index++ ) + { + packPositionX = packPositions[index].GetX(); + packPositionY = packPositions[index].GetY(); + atlasTexture.Upload( pixelData[index], 0u, 0u, + packPositionX, packPositionY, + pixelData[index].GetWidth(), pixelData[index].GetHeight() ); + + // Apply the half pixel correction to avoid the color bleeding between neighbour blocks + textureRects[index].x = ( static_cast( packPositionX ) +0.5f ) / atlasWidth; // left + textureRects[index].y = ( static_cast( packPositionY ) +0.5f ) / atlasHeight; // right + textureRects[index].z = ( static_cast( packPositionX + pixelData[index].GetWidth() )-0.5f ) / atlasWidth; // right + textureRects[index].w = ( static_cast( packPositionY + pixelData[index].GetHeight() )-0.5f ) / atlasHeight;// bottom + } + + return atlasTexture; +} ImageAtlas::ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelFormat ) : mAtlas( Texture::New( Dali::TextureType::TEXTURE_2D, pixelFormat, width, height ) ), @@ -49,7 +92,19 @@ ImageAtlas::ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelForm ImageAtlas::~ImageAtlas() { - mIdRectContainer.Clear(); + const std::size_t count = mLoadingTaskInfoContainer.Count(); + for( std::size_t i=0; i < count; ++i ) + { + // Call unregister to every observer in the list. + // Note that, the Atlas can be registered to same observer multiple times, and the Unregister method only remove one item each time. + // In this way, the atlas is actually detached from a observer either every upload call invoked by this observer is completed or atlas is destroyed. + if( mLoadingTaskInfoContainer[i]->observer ) + { + mLoadingTaskInfoContainer[i]->observer->Unregister( *this ); + } + } + + mLoadingTaskInfoContainer.Clear(); } IntrusivePtr ImageAtlas::New( SizeType width, SizeType height, Pixel::Format pixelFormat ) @@ -71,7 +126,7 @@ float ImageAtlas::GetOccupancyRate() const void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl ) { - mBrokenImageSize = ResourceImage::GetImageSize( brokenImageUrl ); + mBrokenImageSize = Dali::GetClosestImageSize( brokenImageUrl ); if(mBrokenImageSize.GetWidth() > 0 && mBrokenImageSize.GetHeight() > 0 ) // check the url is valid { mBrokenImageUrl = brokenImageUrl; @@ -82,18 +137,19 @@ bool ImageAtlas::Upload( Vector4& textureRect, const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, - bool orientationCorrection ) + bool orientationCorrection, + AtlasUploadObserver* atlasUploadObserver ) { ImageDimensions dimensions = size; ImageDimensions zero; if( size == zero ) // image size not provided { - dimensions = ResourceImage::GetImageSize( url ); + dimensions = Dali::GetClosestImageSize( url ); if( dimensions == zero ) // Fail to read the image & broken image file exists { if( !mBrokenImageUrl.empty() ) { - return Upload( textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true ); + return Upload( textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true, atlasUploadObserver ); } else { @@ -107,15 +163,21 @@ bool ImageAtlas::Upload( Vector4& textureRect, unsigned int packPositionY = 0; if( mPacker.Pack( dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY ) ) { - unsigned short loadId = mAsyncLoader.Load( url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection ); - mIdRectContainer.PushBack( new IdRectPair( loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight() ) ); - + unsigned short loadId = mAsyncLoader.Load( url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection); + mLoadingTaskInfoContainer.PushBack( new LoadingTaskInfo( loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight(), atlasUploadObserver ) ); // apply the half pixel correction textureRect.x = ( static_cast( packPositionX ) +0.5f ) / mWidth; // left textureRect.y = ( static_cast( packPositionY ) +0.5f ) / mHeight; // right textureRect.z = ( static_cast( packPositionX + dimensions.GetX() )-0.5f ) / mWidth; // right textureRect.w = ( static_cast( packPositionY + dimensions.GetY() )-0.5f ) / mHeight;// bottom + if( atlasUploadObserver ) + { + // register to the observer, + // Not that a matching unregister call should be invoked in UploadToAtlas if the observer is still alive by then. + atlasUploadObserver->Register( *this ); + } + return true; } @@ -150,41 +212,58 @@ void ImageAtlas::Remove( const Vector4& textureRect ) static_cast((textureRect.w-textureRect.y)*mHeight+1.f) ); } -void ImageAtlas::UploadToAtlas( unsigned int id, PixelData pixelData ) +void ImageAtlas::ObserverDestroyed( AtlasUploadObserver* observer ) +{ + const std::size_t count = mLoadingTaskInfoContainer.Count(); + for( std::size_t i=0; i < count; ++i ) + { + if( mLoadingTaskInfoContainer[i]->observer == observer ) + { + // the observer is destructing, so its member function should not be called anymore + mLoadingTaskInfoContainer[i]->observer = NULL; + } + } +} + +void ImageAtlas::UploadToAtlas( uint32_t id, PixelData pixelData ) { - if( mIdRectContainer[0]->loadTaskId == id) + if( mLoadingTaskInfoContainer[0]->loadTaskId == id) { + Rect packRect( mLoadingTaskInfoContainer[0]->packRect ); if( !pixelData || ( pixelData.GetWidth() ==0 && pixelData.GetHeight() == 0 )) { if(!mBrokenImageUrl.empty()) // replace with the broken image { - UploadBrokenImage( mIdRectContainer[0]->packRect ); + UploadBrokenImage( packRect ); } } else { - if( pixelData.GetWidth() < mIdRectContainer[0]->packRect.width || pixelData.GetHeight() < mIdRectContainer[0]->packRect.height ) + if( pixelData.GetWidth() < packRect.width || pixelData.GetHeight() < packRect.height ) { DALI_LOG_ERROR( "Can not upscale the image from actual loaded size [ %d, %d ] to specified size [ %d, %d ]\n", - pixelData.GetWidth(), pixelData.GetHeight(), - mIdRectContainer[0]->packRect.width, mIdRectContainer[0]->packRect.height ); + pixelData.GetWidth(), pixelData.GetHeight(), + packRect.width, packRect.height ); } - mAtlas.Upload( pixelData, 0u, 0u, - mIdRectContainer[0]->packRect.x, mIdRectContainer[0]->packRect.y, - mIdRectContainer[0]->packRect.width, mIdRectContainer[0]->packRect.height ); + mAtlas.Upload( pixelData, 0u, 0u, packRect.x, packRect.y, packRect.width, packRect.height ); } - } - mIdRectContainer.Erase( mIdRectContainer.Begin() ); + if( mLoadingTaskInfoContainer[0]->observer ) + { + mLoadingTaskInfoContainer[0]->observer->UploadCompleted(); + mLoadingTaskInfoContainer[0]->observer->Unregister( *this ); + } + + mLoadingTaskInfoContainer.Erase( mLoadingTaskInfoContainer.Begin() ); + } } void ImageAtlas::UploadBrokenImage( const Rect& area ) { - BitmapLoader loader = BitmapLoader::New(mBrokenImageUrl, ImageDimensions( area.width, area.height ) ); - loader.Load(); - SizeType loadedWidth = loader.GetPixelData().GetWidth(); - SizeType loadedHeight = loader.GetPixelData().GetHeight(); + Devel::PixelBuffer brokenBuffer = LoadImageFromFile( mBrokenImageUrl, ImageDimensions( area.width, area.height ) ); + SizeType loadedWidth = brokenBuffer.GetWidth(); + SizeType loadedHeight = brokenBuffer.GetHeight(); bool needBackgroundClear = false; SizeType packX = area.x; @@ -204,16 +283,18 @@ void ImageAtlas::UploadBrokenImage( const Rect& area ) if( needBackgroundClear ) { SizeType size = area.width * area.height * Pixel::GetBytesPerPixel( mPixelFormat ); - PixelBuffer* buffer = new PixelBuffer [size]; - PixelData background = PixelData::New( buffer, size, area.width, area.height, mPixelFormat, PixelData::DELETE_ARRAY ); + Devel::PixelBuffer background = Devel::PixelBuffer::New( area.width, area.height, mPixelFormat ); + unsigned char* buffer = background.GetBuffer(); for( SizeType idx = 0; idx < size; idx++ ) { buffer[idx] = 0x00; } - mAtlas.Upload( background, 0u, 0u, area.x, area.y, area.width, area.height ); + PixelData pixelData = Devel::PixelBuffer::Convert( background ); + mAtlas.Upload( pixelData, 0u, 0u, area.x, area.y, area.width, area.height ); } - mAtlas.Upload( loader.GetPixelData(), 0u, 0u, packX, packY, loadedWidth, loadedHeight ); + PixelData brokenPixelData = Devel::PixelBuffer::Convert( brokenBuffer ); + mAtlas.Upload( brokenPixelData, 0u, 0u, packX, packY, loadedWidth, loadedHeight ); } } // namespace Internal