Merge "Remove ImageAttributes from public API" 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     ResourceId srcId = bufferImage.GetResourceId();
71
72     if( destId && srcId )
73     {
74       mResourceClient.UploadBitmap( destId, srcId, xOffset, yOffset );
75       uploadSuccess = true;
76     }
77   }
78
79   return uploadSuccess;
80 }
81
82 bool Atlas::Upload( const std::string& url,
83                     SizeType xOffset,
84                     SizeType yOffset)
85 {
86   bool uploadSuccess( false );
87
88   Integration::BitmapPtr bitmap = LoadBitmap( url );
89
90   if( bitmap && Compatible(bitmap->GetPixelFormat(), xOffset + bitmap->GetImageWidth(), yOffset + bitmap->GetImageHeight()) )
91   {
92     AllocateAtlas();
93     ResourceId destId = GetResourceId();
94     if( destId )
95     {
96       mResourceClient.UploadBitmap( destId, bitmap, xOffset, yOffset  );
97       uploadSuccess = true;
98
99       if( mRecoverContext )
100       {
101         mTiles.PushBack( new Tile(xOffset, yOffset, url) );
102       }
103     }
104   }
105   return uploadSuccess;
106 }
107
108 void Atlas::RecoverFromContextLoss()
109 {
110   ResourceId destId = GetResourceId();
111   if( destId )
112   {
113     if( mClear )
114     {
115       ClearBackground( mClearColor );
116     }
117
118     if( mRecoverContext )
119     {
120       // Restore the atlas by re-uploading the url resources
121       Vector< Tile* >::ConstIterator end = mTiles.End();
122       for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
123       {
124         Integration::BitmapPtr bitmap = LoadBitmap( (*iter)->url );
125         mResourceClient.UploadBitmap( destId, bitmap, (*iter)->xOffset, (*iter)->yOffset  );
126       }
127     }
128   }
129 }
130
131 Atlas::~Atlas()
132 {
133   ReleaseAtlas();
134 }
135
136 Atlas::Atlas( SizeType width,
137               SizeType height,
138               Pixel::Format pixelFormat,
139               bool recoverContext )
140 : mResourceClient( ThreadLocalStorage::Get().GetResourceClient() ),
141   mImageFactory( ThreadLocalStorage::Get().GetImageFactory() ),
142   mClearColor( Vector4::ZERO ),
143   mPixelFormat( pixelFormat ),
144   mClear( false ),
145   mRecoverContext( recoverContext )
146 {
147   mWidth  = width;
148   mHeight = height;
149 }
150
151 void Atlas::Connect()
152 {
153   ++mConnectionCount;
154
155   if( mConnectionCount == 1 )
156   {
157     AllocateAtlas();
158   }
159 }
160
161 void Atlas::Disconnect()
162 {
163   if( mConnectionCount )
164   {
165     --mConnectionCount;
166
167     if ( Dali::Image::UNUSED == mReleasePolicy &&
168          mConnectionCount == 0 )
169     {
170       ReleaseAtlas();
171     }
172   }
173 }
174
175 bool Atlas::Compatible( Pixel::Format pixelFormat,
176                         SizeType x,
177                         SizeType y )
178 {
179   bool Compatible(false);
180
181   if( mPixelFormat != pixelFormat )
182   {
183     DALI_LOG_ERROR( "Pixel format %d does not match Atlas format %d\n", pixelFormat, mPixelFormat );
184   }
185   else
186   {
187     if( x <= mWidth  && y <= mHeight )
188     {
189       Compatible = true;
190     }
191     else
192     {
193       DALI_LOG_ERROR( "image does not fit within the atlas \n" );
194     }
195   }
196
197   return Compatible;
198 }
199
200 void Atlas::AllocateAtlas()
201 {
202   if( !mTicket )
203   {
204     mTicket = mResourceClient.AllocateTexture( mWidth, mHeight, mPixelFormat );
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     // converting color value from float 0.f~1.f to byte 0~255
228     unsigned char r =  static_cast<unsigned char>( 255.f * Clamp( color.r, 0.f, 1.f ) );
229     unsigned char g =  static_cast<unsigned char>( 255.f * Clamp( color.g, 0.f, 1.f ) );
230     unsigned char b =  static_cast<unsigned char>( 255.f * Clamp( color.b, 0.f, 1.f ) );
231     unsigned char a =  static_cast<unsigned char>( 255.f * Clamp( color.a, 0.f, 1.f ) );
232     if( mPixelFormat == Pixel::RGBA8888 )
233     {
234       // For little-endian byte order, the RGBA channels needs to be reversed for bit shifting.
235       uint32_t clearColor = ( (uint32_t) a<<24 | (uint32_t)b << 16 | (uint32_t)g << 8 | (uint32_t)r );
236       uint32_t* buf = (uint32_t *) pixbuf;
237       for( unsigned int i = 0; i < numPixels; ++i )
238       {
239         buf[i] = clearColor;
240       }
241     }
242     else if( mPixelFormat == Pixel::RGB888 )
243     {
244       for( unsigned int i = 0; i < numPixels; ++i )
245       {
246         pixbuf[i*bytesPerPixel] = r;
247         pixbuf[i*bytesPerPixel+1] = g;
248         pixbuf[i*bytesPerPixel+2] = b;
249       }
250     }
251     else if( mPixelFormat == Pixel::A8 )
252     {
253       memset( pixbuf, a, numPixels );
254     }
255
256     RectArea area;
257     imageData->Update(area);
258
259     mClearColor = color;
260     mClear = true;
261     mResourceClient.UploadBitmap( destId, imageData->GetResourceId(), 0, 0 );
262   }
263 }
264
265 void Atlas::ClearCache()
266 {
267   Vector< Tile* >::ConstIterator end = mTiles.End();
268   for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
269   {
270     delete *iter;
271   }
272   mTiles.Clear();
273 }
274
275 Integration::BitmapPtr Atlas::LoadBitmap( const std::string& url )
276 {
277   Integration::BitmapResourceType resourceType;
278   Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
279
280   Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, url);
281   Integration::BitmapPtr bitmap = static_cast<Integration::Bitmap*>( resource.Get());
282
283   return bitmap;
284 }
285
286 } // namespace Internal
287
288 } // namespace Dali