Merge "This patch is for refining dali application to support tizen c# application...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / image-loader / image-atlas-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "image-atlas-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <string.h>
23 #include <dali/public-api/signals/callback.h>
24 #include <dali/public-api/images/resource-image.h>
25 #include <dali/devel-api/adaptor-framework/bitmap-loader.h>
26 #include <dali/integration-api/debug.h>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace Internal
35 {
36
37 ImageAtlas::ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelFormat )
38 : mAtlas( Texture::New( Dali::TextureType::TEXTURE_2D, pixelFormat, width, height ) ),
39   mPacker( width, height ),
40   mAsyncLoader( Toolkit::AsyncImageLoader::New() ),
41   mBrokenImageUrl(""),
42   mBrokenImageSize(),
43   mWidth( static_cast<float>(width) ),
44   mHeight( static_cast<float>( height ) ),
45   mPixelFormat( pixelFormat )
46 {
47   mAsyncLoader.ImageLoadedSignal().Connect( this, &ImageAtlas::UploadToAtlas );
48 }
49
50 ImageAtlas::~ImageAtlas()
51 {
52   mIdRectContainer.Clear();
53 }
54
55 IntrusivePtr<ImageAtlas> ImageAtlas::New( SizeType width, SizeType height, Pixel::Format pixelFormat )
56 {
57   IntrusivePtr<ImageAtlas> internal = new ImageAtlas( width, height, pixelFormat );
58
59   return internal;
60 }
61
62 Texture ImageAtlas::GetAtlas()
63 {
64   return mAtlas;
65 }
66
67 float ImageAtlas::GetOccupancyRate() const
68 {
69   return 1.f - static_cast<float>( mPacker.GetAvailableArea() ) / ( mWidth*mHeight );
70 }
71
72 void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl )
73 {
74   mBrokenImageSize = ResourceImage::GetImageSize( brokenImageUrl );
75   if(mBrokenImageSize.GetWidth() > 0 && mBrokenImageSize.GetHeight() > 0 ) // check the url is valid
76   {
77     mBrokenImageUrl = brokenImageUrl;
78   }
79 }
80
81 bool ImageAtlas::Upload( Vector4& textureRect,
82                          const std::string& url,
83                          ImageDimensions size,
84                          FittingMode::Type fittingMode,
85                          bool orientationCorrection )
86 {
87   ImageDimensions dimensions = size;
88   ImageDimensions zero;
89   if( size == zero ) // image size not provided
90   {
91     dimensions = ResourceImage::GetImageSize( url );
92     if( dimensions == zero ) // Fail to read the image & broken image file exists
93     {
94       if( !mBrokenImageUrl.empty() )
95       {
96         return Upload( textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true );
97       }
98       else
99       {
100         textureRect = Vector4::ZERO;
101         return true;
102       }
103     }
104   }
105
106   unsigned int packPositionX = 0;
107   unsigned int packPositionY = 0;
108   if( mPacker.Pack( dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY ) )
109   {
110     unsigned short loadId = mAsyncLoader.Load( url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection );
111     mIdRectContainer.PushBack( new IdRectPair( loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight() ) );
112
113     // apply the half pixel correction
114     textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
115     textureRect.y = ( static_cast<float>( packPositionY ) +0.5f ) / mHeight; // right
116     textureRect.z = ( static_cast<float>( packPositionX + dimensions.GetX() )-0.5f ) / mWidth; // right
117     textureRect.w = ( static_cast<float>( packPositionY + dimensions.GetY() )-0.5f ) / mHeight;// bottom
118
119     return true;
120   }
121
122   return false;
123 }
124
125 bool ImageAtlas::Upload( Vector4& textureRect, PixelData pixelData )
126 {
127   unsigned int packPositionX = 0;
128   unsigned int packPositionY = 0;
129   if( mPacker.Pack( pixelData.GetWidth(), pixelData.GetHeight(), packPositionX, packPositionY ) )
130   {
131     mAtlas.Upload( pixelData, 0u, 0u, packPositionX, packPositionY, pixelData.GetWidth(), pixelData.GetHeight() );
132
133     // apply the half pixel correction
134     textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
135     textureRect.y = ( static_cast<float>( packPositionY ) +0.5f ) / mHeight; // right
136     textureRect.z = ( static_cast<float>( packPositionX + pixelData.GetWidth() )-0.5f ) / mWidth; // right
137     textureRect.w = ( static_cast<float>( packPositionY + pixelData.GetHeight() )-0.5f ) / mHeight;// bottom
138
139     return true;
140   }
141
142   return false;
143 }
144
145 void ImageAtlas::Remove( const Vector4& textureRect )
146 {
147   mPacker.DeleteBlock( static_cast<SizeType>(textureRect.x*mWidth),
148                        static_cast<SizeType>(textureRect.y*mHeight),
149                        static_cast<SizeType>((textureRect.z-textureRect.x)*mWidth+1.f),
150                        static_cast<SizeType>((textureRect.w-textureRect.y)*mHeight+1.f) );
151 }
152
153 void ImageAtlas::UploadToAtlas( unsigned int id, PixelData pixelData )
154 {
155   if(  mIdRectContainer[0]->loadTaskId == id)
156   {
157     if( !pixelData || ( pixelData.GetWidth() ==0 && pixelData.GetHeight() == 0 ))
158     {
159       if(!mBrokenImageUrl.empty()) // replace with the broken image
160       {
161         UploadBrokenImage( mIdRectContainer[0]->packRect );
162       }
163     }
164     else
165     {
166       if( pixelData.GetWidth() < mIdRectContainer[0]->packRect.width || pixelData.GetHeight() < mIdRectContainer[0]->packRect.height  )
167       {
168         DALI_LOG_ERROR( "Can not upscale the image from actual loaded size [ %d, %d ] to specified size [ %d, %d ]\n",
169                         pixelData.GetWidth(), pixelData.GetHeight(),
170                         mIdRectContainer[0]->packRect.width,  mIdRectContainer[0]->packRect.height );
171       }
172
173       mAtlas.Upload( pixelData, 0u, 0u,
174                     mIdRectContainer[0]->packRect.x, mIdRectContainer[0]->packRect.y,
175                     mIdRectContainer[0]->packRect.width, mIdRectContainer[0]->packRect.height );
176     }
177   }
178
179   mIdRectContainer.Erase( mIdRectContainer.Begin() );
180 }
181
182 void ImageAtlas::UploadBrokenImage( const Rect<unsigned int>& area )
183 {
184   BitmapLoader loader = BitmapLoader::New(mBrokenImageUrl, ImageDimensions( area.width, area.height ) );
185   loader.Load();
186   SizeType loadedWidth = loader.GetPixelData().GetWidth();
187   SizeType loadedHeight = loader.GetPixelData().GetHeight();
188
189   bool needBackgroundClear = false;
190   SizeType packX = area.x;
191   SizeType packY = area.y;
192   // locate the broken image in the middle.
193   if( area.width > loadedWidth)
194   {
195     packX += (area.width - loadedWidth)/2;
196     needBackgroundClear = true;
197   }
198   if( area.height > loadedHeight)
199   {
200     packY += (area.height - loadedHeight)/2;
201     needBackgroundClear = true;
202   }
203
204   if( needBackgroundClear )
205   {
206     SizeType size = area.width * area.height * Pixel::GetBytesPerPixel( mPixelFormat );
207     PixelBuffer* buffer = new PixelBuffer [size];
208     PixelData background = PixelData::New( buffer, size, area.width, area.height, mPixelFormat, PixelData::DELETE_ARRAY );
209     for( SizeType idx = 0; idx < size; idx++ )
210     {
211       buffer[idx] = 0x00;
212     }
213     mAtlas.Upload( background, 0u, 0u, area.x, area.y, area.width, area.height );
214   }
215
216   mAtlas.Upload( loader.GetPixelData(), 0u, 0u, packX, packY, loadedWidth, loadedHeight );
217 }
218
219 } // namespace Internal
220
221 } // namespace Toolkit
222
223 } // namespace Dali