Merge branch 'devel/master (1.1.2 ~ 1.1.7)' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / images / atlas-impl.cpp
1 /*
2  * Copyright (c) 2015 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 <dali/internal/event/images/atlas-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for memset()
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/internal/event/common/thread-local-storage.h>
27 #include <dali/internal/event/images/image-factory.h>
28 #include <dali/internal/event/resources/resource-client.h>
29 #include <dali/integration-api/bitmap.h>
30 #include <dali/integration-api/platform-abstraction.h>
31
32
33 namespace Dali
34 {
35
36 namespace Internal
37 {
38
39 namespace
40 {
41 TypeRegistration mType( typeid( Dali::Atlas ), typeid( Dali::Image ), NULL );
42 }
43
44 Atlas* Atlas::New( SizeType width,
45                    SizeType height,
46                    Pixel::Format pixelFormat,
47                    bool recoverContext)
48 {
49   return new Atlas( width, height, pixelFormat, recoverContext );
50 }
51
52 void Atlas::Clear(const Vector4& color)
53 {
54   ClearCache();
55   ClearBackground( color );
56 }
57
58 bool Atlas::Upload( BufferImage& bufferImage,
59                     SizeType xOffset,
60                     SizeType yOffset )
61 {
62   bool uploadSuccess( false );
63
64   if( Compatible(bufferImage.GetPixelFormat(),
65                  xOffset + bufferImage.GetWidth(),
66                  yOffset + bufferImage.GetHeight() ) )
67   {
68     AllocateAtlas();
69     ResourceId destId = GetResourceId();
70
71     if( destId )
72     {
73       bufferImage.UploadBitmap( destId, xOffset, yOffset );
74       uploadSuccess = true;
75     }
76   }
77
78   return uploadSuccess;
79 }
80
81 bool Atlas::Upload( const std::string& url,
82                     SizeType xOffset,
83                     SizeType yOffset)
84 {
85   bool uploadSuccess( false );
86
87   Integration::BitmapPtr bitmap = LoadBitmap( url );
88
89   if( bitmap && Compatible(bitmap->GetPixelFormat(), xOffset + bitmap->GetImageWidth(), yOffset + bitmap->GetImageHeight()) )
90   {
91     AllocateAtlas();
92     ResourceId destId = GetResourceId();
93     if( destId )
94     {
95       mResourceClient.UploadBitmap( destId, bitmap, xOffset, yOffset  );
96       uploadSuccess = true;
97
98       if( mRecoverContext )
99       {
100         mTiles.PushBack( new Tile(xOffset, yOffset, url) );
101       }
102     }
103   }
104   return uploadSuccess;
105 }
106
107 void Atlas::RecoverFromContextLoss()
108 {
109   ResourceId destId = GetResourceId();
110   if( destId )
111   {
112     if( mClear )
113     {
114       ClearBackground( mClearColor );
115     }
116
117     if( mRecoverContext )
118     {
119       // Restore the atlas by re-uploading the url resources
120       Vector< Tile* >::ConstIterator end = mTiles.End();
121       for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
122       {
123         Integration::BitmapPtr bitmap = LoadBitmap( (*iter)->url );
124         mResourceClient.UploadBitmap( destId, bitmap, (*iter)->xOffset, (*iter)->yOffset  );
125       }
126     }
127   }
128 }
129
130 Atlas::~Atlas()
131 {
132   ReleaseAtlas();
133 }
134
135 Atlas::Atlas( SizeType width,
136               SizeType height,
137               Pixel::Format pixelFormat,
138               bool recoverContext )
139 : mResourceClient( ThreadLocalStorage::Get().GetResourceClient() ),
140   mImageFactory( ThreadLocalStorage::Get().GetImageFactory() ),
141   mClearColor( Vector4::ZERO ),
142   mPixelFormat( pixelFormat ),
143   mClear( false ),
144   mRecoverContext( recoverContext )
145 {
146   mWidth  = width;
147   mHeight = height;
148 }
149
150 void Atlas::Connect()
151 {
152   ++mConnectionCount;
153
154   if( mConnectionCount == 1 )
155   {
156     AllocateAtlas();
157   }
158 }
159
160 void Atlas::Disconnect()
161 {
162   if( mConnectionCount )
163   {
164     --mConnectionCount;
165
166     if ( Dali::Image::UNUSED == mReleasePolicy &&
167          mConnectionCount == 0 )
168     {
169       ReleaseAtlas();
170     }
171   }
172 }
173
174 bool Atlas::Compatible( Pixel::Format pixelFormat,
175                         SizeType x,
176                         SizeType y )
177 {
178   bool Compatible(false);
179
180   if( mPixelFormat != pixelFormat )
181   {
182     DALI_LOG_ERROR( "Pixel format %d does not match Atlas format %d\n", pixelFormat, mPixelFormat );
183   }
184   else
185   {
186     if( x <= mWidth  && y <= mHeight )
187     {
188       Compatible = true;
189     }
190     else
191     {
192       DALI_LOG_ERROR( "image does not fit within the atlas \n" );
193     }
194   }
195
196   return Compatible;
197 }
198
199 void Atlas::AllocateAtlas()
200 {
201   if( !mTicket )
202   {
203     mTicket = mResourceClient.AllocateTexture( mWidth, mHeight, mPixelFormat );
204     mTicket->AddObserver( *this );
205     mImageFactory.RegisterForContextRecovery( this );
206   }
207 }
208
209 void Atlas::ReleaseAtlas()
210 {
211   mTicket.Reset();
212   ClearCache();
213   mImageFactory.UnregisterFromContextRecovery( this );
214 }
215
216 void Atlas::ClearBackground(const Vector4& color )
217 {
218   AllocateAtlas();
219   ResourceId destId = GetResourceId();
220   if( destId )
221   {
222     const unsigned int numPixels = mWidth * mHeight;
223     unsigned int bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
224     BufferImagePtr imageData = BufferImage::New( mWidth, mHeight, mPixelFormat );
225     PixelBuffer* pixbuf = imageData->GetBuffer();
226
227     if( pixbuf )
228     {
229       // converting color value from float 0.f~1.f to byte 0~255
230       unsigned char r =  static_cast<unsigned char>( 255.f * Clamp( color.r, 0.f, 1.f ) );
231       unsigned char g =  static_cast<unsigned char>( 255.f * Clamp( color.g, 0.f, 1.f ) );
232       unsigned char b =  static_cast<unsigned char>( 255.f * Clamp( color.b, 0.f, 1.f ) );
233       unsigned char a =  static_cast<unsigned char>( 255.f * Clamp( color.a, 0.f, 1.f ) );
234       if( mPixelFormat == Pixel::RGBA8888 )
235       {
236         // For little-endian byte order, the RGBA channels needs to be reversed for bit shifting.
237         uint32_t clearColor = ( (uint32_t) a<<24 | (uint32_t)b << 16 | (uint32_t)g << 8 | (uint32_t)r );
238         uint32_t* buf = (uint32_t *) pixbuf;
239         for( unsigned int i = 0; i < numPixels; ++i )
240         {
241           buf[i] = clearColor;
242         }
243       }
244       else if( mPixelFormat == Pixel::RGB888 )
245       {
246         for( unsigned int i = 0; i < numPixels; ++i )
247         {
248           pixbuf[i*bytesPerPixel] = r;
249           pixbuf[i*bytesPerPixel+1] = g;
250           pixbuf[i*bytesPerPixel+2] = b;
251         }
252       }
253       else if( mPixelFormat == Pixel::A8 )
254       {
255         memset( pixbuf, a, numPixels );
256       }
257     }
258
259     RectArea area;
260     imageData->Update(area);
261
262     mClearColor = color;
263     mClear = true;
264     mResourceClient.UploadBitmap( destId, imageData->GetResourceId(), 0, 0 );
265   }
266 }
267
268 void Atlas::ClearCache()
269 {
270   Vector< Tile* >::ConstIterator end = mTiles.End();
271   for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
272   {
273     delete *iter;
274   }
275   mTiles.Clear();
276 }
277
278 Integration::BitmapPtr Atlas::LoadBitmap( const std::string& url )
279 {
280   Integration::BitmapResourceType resourceType;
281   Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
282
283   Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, url);
284   Integration::BitmapPtr bitmap = static_cast<Integration::Bitmap*>( resource.Get());
285
286   return bitmap;
287 }
288
289 } // namespace Internal
290
291 } // namespace Dali